@@ -23,7 +23,7 @@ discard block |
||
23 | 23 | * @param mixed $guid |
24 | 24 | */ |
25 | 25 | function makeGuid($guid) { |
26 | - 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)); |
|
26 | + 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)); |
|
27 | 27 | } |
28 | 28 | |
29 | 29 | /** |
@@ -34,37 +34,37 @@ discard block |
||
34 | 34 | *@return string The defined name for the MAPI error code |
35 | 35 | */ |
36 | 36 | function get_mapi_error_name($errcode = null) { |
37 | - if ($errcode === null) { |
|
38 | - $errcode = mapi_last_hresult(); |
|
39 | - } |
|
40 | - |
|
41 | - if ($errcode !== 0) { |
|
42 | - // Retrieve constants categories, MAPI error names are defined |
|
43 | - // in the 'user' category, since the WebApp code defines it in mapicode.php. |
|
44 | - foreach (get_defined_constants(true)['user'] as $key => $value) { |
|
45 | - /* |
|
37 | + if ($errcode === null) { |
|
38 | + $errcode = mapi_last_hresult(); |
|
39 | + } |
|
40 | + |
|
41 | + if ($errcode !== 0) { |
|
42 | + // Retrieve constants categories, MAPI error names are defined |
|
43 | + // in the 'user' category, since the WebApp code defines it in mapicode.php. |
|
44 | + foreach (get_defined_constants(true)['user'] as $key => $value) { |
|
45 | + /* |
|
46 | 46 | * If PHP encounters a number beyond the bounds of the integer type, |
47 | 47 | * it will be interpreted as a float instead, so when comparing these error codes |
48 | 48 | * we have to manually typecast value to integer, so float will be converted in integer, |
49 | 49 | * but still its out of bound for integer limit so it will be auto adjusted to minus value |
50 | 50 | */ |
51 | - if ($errcode == (int) $value) { |
|
52 | - // Check that we have an actual MAPI error or warning definition |
|
53 | - $prefix = substr($key, 0, 7); |
|
54 | - if ($prefix == "MAPI_E_" || $prefix == "MAPI_W_") { |
|
55 | - return $key; |
|
56 | - } |
|
57 | - } |
|
58 | - } |
|
59 | - } |
|
60 | - else { |
|
61 | - return "NOERROR"; |
|
62 | - } |
|
63 | - |
|
64 | - // error code not found, return hex value (this is a fix for 64-bit systems, we can't use the dechex() function for this) |
|
65 | - $result = unpack("H*", pack("N", $errcode)); |
|
66 | - |
|
67 | - return "0x" . $result[1]; |
|
51 | + if ($errcode == (int) $value) { |
|
52 | + // Check that we have an actual MAPI error or warning definition |
|
53 | + $prefix = substr($key, 0, 7); |
|
54 | + if ($prefix == "MAPI_E_" || $prefix == "MAPI_W_") { |
|
55 | + return $key; |
|
56 | + } |
|
57 | + } |
|
58 | + } |
|
59 | + } |
|
60 | + else { |
|
61 | + return "NOERROR"; |
|
62 | + } |
|
63 | + |
|
64 | + // error code not found, return hex value (this is a fix for 64-bit systems, we can't use the dechex() function for this) |
|
65 | + $result = unpack("H*", pack("N", $errcode)); |
|
66 | + |
|
67 | + return "0x" . $result[1]; |
|
68 | 68 | } |
69 | 69 | |
70 | 70 | /** |
@@ -78,66 +78,66 @@ discard block |
||
78 | 78 | * @param mixed $mapping |
79 | 79 | */ |
80 | 80 | function getPropIdsFromStrings($store, $mapping) { |
81 | - $props = []; |
|
82 | - |
|
83 | - $ids = ["name" => [], "id" => [], "guid" => [], "type" => []]; // this array stores all the information needed to retrieve a named property |
|
84 | - $num = 0; |
|
85 | - |
|
86 | - // caching |
|
87 | - $guids = []; |
|
88 | - |
|
89 | - foreach ($mapping as $name => $val) { |
|
90 | - if (is_string($val)) { |
|
91 | - $split = explode(":", $val); |
|
92 | - |
|
93 | - if (count($split) != 3) { // invalid string, ignore |
|
94 | - trigger_error(sprintf("Invalid property: %s \"%s\"", $name, $val), E_USER_NOTICE); |
|
95 | - |
|
96 | - continue; |
|
97 | - } |
|
98 | - |
|
99 | - if (substr($split[2], 0, 2) == "0x") { |
|
100 | - $id = hexdec(substr($split[2], 2)); |
|
101 | - } |
|
102 | - else { |
|
103 | - $id = $split[2]; |
|
104 | - } |
|
105 | - |
|
106 | - // have we used this guid before? |
|
107 | - if (!defined($split[1])) { |
|
108 | - if (!array_key_exists($split[1], $guids)) { |
|
109 | - $guids[$split[1]] = makeguid($split[1]); |
|
110 | - } |
|
111 | - $guid = $guids[$split[1]]; |
|
112 | - } |
|
113 | - else { |
|
114 | - $guid = constant($split[1]); |
|
115 | - } |
|
116 | - |
|
117 | - // temp store info about named prop, so we have to call mapi_getidsfromnames just one time |
|
118 | - $ids["name"][$num] = $name; |
|
119 | - $ids["id"][$num] = $id; |
|
120 | - $ids["guid"][$num] = $guid; |
|
121 | - $ids["type"][$num] = $split[0]; |
|
122 | - ++$num; |
|
123 | - } |
|
124 | - else { |
|
125 | - // not a named property |
|
126 | - $props[$name] = $val; |
|
127 | - } |
|
128 | - } |
|
129 | - |
|
130 | - if (empty($ids["id"])) { |
|
131 | - return $props; |
|
132 | - } |
|
133 | - |
|
134 | - // get the ids |
|
135 | - $named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]); |
|
136 | - foreach ($named as $num => $prop) { |
|
137 | - $props[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop)); |
|
138 | - } |
|
139 | - |
|
140 | - return $props; |
|
81 | + $props = []; |
|
82 | + |
|
83 | + $ids = ["name" => [], "id" => [], "guid" => [], "type" => []]; // this array stores all the information needed to retrieve a named property |
|
84 | + $num = 0; |
|
85 | + |
|
86 | + // caching |
|
87 | + $guids = []; |
|
88 | + |
|
89 | + foreach ($mapping as $name => $val) { |
|
90 | + if (is_string($val)) { |
|
91 | + $split = explode(":", $val); |
|
92 | + |
|
93 | + if (count($split) != 3) { // invalid string, ignore |
|
94 | + trigger_error(sprintf("Invalid property: %s \"%s\"", $name, $val), E_USER_NOTICE); |
|
95 | + |
|
96 | + continue; |
|
97 | + } |
|
98 | + |
|
99 | + if (substr($split[2], 0, 2) == "0x") { |
|
100 | + $id = hexdec(substr($split[2], 2)); |
|
101 | + } |
|
102 | + else { |
|
103 | + $id = $split[2]; |
|
104 | + } |
|
105 | + |
|
106 | + // have we used this guid before? |
|
107 | + if (!defined($split[1])) { |
|
108 | + if (!array_key_exists($split[1], $guids)) { |
|
109 | + $guids[$split[1]] = makeguid($split[1]); |
|
110 | + } |
|
111 | + $guid = $guids[$split[1]]; |
|
112 | + } |
|
113 | + else { |
|
114 | + $guid = constant($split[1]); |
|
115 | + } |
|
116 | + |
|
117 | + // temp store info about named prop, so we have to call mapi_getidsfromnames just one time |
|
118 | + $ids["name"][$num] = $name; |
|
119 | + $ids["id"][$num] = $id; |
|
120 | + $ids["guid"][$num] = $guid; |
|
121 | + $ids["type"][$num] = $split[0]; |
|
122 | + ++$num; |
|
123 | + } |
|
124 | + else { |
|
125 | + // not a named property |
|
126 | + $props[$name] = $val; |
|
127 | + } |
|
128 | + } |
|
129 | + |
|
130 | + if (empty($ids["id"])) { |
|
131 | + return $props; |
|
132 | + } |
|
133 | + |
|
134 | + // get the ids |
|
135 | + $named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]); |
|
136 | + foreach ($named as $num => $prop) { |
|
137 | + $props[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop)); |
|
138 | + } |
|
139 | + |
|
140 | + return $props; |
|
141 | 141 | } |
142 | 142 | |
143 | 143 | /** |
@@ -153,11 +153,11 @@ discard block |
||
153 | 153 | * @return mixed Gives back false when there is no error, if there is, gives the error |
154 | 154 | */ |
155 | 155 | function propIsError($property, $propArray) { |
156 | - if (array_key_exists(mapi_prop_tag(PT_ERROR, mapi_prop_id($property)), $propArray)) { |
|
157 | - return $propArray[mapi_prop_tag(PT_ERROR, mapi_prop_id($property))]; |
|
158 | - } |
|
156 | + if (array_key_exists(mapi_prop_tag(PT_ERROR, mapi_prop_id($property)), $propArray)) { |
|
157 | + return $propArray[mapi_prop_tag(PT_ERROR, mapi_prop_id($property))]; |
|
158 | + } |
|
159 | 159 | |
160 | - return false; |
|
160 | + return false; |
|
161 | 161 | } |
162 | 162 | |
163 | 163 | /* Macro Functions for PR_DISPLAY_TYPE_EX values */ |
@@ -167,7 +167,7 @@ discard block |
||
167 | 167 | * @param mixed $value |
168 | 168 | */ |
169 | 169 | function DTE_IS_REMOTE_VALID($value) { |
170 | - return (bool) ($value & DTE_FLAG_REMOTE_VALID); |
|
170 | + return (bool) ($value & DTE_FLAG_REMOTE_VALID); |
|
171 | 171 | } |
172 | 172 | |
173 | 173 | /** |
@@ -176,15 +176,15 @@ discard block |
||
176 | 176 | * @param mixed $value |
177 | 177 | */ |
178 | 178 | function DTE_IS_ACL_CAPABLE($value) { |
179 | - return (bool) ($value & DTE_FLAG_ACL_CAPABLE); |
|
179 | + return (bool) ($value & DTE_FLAG_ACL_CAPABLE); |
|
180 | 180 | } |
181 | 181 | |
182 | 182 | function DTE_REMOTE($value) { |
183 | - return ($value & DTE_MASK_REMOTE) >> 8; |
|
183 | + return ($value & DTE_MASK_REMOTE) >> 8; |
|
184 | 184 | } |
185 | 185 | |
186 | 186 | function DTE_LOCAL($value) { |
187 | - return $value & DTE_MASK_LOCAL; |
|
187 | + return $value & DTE_MASK_LOCAL; |
|
188 | 188 | } |
189 | 189 | |
190 | 190 | /** |
@@ -204,92 +204,92 @@ discard block |
||
204 | 204 | * expanded so that it seems that there are only many single appointments in the table. |
205 | 205 | */ |
206 | 206 | function getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested) { |
207 | - $result = []; |
|
208 | - $properties = getPropIdsFromStrings($store, [ |
|
209 | - "duedate" => "PT_SYSTIME:PSETID_Appointment:0x820e", |
|
210 | - "startdate" => "PT_SYSTIME:PSETID_Appointment:0x820d", |
|
211 | - "enddate_recurring" => "PT_SYSTIME:PSETID_Appointment:0x8236", |
|
212 | - "recurring" => "PT_BOOLEAN:PSETID_Appointment:0x8223", |
|
213 | - "recurring_data" => "PT_BINARY:PSETID_Appointment:0x8216", |
|
214 | - "timezone_data" => "PT_BINARY:PSETID_Appointment:0x8233", |
|
215 | - "label" => "PT_LONG:PSETID_Appointment:0x8214", |
|
216 | - ]); |
|
217 | - |
|
218 | - // Create a restriction that will discard rows of appointments that are definitely not in our |
|
219 | - // requested time frame |
|
220 | - |
|
221 | - $table = mapi_folder_getcontentstable($calendar); |
|
222 | - |
|
223 | - $restriction = |
|
224 | - // OR |
|
225 | - [ |
|
226 | - RES_OR, |
|
227 | - [ |
|
228 | - [ |
|
229 | - RES_AND, // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd |
|
230 | - [ |
|
231 | - [ |
|
232 | - RES_PROPERTY, |
|
233 | - [ |
|
234 | - RELOP => RELOP_GT, |
|
235 | - ULPROPTAG => $properties["duedate"], |
|
236 | - VALUE => $viewstart, |
|
237 | - ], |
|
238 | - ], |
|
239 | - [ |
|
240 | - RES_PROPERTY, |
|
241 | - [ |
|
242 | - RELOP => RELOP_LT, |
|
243 | - ULPROPTAG => $properties["startdate"], |
|
244 | - VALUE => $viewend, |
|
245 | - ], |
|
246 | - ], |
|
247 | - ], |
|
248 | - ], |
|
249 | - // OR |
|
250 | - [ |
|
251 | - RES_PROPERTY, |
|
252 | - [ |
|
253 | - RELOP => RELOP_EQ, |
|
254 | - ULPROPTAG => $properties["recurring"], |
|
255 | - VALUE => true, |
|
256 | - ], |
|
257 | - ], |
|
258 | - ], // EXISTS OR |
|
259 | - ]; // global OR |
|
260 | - |
|
261 | - // Get requested properties, plus whatever we need |
|
262 | - $proplist = [PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]]; |
|
263 | - $proplist = array_merge($proplist, $propsrequested); |
|
264 | - |
|
265 | - $rows = mapi_table_queryallrows($table, $proplist, $restriction); |
|
266 | - |
|
267 | - // $rows now contains all the items that MAY be in the window; a recurring item needs expansion before including in the output. |
|
268 | - |
|
269 | - foreach ($rows as $row) { |
|
270 | - $items = []; |
|
271 | - |
|
272 | - if (isset($row[$properties["recurring"]]) && $row[$properties["recurring"]]) { |
|
273 | - // Recurring item |
|
274 | - $rec = new Recurrence($store, $row); |
|
275 | - |
|
276 | - // GetItems guarantees that the item overlaps the interval <$viewstart, $viewend> |
|
277 | - $occurrences = $rec->getItems($viewstart, $viewend); |
|
278 | - foreach ($occurrences as $occurrence) { |
|
279 | - // The occurrence takes all properties from the main row, but overrides some properties (like start and end obviously) |
|
280 | - $item = $occurrence + $row; |
|
281 | - array_push($items, $item); |
|
282 | - } |
|
283 | - } |
|
284 | - else { |
|
285 | - // Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend> |
|
286 | - array_push($items, $row); |
|
287 | - } |
|
288 | - |
|
289 | - $result = array_merge($result, $items); |
|
290 | - } |
|
291 | - |
|
292 | - // All items are guaranteed to overlap the interval <$viewstart, $viewend>. Note that we may be returning a few extra |
|
293 | - // properties that the caller did not request (recurring, etc). This shouldn't be a problem though. |
|
294 | - return $result; |
|
207 | + $result = []; |
|
208 | + $properties = getPropIdsFromStrings($store, [ |
|
209 | + "duedate" => "PT_SYSTIME:PSETID_Appointment:0x820e", |
|
210 | + "startdate" => "PT_SYSTIME:PSETID_Appointment:0x820d", |
|
211 | + "enddate_recurring" => "PT_SYSTIME:PSETID_Appointment:0x8236", |
|
212 | + "recurring" => "PT_BOOLEAN:PSETID_Appointment:0x8223", |
|
213 | + "recurring_data" => "PT_BINARY:PSETID_Appointment:0x8216", |
|
214 | + "timezone_data" => "PT_BINARY:PSETID_Appointment:0x8233", |
|
215 | + "label" => "PT_LONG:PSETID_Appointment:0x8214", |
|
216 | + ]); |
|
217 | + |
|
218 | + // Create a restriction that will discard rows of appointments that are definitely not in our |
|
219 | + // requested time frame |
|
220 | + |
|
221 | + $table = mapi_folder_getcontentstable($calendar); |
|
222 | + |
|
223 | + $restriction = |
|
224 | + // OR |
|
225 | + [ |
|
226 | + RES_OR, |
|
227 | + [ |
|
228 | + [ |
|
229 | + RES_AND, // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd |
|
230 | + [ |
|
231 | + [ |
|
232 | + RES_PROPERTY, |
|
233 | + [ |
|
234 | + RELOP => RELOP_GT, |
|
235 | + ULPROPTAG => $properties["duedate"], |
|
236 | + VALUE => $viewstart, |
|
237 | + ], |
|
238 | + ], |
|
239 | + [ |
|
240 | + RES_PROPERTY, |
|
241 | + [ |
|
242 | + RELOP => RELOP_LT, |
|
243 | + ULPROPTAG => $properties["startdate"], |
|
244 | + VALUE => $viewend, |
|
245 | + ], |
|
246 | + ], |
|
247 | + ], |
|
248 | + ], |
|
249 | + // OR |
|
250 | + [ |
|
251 | + RES_PROPERTY, |
|
252 | + [ |
|
253 | + RELOP => RELOP_EQ, |
|
254 | + ULPROPTAG => $properties["recurring"], |
|
255 | + VALUE => true, |
|
256 | + ], |
|
257 | + ], |
|
258 | + ], // EXISTS OR |
|
259 | + ]; // global OR |
|
260 | + |
|
261 | + // Get requested properties, plus whatever we need |
|
262 | + $proplist = [PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]]; |
|
263 | + $proplist = array_merge($proplist, $propsrequested); |
|
264 | + |
|
265 | + $rows = mapi_table_queryallrows($table, $proplist, $restriction); |
|
266 | + |
|
267 | + // $rows now contains all the items that MAY be in the window; a recurring item needs expansion before including in the output. |
|
268 | + |
|
269 | + foreach ($rows as $row) { |
|
270 | + $items = []; |
|
271 | + |
|
272 | + if (isset($row[$properties["recurring"]]) && $row[$properties["recurring"]]) { |
|
273 | + // Recurring item |
|
274 | + $rec = new Recurrence($store, $row); |
|
275 | + |
|
276 | + // GetItems guarantees that the item overlaps the interval <$viewstart, $viewend> |
|
277 | + $occurrences = $rec->getItems($viewstart, $viewend); |
|
278 | + foreach ($occurrences as $occurrence) { |
|
279 | + // The occurrence takes all properties from the main row, but overrides some properties (like start and end obviously) |
|
280 | + $item = $occurrence + $row; |
|
281 | + array_push($items, $item); |
|
282 | + } |
|
283 | + } |
|
284 | + else { |
|
285 | + // Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend> |
|
286 | + array_push($items, $row); |
|
287 | + } |
|
288 | + |
|
289 | + $result = array_merge($result, $items); |
|
290 | + } |
|
291 | + |
|
292 | + // All items are guaranteed to overlap the interval <$viewstart, $viewend>. Note that we may be returning a few extra |
|
293 | + // properties that the caller did not request (recurring, etc). This shouldn't be a problem though. |
|
294 | + return $result; |
|
295 | 295 | } |
@@ -23,7 +23,7 @@ discard block |
||
23 | 23 | * @param mixed $guid |
24 | 24 | */ |
25 | 25 | function makeGuid($guid) { |
26 | - 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)); |
|
26 | + 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)); |
|
27 | 27 | } |
28 | 28 | |
29 | 29 | /** |
@@ -48,7 +48,7 @@ discard block |
||
48 | 48 | * we have to manually typecast value to integer, so float will be converted in integer, |
49 | 49 | * but still its out of bound for integer limit so it will be auto adjusted to minus value |
50 | 50 | */ |
51 | - if ($errcode == (int) $value) { |
|
51 | + if ($errcode == (int)$value) { |
|
52 | 52 | // Check that we have an actual MAPI error or warning definition |
53 | 53 | $prefix = substr($key, 0, 7); |
54 | 54 | if ($prefix == "MAPI_E_" || $prefix == "MAPI_W_") { |
@@ -64,7 +64,7 @@ discard block |
||
64 | 64 | // error code not found, return hex value (this is a fix for 64-bit systems, we can't use the dechex() function for this) |
65 | 65 | $result = unpack("H*", pack("N", $errcode)); |
66 | 66 | |
67 | - return "0x" . $result[1]; |
|
67 | + return "0x".$result[1]; |
|
68 | 68 | } |
69 | 69 | |
70 | 70 | /** |
@@ -167,7 +167,7 @@ discard block |
||
167 | 167 | * @param mixed $value |
168 | 168 | */ |
169 | 169 | function DTE_IS_REMOTE_VALID($value) { |
170 | - return (bool) ($value & DTE_FLAG_REMOTE_VALID); |
|
170 | + return (bool)($value & DTE_FLAG_REMOTE_VALID); |
|
171 | 171 | } |
172 | 172 | |
173 | 173 | /** |
@@ -176,7 +176,7 @@ discard block |
||
176 | 176 | * @param mixed $value |
177 | 177 | */ |
178 | 178 | function DTE_IS_ACL_CAPABLE($value) { |
179 | - return (bool) ($value & DTE_FLAG_ACL_CAPABLE); |
|
179 | + return (bool)($value & DTE_FLAG_ACL_CAPABLE); |
|
180 | 180 | } |
181 | 181 | |
182 | 182 | function DTE_REMOTE($value) { |
@@ -226,7 +226,7 @@ discard block |
||
226 | 226 | RES_OR, |
227 | 227 | [ |
228 | 228 | [ |
229 | - RES_AND, // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd |
|
229 | + RES_AND, // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd |
|
230 | 230 | [ |
231 | 231 | [ |
232 | 232 | RES_PROPERTY, |
@@ -256,7 +256,7 @@ discard block |
||
256 | 256 | ], |
257 | 257 | ], |
258 | 258 | ], // EXISTS OR |
259 | - ]; // global OR |
|
259 | + ]; // global OR |
|
260 | 260 | |
261 | 261 | // Get requested properties, plus whatever we need |
262 | 262 | $proplist = [PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]]; |
@@ -56,8 +56,7 @@ discard block |
||
56 | 56 | } |
57 | 57 | } |
58 | 58 | } |
59 | - } |
|
60 | - else { |
|
59 | + } else { |
|
61 | 60 | return "NOERROR"; |
62 | 61 | } |
63 | 62 | |
@@ -98,8 +97,7 @@ discard block |
||
98 | 97 | |
99 | 98 | if (substr($split[2], 0, 2) == "0x") { |
100 | 99 | $id = hexdec(substr($split[2], 2)); |
101 | - } |
|
102 | - else { |
|
100 | + } else { |
|
103 | 101 | $id = $split[2]; |
104 | 102 | } |
105 | 103 | |
@@ -109,8 +107,7 @@ discard block |
||
109 | 107 | $guids[$split[1]] = makeguid($split[1]); |
110 | 108 | } |
111 | 109 | $guid = $guids[$split[1]]; |
112 | - } |
|
113 | - else { |
|
110 | + } else { |
|
114 | 111 | $guid = constant($split[1]); |
115 | 112 | } |
116 | 113 | |
@@ -120,8 +117,7 @@ discard block |
||
120 | 117 | $ids["guid"][$num] = $guid; |
121 | 118 | $ids["type"][$num] = $split[0]; |
122 | 119 | ++$num; |
123 | - } |
|
124 | - else { |
|
120 | + } else { |
|
125 | 121 | // not a named property |
126 | 122 | $props[$name] = $val; |
127 | 123 | } |
@@ -280,8 +276,7 @@ discard block |
||
280 | 276 | $item = $occurrence + $row; |
281 | 277 | array_push($items, $item); |
282 | 278 | } |
283 | - } |
|
284 | - else { |
|
279 | + } else { |
|
285 | 280 | // Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend> |
286 | 281 | array_push($items, $row); |
287 | 282 | } |
@@ -632,7 +632,7 @@ |
||
632 | 632 | /* PersistElementType Values ElementIDs for persist data of PR_IPM_OL2007_ENTRYIDS / PR_ADDITIONAL_REN_ENTRYIDS_EX */ |
633 | 633 | define('ELEMENT_SENTINEL', 0x0000); // 0 bytes Indicates that the PersistElement structure is the last one contained in the DataElements field of the PersistData structure. |
634 | 634 | define('RSF_ELID_ENTRYID', 0x0001); // variable Indicates that the ElementData field contains the entry ID of the special folder |
635 | - // that is of the type indicated by the value of the PersistID field of the PersistData structure. |
|
635 | + // that is of the type indicated by the value of the PersistID field of the PersistData structure. |
|
636 | 636 | define('RSF_ELID_HEADER', 0x0002); // 4 bytes Indicates that the ElementData field contains a 4-byte header value equal to 0x00000000. |
637 | 637 | |
638 | 638 | define('STGM_DIRECT', 0x00000000); |
@@ -16,40 +16,40 @@ discard block |
||
16 | 16 | |
17 | 17 | /* Object type */ |
18 | 18 | |
19 | -define('MAPI_STORE', 0x00000001); /* Message Store */ |
|
20 | -define('MAPI_ADDRBOOK', 0x00000002); /* Address Book */ |
|
21 | -define('MAPI_FOLDER', 0x00000003); /* Folder */ |
|
22 | -define('MAPI_ABCONT', 0x00000004); /* Address Book Container */ |
|
23 | -define('MAPI_MESSAGE', 0x00000005); /* Message */ |
|
24 | -define('MAPI_MAILUSER', 0x00000006); /* Individual Recipient */ |
|
25 | -define('MAPI_ATTACH', 0x00000007); /* Attachment */ |
|
26 | -define('MAPI_DISTLIST', 0x00000008); /* Distribution List Recipient */ |
|
27 | -define('MAPI_PROFSECT', 0x00000009); /* Profile Section */ |
|
28 | -define('MAPI_STATUS', 0x0000000A); /* Status Object */ |
|
29 | -define('MAPI_SESSION', 0x0000000B); /* Session */ |
|
30 | -define('MAPI_FORMINFO', 0x0000000C); /* Form Information */ |
|
19 | +define('MAPI_STORE', 0x00000001); /* Message Store */ |
|
20 | +define('MAPI_ADDRBOOK', 0x00000002); /* Address Book */ |
|
21 | +define('MAPI_FOLDER', 0x00000003); /* Folder */ |
|
22 | +define('MAPI_ABCONT', 0x00000004); /* Address Book Container */ |
|
23 | +define('MAPI_MESSAGE', 0x00000005); /* Message */ |
|
24 | +define('MAPI_MAILUSER', 0x00000006); /* Individual Recipient */ |
|
25 | +define('MAPI_ATTACH', 0x00000007); /* Attachment */ |
|
26 | +define('MAPI_DISTLIST', 0x00000008); /* Distribution List Recipient */ |
|
27 | +define('MAPI_PROFSECT', 0x00000009); /* Profile Section */ |
|
28 | +define('MAPI_STATUS', 0x0000000A); /* Status Object */ |
|
29 | +define('MAPI_SESSION', 0x0000000B); /* Session */ |
|
30 | +define('MAPI_FORMINFO', 0x0000000C); /* Form Information */ |
|
31 | 31 | |
32 | 32 | define('MV_FLAG', 0x1000); |
33 | 33 | define('MV_INSTANCE', 0x2000); |
34 | -define('MVI_FLAG', MV_FLAG | MV_INSTANCE); |
|
35 | - |
|
36 | -define('PT_UNSPECIFIED', 0); /* (Reserved for interface use) type doesn't matter to caller */ |
|
37 | -define('PT_NULL', 1); /* NULL property value */ |
|
38 | -define('PT_I2', 2); /* Signed 16-bit value */ |
|
39 | -define('PT_LONG', 3); /* Signed 32-bit value */ |
|
40 | -define('PT_R4', 4); /* 4-byte floating point */ |
|
41 | -define('PT_DOUBLE', 5); /* Floating point double */ |
|
42 | -define('PT_CURRENCY', 6); /* Signed 64-bit int (decimal w/ 4 digits right of decimal pt) */ |
|
43 | -define('PT_APPTIME', 7); /* Application time */ |
|
44 | -define('PT_ERROR', 10); /* 32-bit error value */ |
|
45 | -define('PT_BOOLEAN', 11); /* 16-bit boolean (non-zero true) */ |
|
46 | -define('PT_OBJECT', 13); /* Embedded object in a property */ |
|
47 | -define('PT_I8', 20); /* 8-byte signed integer */ |
|
48 | -define('PT_STRING8', 30); /* Null terminated 8-bit character string */ |
|
49 | -define('PT_UNICODE', 31); /* Null terminated Unicode string */ |
|
50 | -define('PT_SYSTIME', 64); /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */ |
|
51 | -define('PT_CLSID', 72); /* OLE GUID */ |
|
52 | -define('PT_BINARY', 258); /* Uninterpreted (counted byte array) */ |
|
34 | +define('MVI_FLAG', MV_FLAG|MV_INSTANCE); |
|
35 | + |
|
36 | +define('PT_UNSPECIFIED', 0); /* (Reserved for interface use) type doesn't matter to caller */ |
|
37 | +define('PT_NULL', 1); /* NULL property value */ |
|
38 | +define('PT_I2', 2); /* Signed 16-bit value */ |
|
39 | +define('PT_LONG', 3); /* Signed 32-bit value */ |
|
40 | +define('PT_R4', 4); /* 4-byte floating point */ |
|
41 | +define('PT_DOUBLE', 5); /* Floating point double */ |
|
42 | +define('PT_CURRENCY', 6); /* Signed 64-bit int (decimal w/ 4 digits right of decimal pt) */ |
|
43 | +define('PT_APPTIME', 7); /* Application time */ |
|
44 | +define('PT_ERROR', 10); /* 32-bit error value */ |
|
45 | +define('PT_BOOLEAN', 11); /* 16-bit boolean (non-zero true) */ |
|
46 | +define('PT_OBJECT', 13); /* Embedded object in a property */ |
|
47 | +define('PT_I8', 20); /* 8-byte signed integer */ |
|
48 | +define('PT_STRING8', 30); /* Null terminated 8-bit character string */ |
|
49 | +define('PT_UNICODE', 31); /* Null terminated Unicode string */ |
|
50 | +define('PT_SYSTIME', 64); /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */ |
|
51 | +define('PT_CLSID', 72); /* OLE GUID */ |
|
52 | +define('PT_BINARY', 258); /* Uninterpreted (counted byte array) */ |
|
53 | 53 | /* Changes are likely to these numbers, and to their structures. */ |
54 | 54 | |
55 | 55 | /* Alternate property type names for ease of use */ |
@@ -61,18 +61,18 @@ discard block |
||
61 | 61 | |
62 | 62 | define('PT_TSTRING', PT_STRING8); |
63 | 63 | |
64 | -define('PT_MV_I2', (MV_FLAG | PT_I2)); |
|
65 | -define('PT_MV_LONG', (MV_FLAG | PT_LONG)); |
|
66 | -define('PT_MV_R4', (MV_FLAG | PT_R4)); |
|
67 | -define('PT_MV_DOUBLE', (MV_FLAG | PT_DOUBLE)); |
|
68 | -define('PT_MV_CURRENCY', (MV_FLAG | PT_CURRENCY)); |
|
69 | -define('PT_MV_APPTIME', (MV_FLAG | PT_APPTIME)); |
|
70 | -define('PT_MV_SYSTIME', (MV_FLAG | PT_SYSTIME)); |
|
71 | -define('PT_MV_STRING8', (MV_FLAG | PT_STRING8)); |
|
72 | -define('PT_MV_BINARY', (MV_FLAG | PT_BINARY)); |
|
73 | -define('PT_MV_UNICODE', (MV_FLAG | PT_UNICODE)); |
|
74 | -define('PT_MV_CLSID', (MV_FLAG | PT_CLSID)); |
|
75 | -define('PT_MV_I8', (MV_FLAG | PT_I8)); |
|
64 | +define('PT_MV_I2', (MV_FLAG|PT_I2)); |
|
65 | +define('PT_MV_LONG', (MV_FLAG|PT_LONG)); |
|
66 | +define('PT_MV_R4', (MV_FLAG|PT_R4)); |
|
67 | +define('PT_MV_DOUBLE', (MV_FLAG|PT_DOUBLE)); |
|
68 | +define('PT_MV_CURRENCY', (MV_FLAG|PT_CURRENCY)); |
|
69 | +define('PT_MV_APPTIME', (MV_FLAG|PT_APPTIME)); |
|
70 | +define('PT_MV_SYSTIME', (MV_FLAG|PT_SYSTIME)); |
|
71 | +define('PT_MV_STRING8', (MV_FLAG|PT_STRING8)); |
|
72 | +define('PT_MV_BINARY', (MV_FLAG|PT_BINARY)); |
|
73 | +define('PT_MV_UNICODE', (MV_FLAG|PT_UNICODE)); |
|
74 | +define('PT_MV_CLSID', (MV_FLAG|PT_CLSID)); |
|
75 | +define('PT_MV_I8', (MV_FLAG|PT_I8)); |
|
76 | 76 | |
77 | 77 | define('PT_MV_TSTRING', PT_MV_STRING8); |
78 | 78 | /* bit 0: set if descending, clear if ascending */ |
@@ -190,14 +190,14 @@ discard block |
||
190 | 190 | |
191 | 191 | /* Values for PR_RESOURCE_TYPE, _METHODS, _FLAGS */ |
192 | 192 | |
193 | -define('MAPI_STORE_PROVIDER', 33); /* Message Store */ |
|
194 | -define('MAPI_AB', 34); /* Address Book */ |
|
195 | -define('MAPI_AB_PROVIDER', 35); /* Address Book Provider */ |
|
196 | -define('MAPI_TRANSPORT_PROVIDER', 36); /* Transport Provider */ |
|
197 | -define('MAPI_SPOOLER', 37); /* Message Spooler */ |
|
198 | -define('MAPI_PROFILE_PROVIDER', 38); /* Profile Provider */ |
|
199 | -define('MAPI_SUBSYSTEM', 39); /* Overall Subsystem Status */ |
|
200 | -define('MAPI_HOOK_PROVIDER', 40); /* Spooler Hook */ |
|
193 | +define('MAPI_STORE_PROVIDER', 33); /* Message Store */ |
|
194 | +define('MAPI_AB', 34); /* Address Book */ |
|
195 | +define('MAPI_AB_PROVIDER', 35); /* Address Book Provider */ |
|
196 | +define('MAPI_TRANSPORT_PROVIDER', 36); /* Transport Provider */ |
|
197 | +define('MAPI_SPOOLER', 37); /* Message Spooler */ |
|
198 | +define('MAPI_PROFILE_PROVIDER', 38); /* Profile Provider */ |
|
199 | +define('MAPI_SUBSYSTEM', 39); /* Overall Subsystem Status */ |
|
200 | +define('MAPI_HOOK_PROVIDER', 40); /* Spooler Hook */ |
|
201 | 201 | define('STATUS_VALIDATE_STATE', 0x00000001); |
202 | 202 | define('STATUS_SETTINGS_DIALOG', 0x00000002); |
203 | 203 | define('STATUS_CHANGE_PASSWORD', 0x00000004); |
@@ -243,10 +243,10 @@ discard block |
||
243 | 243 | define('MODRECIP_MODIFY', 0x00000004); |
244 | 244 | define('MODRECIP_REMOVE', 0x00000008); |
245 | 245 | |
246 | -define('MAPI_ORIG', 0); /* Recipient is message originator */ |
|
247 | -define('MAPI_TO', 1); /* Recipient is a primary recipient */ |
|
248 | -define('MAPI_CC', 2); /* Recipient is a copy recipient */ |
|
249 | -define('MAPI_BCC', 3); /* Recipient is blind copy recipient */ |
|
246 | +define('MAPI_ORIG', 0); /* Recipient is message originator */ |
|
247 | +define('MAPI_TO', 1); /* Recipient is a primary recipient */ |
|
248 | +define('MAPI_CC', 2); /* Recipient is a copy recipient */ |
|
249 | +define('MAPI_BCC', 3); /* Recipient is blind copy recipient */ |
|
250 | 250 | |
251 | 251 | /* IAttach Interface ------------------------------------------------------- */ |
252 | 252 | |
@@ -438,23 +438,23 @@ discard block |
||
438 | 438 | define('BMR_NEZ', 0x00000001); |
439 | 439 | |
440 | 440 | /* array index values of restrictions -- same values are used in php-ext/main.cpp::PHPArraytoSRestriction() */ |
441 | -define('VALUE', 0); // propval |
|
442 | -define('RELOP', 1); // compare method |
|
443 | -define('FUZZYLEVEL', 2); // string search flags |
|
444 | -define('CB', 3); // size restriction |
|
445 | -define('ULTYPE', 4); // bit mask restriction type BMR_xxx |
|
446 | -define('ULMASK', 5); // bitmask |
|
447 | -define('ULPROPTAG', 6); // property |
|
448 | -define('ULPROPTAG1', 7); // RES_COMPAREPROPS 1st property |
|
449 | -define('ULPROPTAG2', 8); // RES_COMPAREPROPS 2nd property |
|
450 | -define('PROPS', 9); // RES_COMMENT properties |
|
451 | -define('RESTRICTION', 10); // RES_COMMENT and RES_SUBRESTRICTION restriction |
|
441 | +define('VALUE', 0); // propval |
|
442 | +define('RELOP', 1); // compare method |
|
443 | +define('FUZZYLEVEL', 2); // string search flags |
|
444 | +define('CB', 3); // size restriction |
|
445 | +define('ULTYPE', 4); // bit mask restriction type BMR_xxx |
|
446 | +define('ULMASK', 5); // bitmask |
|
447 | +define('ULPROPTAG', 6); // property |
|
448 | +define('ULPROPTAG1', 7); // RES_COMPAREPROPS 1st property |
|
449 | +define('ULPROPTAG2', 8); // RES_COMPAREPROPS 2nd property |
|
450 | +define('PROPS', 9); // RES_COMMENT properties |
|
451 | +define('RESTRICTION', 10); // RES_COMMENT and RES_SUBRESTRICTION restriction |
|
452 | 452 | |
453 | 453 | /* GUID's for PR_MDB_PROVIDER */ |
454 | -define("ZARAFA_SERVICE_GUID", makeGuid("{3C253DCA-D227-443C-94FE-425FAB958C19}")); // default store |
|
455 | -define("ZARAFA_STORE_PUBLIC_GUID", makeGuid("{70FAB278-F7AF-CD11-9BC8-00AA002FC45A}")); // public store |
|
456 | -define("ZARAFA_STORE_DELEGATE_GUID", makeGuid("{7C7C1085-BC6D-4E53-9DAB-8A53F8DEF808}")); // other store |
|
457 | -define('ZARAFA_STORE_ARCHIVER_GUID', makeGuid("{BC8953AD-2E3F-4172-9404-896FF459870F}")); // archive store |
|
454 | +define("ZARAFA_SERVICE_GUID", makeGuid("{3C253DCA-D227-443C-94FE-425FAB958C19}")); // default store |
|
455 | +define("ZARAFA_STORE_PUBLIC_GUID", makeGuid("{70FAB278-F7AF-CD11-9BC8-00AA002FC45A}")); // public store |
|
456 | +define("ZARAFA_STORE_DELEGATE_GUID", makeGuid("{7C7C1085-BC6D-4E53-9DAB-8A53F8DEF808}")); // other store |
|
457 | +define('ZARAFA_STORE_ARCHIVER_GUID', makeGuid("{BC8953AD-2E3F-4172-9404-896FF459870F}")); // archive store |
|
458 | 458 | |
459 | 459 | /* global profile section guid */ |
460 | 460 | define('pbGlobalProfileSectionGuid', makeGuid("{C8B0DB13-05AA-1A10-9BB0-00AA002FC45A}")); |
@@ -481,10 +481,10 @@ discard block |
||
481 | 481 | // define('ecrightsContact' ,0x00000200); |
482 | 482 | define('ecRightsFolderVisible', 0x00000400); |
483 | 483 | |
484 | -define('ecRightsAll', ecRightsReadAny | ecRightsCreate | ecRightsEditOwned | ecRightsDeleteOwned | ecRightsEditAny | ecRightsDeleteAny | ecRightsCreateSubfolder | ecRightsFolderAccess | ecRightsFolderVisible); |
|
485 | -define('ecRightsFullControl', ecRightsReadAny | ecRightsCreate | ecRightsEditOwned | ecRightsDeleteOwned | ecRightsEditAny | ecRightsDeleteAny | ecRightsCreateSubfolder | ecRightsFolderVisible); |
|
486 | -define('ecRightsDefault', ecRightsNone | ecRightsFolderVisible); |
|
487 | -define('ecRightsDefaultPublic', ecRightsReadAny | ecRightsFolderVisible); |
|
484 | +define('ecRightsAll', ecRightsReadAny|ecRightsCreate|ecRightsEditOwned|ecRightsDeleteOwned|ecRightsEditAny|ecRightsDeleteAny|ecRightsCreateSubfolder|ecRightsFolderAccess|ecRightsFolderVisible); |
|
485 | +define('ecRightsFullControl', ecRightsReadAny|ecRightsCreate|ecRightsEditOwned|ecRightsDeleteOwned|ecRightsEditAny|ecRightsDeleteAny|ecRightsCreateSubfolder|ecRightsFolderVisible); |
|
486 | +define('ecRightsDefault', ecRightsNone|ecRightsFolderVisible); |
|
487 | +define('ecRightsDefaultPublic', ecRightsReadAny|ecRightsFolderVisible); |
|
488 | 488 | define('ecRightsAdmin', 0x00001000); |
489 | 489 | define('ecRightsAllMask', 0x000015FB); |
490 | 490 | |
@@ -500,7 +500,7 @@ discard block |
||
500 | 500 | define('ROW_ADD', 0x0001); |
501 | 501 | define('ROW_MODIFY', 0x0002); |
502 | 502 | define('ROW_REMOVE', 0x0004); |
503 | -define('ROW_EMPTY', (ROW_ADD | ROW_REMOVE)); |
|
503 | +define('ROW_EMPTY', (ROW_ADD|ROW_REMOVE)); |
|
504 | 504 | |
505 | 505 | // new property types |
506 | 506 | define('PT_SRESTRICTION', 0x00FD); |
@@ -570,38 +570,38 @@ discard block |
||
570 | 570 | define('SYNC_NO_FOREIGN_KEYS', 0x100); |
571 | 571 | define('SYNC_LIMITED_IMESSAGE', 0x200); |
572 | 572 | define('SYNC_CATCHUP', 0x400); |
573 | -define('SYNC_NEW_MESSAGE', 0x800); // only applicable to ImportMessageChange() |
|
574 | -define('SYNC_MSG_SELECTIVE', 0x1000); // Used internally. Will reject if used by clients. |
|
573 | +define('SYNC_NEW_MESSAGE', 0x800); // only applicable to ImportMessageChange() |
|
574 | +define('SYNC_MSG_SELECTIVE', 0x1000); // Used internally. Will reject if used by clients. |
|
575 | 575 | define('SYNC_BEST_BODY', 0x2000); |
576 | 576 | define('SYNC_IGNORE_SPECIFIED_ON_ASSOCIATED', 0x4000); |
577 | -define('SYNC_PROGRESS_MODE', 0x8000); // AirMapi progress mode |
|
577 | +define('SYNC_PROGRESS_MODE', 0x8000); // AirMapi progress mode |
|
578 | 578 | define('SYNC_FXRECOVERMODE', 0x10000); |
579 | 579 | define('SYNC_DEFER_CONFIG', 0x20000); |
580 | -define('SYNC_FORCE_UNICODE', 0x40000); // Forces server to return Unicode properties |
|
581 | -define('SYNC_STATE_READONLY', 0x80000); // Server will not update the states in the DB, setting up exporter with this flag states are read only |
|
580 | +define('SYNC_FORCE_UNICODE', 0x40000); // Forces server to return Unicode properties |
|
581 | +define('SYNC_STATE_READONLY', 0x80000); // Server will not update the states in the DB, setting up exporter with this flag states are read only |
|
582 | 582 | |
583 | -define('EMS_AB_ADDRESS_LOOKUP', 0x00000001); // Flag for resolvename to resolve only exact matches |
|
583 | +define('EMS_AB_ADDRESS_LOOKUP', 0x00000001); // Flag for resolvename to resolve only exact matches |
|
584 | 584 | |
585 | -define('TBL_BATCH', 0x00000002); // Batch multiple table commands |
|
585 | +define('TBL_BATCH', 0x00000002); // Batch multiple table commands |
|
586 | 586 | |
587 | 587 | /* Flags for recipients in exceptions */ |
588 | -define('recipSendable', 0x00000001); // sendable attendee. |
|
589 | -define('recipOrganizer', 0x00000002); // meeting organizer |
|
590 | -define('recipExceptionalResponse', 0x00000010); // attendee gave a response for the exception |
|
591 | -define('recipExceptionalDeleted', 0x00000020); // recipientRow exists, but it is treated as if the corresponding recipient is deleted from meeting |
|
592 | -define('recipOriginal', 0x00000100); // recipient is an original Attendee |
|
588 | +define('recipSendable', 0x00000001); // sendable attendee. |
|
589 | +define('recipOrganizer', 0x00000002); // meeting organizer |
|
590 | +define('recipExceptionalResponse', 0x00000010); // attendee gave a response for the exception |
|
591 | +define('recipExceptionalDeleted', 0x00000020); // recipientRow exists, but it is treated as if the corresponding recipient is deleted from meeting |
|
592 | +define('recipOriginal', 0x00000100); // recipient is an original Attendee |
|
593 | 593 | define('recipReserved', 0x00000200); |
594 | 594 | |
595 | 595 | /* Flags which indicates type of Meeting Object */ |
596 | -define('mtgEmpty', 0x00000000); // Unspecified. |
|
597 | -define('mtgRequest', 0x00000001); // Initial meeting request. |
|
598 | -define('mtgFull', 0x00010000); // Full update. |
|
599 | -define('mtgInfo', 0x00020000); // Informational update. |
|
600 | -define('mtgOutOfDate', 0x00080000); // A newer Meeting Request object or Meeting Update object was received after this one. |
|
601 | -define('mtgDelegatorCopy', 0x00100000); // This is set on the delegator's copy when a delegate will handle meeting-related objects. |
|
602 | - |
|
603 | -define('MAPI_ONE_OFF_UNICODE', 0x8000); // the flag that defines whether the embedded strings are Unicode in one off entryids. |
|
604 | -define('MAPI_ONE_OFF_NO_RICH_INFO', 0x0001); // the flag that specifies whether the recipient gets TNEF or not. |
|
596 | +define('mtgEmpty', 0x00000000); // Unspecified. |
|
597 | +define('mtgRequest', 0x00000001); // Initial meeting request. |
|
598 | +define('mtgFull', 0x00010000); // Full update. |
|
599 | +define('mtgInfo', 0x00020000); // Informational update. |
|
600 | +define('mtgOutOfDate', 0x00080000); // A newer Meeting Request object or Meeting Update object was received after this one. |
|
601 | +define('mtgDelegatorCopy', 0x00100000); // This is set on the delegator's copy when a delegate will handle meeting-related objects. |
|
602 | + |
|
603 | +define('MAPI_ONE_OFF_UNICODE', 0x8000); // the flag that defines whether the embedded strings are Unicode in one off entryids. |
|
604 | +define('MAPI_ONE_OFF_NO_RICH_INFO', 0x0001); // the flag that specifies whether the recipient gets TNEF or not. |
|
605 | 605 | |
606 | 606 | /* Mask flags for mapi_msgstore_advise */ |
607 | 607 | define('fnevCriticalError', 0x00000001); |
@@ -4,7 +4,7 @@ discard block |
||
4 | 4 | * SPDX-FileCopyrightText: Copyright 2005-2016 Zarafa Deutschland GmbH |
5 | 5 | * SPDX-FileCopyrightText: Copyright 2020-2022 grommunio GmbH |
6 | 6 | */ |
7 | - /* |
|
7 | + /* |
|
8 | 8 | * In general |
9 | 9 | * |
10 | 10 | * This class never actually modifies a task item unless we receive a task request update. This means |
@@ -16,93 +16,93 @@ discard block |
||
16 | 16 | * task request is sent via sendTaskRequest. |
17 | 17 | */ |
18 | 18 | |
19 | - /* The TaskMode value is only used for the IPM.TaskRequest items. |
|
19 | + /* The TaskMode value is only used for the IPM.TaskRequest items. |
|
20 | 20 | * It must 0 (tdmtNothing) on IPM.Task items. |
21 | 21 | * |
22 | 22 | * It is used to indicate the type of change that is being |
23 | 23 | * carried in the IPM.TaskRequest item (although this information seems |
24 | 24 | * redundant due to that information already being available in PR_MESSAGE_CLASS). |
25 | 25 | */ |
26 | - define('tdmtNothing', 0); // Value in IPM.Task items |
|
27 | - define('tdmtTaskReq', 1); // Assigner -> Assignee |
|
28 | - define('tdmtTaskAcc', 2); // Assignee -> Assigner |
|
29 | - define('tdmtTaskDec', 3); // Assignee -> Assigner |
|
30 | - define('tdmtTaskUpd', 4); // Assignee -> Assigner |
|
31 | - define('tdmtTaskSELF', 5); // Assigner -> Assigner (?) |
|
32 | - |
|
33 | - /* The TaskHistory is used to show the last action on the task |
|
26 | + define('tdmtNothing', 0); // Value in IPM.Task items |
|
27 | + define('tdmtTaskReq', 1); // Assigner -> Assignee |
|
28 | + define('tdmtTaskAcc', 2); // Assignee -> Assigner |
|
29 | + define('tdmtTaskDec', 3); // Assignee -> Assigner |
|
30 | + define('tdmtTaskUpd', 4); // Assignee -> Assigner |
|
31 | + define('tdmtTaskSELF', 5); // Assigner -> Assigner (?) |
|
32 | + |
|
33 | + /* The TaskHistory is used to show the last action on the task |
|
34 | 34 | * on both the assigner and the assignee's side. |
35 | 35 | * |
36 | 36 | * It is used in combination with 'task_assigned_time' and 'tasklastdelegate' |
37 | 37 | * or 'tasklastuser' to show the information at the top of the task request in |
38 | 38 | * the format 'Accepted by <user> on 01-01-2010 11:00'. |
39 | 39 | */ |
40 | - define('thNone', 0); |
|
41 | - define('thAccepted', 1); // Set by assignee |
|
42 | - define('thDeclined', 2); // Set by assignee |
|
43 | - define('thUpdated', 3); // Set by assignee |
|
44 | - define('thDueDateChanged', 4); |
|
45 | - define('thAssigned', 5); // Set by assigner |
|
46 | - |
|
47 | - /* The TaskState value is used to differentiate the version of a task |
|
40 | + define('thNone', 0); |
|
41 | + define('thAccepted', 1); // Set by assignee |
|
42 | + define('thDeclined', 2); // Set by assignee |
|
43 | + define('thUpdated', 3); // Set by assignee |
|
44 | + define('thDueDateChanged', 4); |
|
45 | + define('thAssigned', 5); // Set by assigner |
|
46 | + |
|
47 | + /* The TaskState value is used to differentiate the version of a task |
|
48 | 48 | * in the assigner's folder and the version in the |
49 | 49 | * assignee's folder. The buttons shown depend on this and |
50 | 50 | * the 'taskaccepted' boolean (for the assignee) |
51 | 51 | */ |
52 | - define('tdsNOM', 0); // Got a response to a deleted task, and re-created the task for the assigner |
|
53 | - define('tdsOWNNEW', 1); // Not assigned |
|
54 | - define('tdsOWN', 2); // Assignee version |
|
55 | - define('tdsACC', 3); // Assigner version |
|
56 | - define('tdsDEC', 4); // Assigner version, but assignee declined |
|
57 | - |
|
58 | - /* The TaskAcceptanceState is used for the assigner to indicate state */ |
|
59 | - define('olTaskNotDelegated', 0); |
|
60 | - define('olTaskDelegationUnknown', 1); // After sending req |
|
61 | - define('olTaskDelegationAccepted', 2); // After receiving accept |
|
62 | - define('olTaskDelegationDeclined', 3); // After receiving decline |
|
63 | - |
|
64 | - /* The task ownership indicates the role of the current user relative to the task. */ |
|
65 | - define('olNewTask', 0); |
|
66 | - define('olDelegatedTask', 1); // Task has been assigned |
|
67 | - define('olOwnTask', 2); // Task owned |
|
68 | - |
|
69 | - /* taskmultrecips indicates whether the task request sent or received has multiple assignees or not. */ |
|
70 | - define('tmrNone', 0); |
|
71 | - define('tmrSent', 1); // Task has been sent to multiple assignee |
|
72 | - define('tmrReceived', 2); // Task Request received has multiple assignee |
|
73 | - |
|
74 | - // Task icon index. |
|
75 | - define('ICON_TASK_ASSIGNEE', 0x00000502); |
|
76 | - define('ICON_TASK_DECLINE', 0x00000506); |
|
77 | - define('ICON_TASK_ASSIGNER', 0x00000503); |
|
78 | - |
|
79 | - class TaskRequest { |
|
80 | - private $props; |
|
81 | - private $store; |
|
82 | - private $message; |
|
83 | - private $session; |
|
84 | - private $taskCommentsInfo; |
|
85 | - |
|
86 | - // All recipient properties |
|
87 | - public $recipProps = [ |
|
88 | - PR_ENTRYID, |
|
89 | - PR_DISPLAY_NAME, |
|
90 | - PR_EMAIL_ADDRESS, |
|
91 | - PR_RECIPIENT_ENTRYID, |
|
92 | - PR_RECIPIENT_TYPE, |
|
93 | - PR_SEND_INTERNET_ENCODING, |
|
94 | - PR_SEND_RICH_INFO, |
|
95 | - PR_RECIPIENT_DISPLAY_NAME, |
|
96 | - PR_ADDRTYPE, |
|
97 | - PR_DISPLAY_TYPE, |
|
98 | - PR_RECIPIENT_TRACKSTATUS, |
|
99 | - PR_RECIPIENT_TRACKSTATUS_TIME, |
|
100 | - PR_RECIPIENT_FLAGS, |
|
101 | - PR_ROWID, |
|
102 | - PR_SEARCH_KEY, |
|
103 | - ]; |
|
104 | - |
|
105 | - /* Constructor |
|
52 | + define('tdsNOM', 0); // Got a response to a deleted task, and re-created the task for the assigner |
|
53 | + define('tdsOWNNEW', 1); // Not assigned |
|
54 | + define('tdsOWN', 2); // Assignee version |
|
55 | + define('tdsACC', 3); // Assigner version |
|
56 | + define('tdsDEC', 4); // Assigner version, but assignee declined |
|
57 | + |
|
58 | + /* The TaskAcceptanceState is used for the assigner to indicate state */ |
|
59 | + define('olTaskNotDelegated', 0); |
|
60 | + define('olTaskDelegationUnknown', 1); // After sending req |
|
61 | + define('olTaskDelegationAccepted', 2); // After receiving accept |
|
62 | + define('olTaskDelegationDeclined', 3); // After receiving decline |
|
63 | + |
|
64 | + /* The task ownership indicates the role of the current user relative to the task. */ |
|
65 | + define('olNewTask', 0); |
|
66 | + define('olDelegatedTask', 1); // Task has been assigned |
|
67 | + define('olOwnTask', 2); // Task owned |
|
68 | + |
|
69 | + /* taskmultrecips indicates whether the task request sent or received has multiple assignees or not. */ |
|
70 | + define('tmrNone', 0); |
|
71 | + define('tmrSent', 1); // Task has been sent to multiple assignee |
|
72 | + define('tmrReceived', 2); // Task Request received has multiple assignee |
|
73 | + |
|
74 | + // Task icon index. |
|
75 | + define('ICON_TASK_ASSIGNEE', 0x00000502); |
|
76 | + define('ICON_TASK_DECLINE', 0x00000506); |
|
77 | + define('ICON_TASK_ASSIGNER', 0x00000503); |
|
78 | + |
|
79 | + class TaskRequest { |
|
80 | + private $props; |
|
81 | + private $store; |
|
82 | + private $message; |
|
83 | + private $session; |
|
84 | + private $taskCommentsInfo; |
|
85 | + |
|
86 | + // All recipient properties |
|
87 | + public $recipProps = [ |
|
88 | + PR_ENTRYID, |
|
89 | + PR_DISPLAY_NAME, |
|
90 | + PR_EMAIL_ADDRESS, |
|
91 | + PR_RECIPIENT_ENTRYID, |
|
92 | + PR_RECIPIENT_TYPE, |
|
93 | + PR_SEND_INTERNET_ENCODING, |
|
94 | + PR_SEND_RICH_INFO, |
|
95 | + PR_RECIPIENT_DISPLAY_NAME, |
|
96 | + PR_ADDRTYPE, |
|
97 | + PR_DISPLAY_TYPE, |
|
98 | + PR_RECIPIENT_TRACKSTATUS, |
|
99 | + PR_RECIPIENT_TRACKSTATUS_TIME, |
|
100 | + PR_RECIPIENT_FLAGS, |
|
101 | + PR_ROWID, |
|
102 | + PR_SEARCH_KEY, |
|
103 | + ]; |
|
104 | + |
|
105 | + /* Constructor |
|
106 | 106 | * |
107 | 107 | * Constructs a TaskRequest object for the specified message. This can be either the task request |
108 | 108 | * message itself (in the inbox) or the task in the tasks folder, depending on the action to be performed. |
@@ -114,582 +114,582 @@ discard block |
||
114 | 114 | * @param $message message MAPI Message to which the task request refers to (can be an email or a task) |
115 | 115 | * @param $session session MAPI Session which is used to open tasks folders for delegated task requests or responses |
116 | 116 | */ |
117 | - public function __construct($store, $message, $session) { |
|
118 | - $this->store = $store; |
|
119 | - $this->message = $message; |
|
120 | - $this->session = $session; |
|
121 | - $this->taskCommentsInfo = false; |
|
122 | - |
|
123 | - $properties["owner"] = "PT_STRING8:PSETID_Task:0x811f"; |
|
124 | - $properties["updatecount"] = "PT_LONG:PSETID_Task:0x8112"; |
|
125 | - $properties["taskstate"] = "PT_LONG:PSETID_Task:0x8113"; |
|
126 | - $properties["taskmultrecips"] = "PT_LONG:PSETID_Task:0x8120"; |
|
127 | - $properties["taskupdates"] = "PT_BOOLEAN:PSETID_Task:0x811b"; |
|
128 | - $properties["tasksoc"] = "PT_BOOLEAN:PSETID_Task:0x8119"; |
|
129 | - $properties["taskhistory"] = "PT_LONG:PSETID_Task:0x811a"; |
|
130 | - $properties["taskmode"] = "PT_LONG:PSETID_Common:0x8518"; |
|
131 | - $properties["task_goid"] = "PT_BINARY:PSETID_Common:0x8519"; |
|
132 | - $properties["complete"] = "PT_BOOLEAN:PSETID_Common:0x811c"; |
|
133 | - $properties["task_assigned_time"] = "PT_SYSTIME:PSETID_Task:0x8115"; |
|
134 | - $properties["taskfcreator"] = "PT_BOOLEAN:PSETID_Task:0x0x811e"; |
|
135 | - $properties["tasklastuser"] = "PT_STRING8:PSETID_Task:0x8122"; |
|
136 | - $properties["tasklastdelegate"] = "PT_STRING8:PSETID_Task:0x8125"; |
|
137 | - $properties["taskaccepted"] = "PT_BOOLEAN:PSETID_Task:0x8108"; |
|
138 | - $properties["task_acceptance_state"] = "PT_LONG:PSETID_Task:0x812a"; |
|
139 | - $properties["ownership"] = "PT_LONG:PSETID_Task:0x8129"; |
|
140 | - |
|
141 | - $properties["complete"] = "PT_BOOLEAN:PSETID_Task:0x811c"; |
|
142 | - $properties["datecompleted"] = "PT_SYSTIME:PSETID_Task:0x810f"; |
|
143 | - $properties["recurring"] = "PT_BOOLEAN:PSETID_Task:0x8126"; |
|
144 | - $properties["startdate"] = "PT_SYSTIME:PSETID_Task:0x8104"; |
|
145 | - $properties["duedate"] = "PT_SYSTIME:PSETID_Task:0x8105"; |
|
146 | - $properties["status"] = "PT_LONG:PSETID_Task:0x8101"; |
|
147 | - $properties["percent_complete"] = "PT_DOUBLE:PSETID_Task:0x8102"; |
|
148 | - $properties["totalwork"] = "PT_LONG:PSETID_Task:0x8111"; |
|
149 | - $properties["actualwork"] = "PT_LONG:PSETID_Task:0x8110"; |
|
150 | - $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords"; |
|
151 | - $properties["companies"] = "PT_MV_STRING8:PSETID_Common:0x8539"; |
|
152 | - $properties["mileage"] = "PT_STRING8:PSETID_Common:0x8534"; |
|
153 | - $properties["billinginformation"] = "PT_STRING8:PSETID_Common:0x8535"; |
|
154 | - |
|
155 | - $this->props = getPropIdsFromStrings($store, $properties); |
|
156 | - } |
|
157 | - |
|
158 | - // General functions |
|
159 | - |
|
160 | - /** |
|
161 | - * Returns TRUE if the message pointed to is an incoming task request and should |
|
162 | - * therefore be replied to with doAccept or doDecline(). |
|
163 | - * |
|
164 | - * @param string $messageClass message class to use for checking |
|
165 | - * |
|
166 | - * @return bool returns true if this is a task request else false |
|
167 | - */ |
|
168 | - public function isTaskRequest($messageClass = false) { |
|
169 | - if ($messageClass === false) { |
|
170 | - $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]); |
|
171 | - $messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false; |
|
172 | - } |
|
173 | - |
|
174 | - if ($messageClass !== false && $messageClass === "IPM.TaskRequest") { |
|
175 | - return true; |
|
176 | - } |
|
177 | - |
|
178 | - return false; |
|
179 | - } |
|
180 | - |
|
181 | - /** |
|
182 | - * Returns TRUE if the message pointed to is a returning task request response. |
|
183 | - * |
|
184 | - * @param string $messageClass message class to use for checking |
|
185 | - * |
|
186 | - * @return bool returns true if this is a task request else false |
|
187 | - */ |
|
188 | - public function isTaskRequestResponse($messageClass = false) { |
|
189 | - if ($messageClass === false) { |
|
190 | - $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]); |
|
191 | - $messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false; |
|
192 | - } |
|
193 | - |
|
194 | - if ($messageClass !== false && strpos($messageClass, "IPM.TaskRequest.") === 0) { |
|
195 | - return true; |
|
196 | - } |
|
197 | - |
|
198 | - return false; |
|
199 | - } |
|
200 | - |
|
201 | - /** |
|
202 | - * Returns TRUE if the message pointed to is an incoming task request/response. |
|
203 | - * |
|
204 | - * @param array $props The MAPI properties to check message is an incoming task request/response |
|
205 | - * |
|
206 | - * @return bool Returns true if this is an incoming task request/response. else false. |
|
207 | - */ |
|
208 | - public function isReceivedItem($props) { |
|
209 | - return isset($props[PR_MESSAGE_TO_ME]) ? $props[PR_MESSAGE_TO_ME] : false; |
|
210 | - } |
|
211 | - |
|
212 | - /** |
|
213 | - * Gets the task associated with an IPM.TaskRequest message. |
|
214 | - * |
|
215 | - * If the task does not exist yet, it is created, using the attachment object in the |
|
216 | - * task request item. |
|
217 | - * |
|
218 | - * @param bool $create false to find the associated task in user's task folder. true to |
|
219 | - * create task in user's task folder if task is not exist in task folder. |
|
220 | - * |
|
221 | - * @return false|MAPIMessage Return associated task of task request else false |
|
222 | - */ |
|
223 | - public function getAssociatedTask($create) { |
|
224 | - $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->props['task_goid']]); |
|
225 | - |
|
226 | - if ($props[PR_MESSAGE_CLASS] == "IPM.Task") { |
|
227 | - // Message itself is task, so return that |
|
228 | - return $this->message; |
|
229 | - } |
|
230 | - |
|
231 | - $taskFolder = $this->getDefaultTasksFolder(); |
|
232 | - $goid = $props[$this->props['task_goid']]; |
|
233 | - |
|
234 | - // Find the task by looking for the task_goid |
|
235 | - $restriction = [ |
|
236 | - RES_PROPERTY, |
|
237 | - [ |
|
238 | - RELOP => RELOP_EQ, |
|
239 | - ULPROPTAG => $this->props['task_goid'], |
|
240 | - VALUE => $goid, |
|
241 | - ], |
|
242 | - ]; |
|
243 | - |
|
244 | - $contents = mapi_folder_getcontentstable($taskFolder); |
|
245 | - |
|
246 | - $rows = mapi_table_queryallrows($contents, [PR_ENTRYID], $restriction); |
|
247 | - |
|
248 | - if (empty($rows)) { |
|
249 | - // None found, create one if possible |
|
250 | - if (!$create) { |
|
251 | - return false; |
|
252 | - } |
|
253 | - |
|
254 | - $task = mapi_folder_createmessage($taskFolder); |
|
255 | - |
|
256 | - $sub = $this->getEmbeddedTask($this->message); |
|
257 | - mapi_copyto($sub, [], [$this->props['categories']], $task); |
|
258 | - |
|
259 | - $senderProps = [ |
|
260 | - PR_SENT_REPRESENTING_NAME, |
|
261 | - PR_SENT_REPRESENTING_EMAIL_ADDRESS, |
|
262 | - PR_SENT_REPRESENTING_ENTRYID, |
|
263 | - PR_SENT_REPRESENTING_ADDRTYPE, |
|
264 | - PR_SENT_REPRESENTING_SEARCH_KEY, |
|
265 | - PR_SENDER_NAME, |
|
266 | - PR_SENDER_EMAIL_ADDRESS, |
|
267 | - PR_SENDER_ENTRYID, |
|
268 | - PR_SENDER_ADDRTYPE, |
|
269 | - PR_SENDER_SEARCH_KEY, ]; |
|
270 | - |
|
271 | - // Copy sender information from the e-mail |
|
272 | - $props = mapi_getprops($this->message, $senderProps); |
|
273 | - mapi_setprops($task, $props); |
|
274 | - } |
|
275 | - else { |
|
276 | - // If there are multiple, just use the first |
|
277 | - $entryid = $rows[0][PR_ENTRYID]; |
|
278 | - |
|
279 | - $store = $this->getTaskFolderStore(); |
|
280 | - $task = mapi_msgstore_openentry($store, $entryid); |
|
281 | - } |
|
282 | - |
|
283 | - return $task; |
|
284 | - } |
|
285 | - |
|
286 | - /** |
|
287 | - * Function which checks that if we have received a task request/response |
|
288 | - * for an already updated task in task folder. |
|
289 | - * |
|
290 | - * @return bool true if task request is updated later |
|
291 | - */ |
|
292 | - public function isTaskRequestUpdated() { |
|
293 | - $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->props['task_goid'], $this->props['updatecount']]); |
|
294 | - $result = false; |
|
295 | - $associatedTask = $this->getAssociatedTask(false); |
|
296 | - if ($this->isTaskRequest($props[PR_MESSAGE_CLASS])) { |
|
297 | - if ($associatedTask) { |
|
298 | - return true; |
|
299 | - } |
|
300 | - $folder = $this->getDefaultTasksFolder(); |
|
301 | - $goid = $props[$this->props['task_goid']]; |
|
302 | - |
|
303 | - // Find the task by looking for the task_goid |
|
304 | - $restriction = [RES_PROPERTY, [ |
|
305 | - RELOP => RELOP_EQ, |
|
306 | - ULPROPTAG => $this->props['task_goid'], |
|
307 | - VALUE => $goid, ], |
|
308 | - ]; |
|
309 | - |
|
310 | - $table = mapi_folder_getcontentstable($folder, MAPI_DEFERRED_ERRORS | SHOW_SOFT_DELETES); |
|
311 | - $softDeletedItems = mapi_table_queryallrows($table, [PR_ENTRYID], $restriction); |
|
312 | - if (!empty($softDeletedItems)) { |
|
313 | - return true; |
|
314 | - } |
|
315 | - } |
|
316 | - |
|
317 | - if ($associatedTask !== false) { |
|
318 | - $taskItemProps = mapi_getprops($associatedTask, [$this->props['updatecount']]); |
|
319 | - /* |
|
117 | + public function __construct($store, $message, $session) { |
|
118 | + $this->store = $store; |
|
119 | + $this->message = $message; |
|
120 | + $this->session = $session; |
|
121 | + $this->taskCommentsInfo = false; |
|
122 | + |
|
123 | + $properties["owner"] = "PT_STRING8:PSETID_Task:0x811f"; |
|
124 | + $properties["updatecount"] = "PT_LONG:PSETID_Task:0x8112"; |
|
125 | + $properties["taskstate"] = "PT_LONG:PSETID_Task:0x8113"; |
|
126 | + $properties["taskmultrecips"] = "PT_LONG:PSETID_Task:0x8120"; |
|
127 | + $properties["taskupdates"] = "PT_BOOLEAN:PSETID_Task:0x811b"; |
|
128 | + $properties["tasksoc"] = "PT_BOOLEAN:PSETID_Task:0x8119"; |
|
129 | + $properties["taskhistory"] = "PT_LONG:PSETID_Task:0x811a"; |
|
130 | + $properties["taskmode"] = "PT_LONG:PSETID_Common:0x8518"; |
|
131 | + $properties["task_goid"] = "PT_BINARY:PSETID_Common:0x8519"; |
|
132 | + $properties["complete"] = "PT_BOOLEAN:PSETID_Common:0x811c"; |
|
133 | + $properties["task_assigned_time"] = "PT_SYSTIME:PSETID_Task:0x8115"; |
|
134 | + $properties["taskfcreator"] = "PT_BOOLEAN:PSETID_Task:0x0x811e"; |
|
135 | + $properties["tasklastuser"] = "PT_STRING8:PSETID_Task:0x8122"; |
|
136 | + $properties["tasklastdelegate"] = "PT_STRING8:PSETID_Task:0x8125"; |
|
137 | + $properties["taskaccepted"] = "PT_BOOLEAN:PSETID_Task:0x8108"; |
|
138 | + $properties["task_acceptance_state"] = "PT_LONG:PSETID_Task:0x812a"; |
|
139 | + $properties["ownership"] = "PT_LONG:PSETID_Task:0x8129"; |
|
140 | + |
|
141 | + $properties["complete"] = "PT_BOOLEAN:PSETID_Task:0x811c"; |
|
142 | + $properties["datecompleted"] = "PT_SYSTIME:PSETID_Task:0x810f"; |
|
143 | + $properties["recurring"] = "PT_BOOLEAN:PSETID_Task:0x8126"; |
|
144 | + $properties["startdate"] = "PT_SYSTIME:PSETID_Task:0x8104"; |
|
145 | + $properties["duedate"] = "PT_SYSTIME:PSETID_Task:0x8105"; |
|
146 | + $properties["status"] = "PT_LONG:PSETID_Task:0x8101"; |
|
147 | + $properties["percent_complete"] = "PT_DOUBLE:PSETID_Task:0x8102"; |
|
148 | + $properties["totalwork"] = "PT_LONG:PSETID_Task:0x8111"; |
|
149 | + $properties["actualwork"] = "PT_LONG:PSETID_Task:0x8110"; |
|
150 | + $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords"; |
|
151 | + $properties["companies"] = "PT_MV_STRING8:PSETID_Common:0x8539"; |
|
152 | + $properties["mileage"] = "PT_STRING8:PSETID_Common:0x8534"; |
|
153 | + $properties["billinginformation"] = "PT_STRING8:PSETID_Common:0x8535"; |
|
154 | + |
|
155 | + $this->props = getPropIdsFromStrings($store, $properties); |
|
156 | + } |
|
157 | + |
|
158 | + // General functions |
|
159 | + |
|
160 | + /** |
|
161 | + * Returns TRUE if the message pointed to is an incoming task request and should |
|
162 | + * therefore be replied to with doAccept or doDecline(). |
|
163 | + * |
|
164 | + * @param string $messageClass message class to use for checking |
|
165 | + * |
|
166 | + * @return bool returns true if this is a task request else false |
|
167 | + */ |
|
168 | + public function isTaskRequest($messageClass = false) { |
|
169 | + if ($messageClass === false) { |
|
170 | + $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]); |
|
171 | + $messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false; |
|
172 | + } |
|
173 | + |
|
174 | + if ($messageClass !== false && $messageClass === "IPM.TaskRequest") { |
|
175 | + return true; |
|
176 | + } |
|
177 | + |
|
178 | + return false; |
|
179 | + } |
|
180 | + |
|
181 | + /** |
|
182 | + * Returns TRUE if the message pointed to is a returning task request response. |
|
183 | + * |
|
184 | + * @param string $messageClass message class to use for checking |
|
185 | + * |
|
186 | + * @return bool returns true if this is a task request else false |
|
187 | + */ |
|
188 | + public function isTaskRequestResponse($messageClass = false) { |
|
189 | + if ($messageClass === false) { |
|
190 | + $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]); |
|
191 | + $messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false; |
|
192 | + } |
|
193 | + |
|
194 | + if ($messageClass !== false && strpos($messageClass, "IPM.TaskRequest.") === 0) { |
|
195 | + return true; |
|
196 | + } |
|
197 | + |
|
198 | + return false; |
|
199 | + } |
|
200 | + |
|
201 | + /** |
|
202 | + * Returns TRUE if the message pointed to is an incoming task request/response. |
|
203 | + * |
|
204 | + * @param array $props The MAPI properties to check message is an incoming task request/response |
|
205 | + * |
|
206 | + * @return bool Returns true if this is an incoming task request/response. else false. |
|
207 | + */ |
|
208 | + public function isReceivedItem($props) { |
|
209 | + return isset($props[PR_MESSAGE_TO_ME]) ? $props[PR_MESSAGE_TO_ME] : false; |
|
210 | + } |
|
211 | + |
|
212 | + /** |
|
213 | + * Gets the task associated with an IPM.TaskRequest message. |
|
214 | + * |
|
215 | + * If the task does not exist yet, it is created, using the attachment object in the |
|
216 | + * task request item. |
|
217 | + * |
|
218 | + * @param bool $create false to find the associated task in user's task folder. true to |
|
219 | + * create task in user's task folder if task is not exist in task folder. |
|
220 | + * |
|
221 | + * @return false|MAPIMessage Return associated task of task request else false |
|
222 | + */ |
|
223 | + public function getAssociatedTask($create) { |
|
224 | + $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->props['task_goid']]); |
|
225 | + |
|
226 | + if ($props[PR_MESSAGE_CLASS] == "IPM.Task") { |
|
227 | + // Message itself is task, so return that |
|
228 | + return $this->message; |
|
229 | + } |
|
230 | + |
|
231 | + $taskFolder = $this->getDefaultTasksFolder(); |
|
232 | + $goid = $props[$this->props['task_goid']]; |
|
233 | + |
|
234 | + // Find the task by looking for the task_goid |
|
235 | + $restriction = [ |
|
236 | + RES_PROPERTY, |
|
237 | + [ |
|
238 | + RELOP => RELOP_EQ, |
|
239 | + ULPROPTAG => $this->props['task_goid'], |
|
240 | + VALUE => $goid, |
|
241 | + ], |
|
242 | + ]; |
|
243 | + |
|
244 | + $contents = mapi_folder_getcontentstable($taskFolder); |
|
245 | + |
|
246 | + $rows = mapi_table_queryallrows($contents, [PR_ENTRYID], $restriction); |
|
247 | + |
|
248 | + if (empty($rows)) { |
|
249 | + // None found, create one if possible |
|
250 | + if (!$create) { |
|
251 | + return false; |
|
252 | + } |
|
253 | + |
|
254 | + $task = mapi_folder_createmessage($taskFolder); |
|
255 | + |
|
256 | + $sub = $this->getEmbeddedTask($this->message); |
|
257 | + mapi_copyto($sub, [], [$this->props['categories']], $task); |
|
258 | + |
|
259 | + $senderProps = [ |
|
260 | + PR_SENT_REPRESENTING_NAME, |
|
261 | + PR_SENT_REPRESENTING_EMAIL_ADDRESS, |
|
262 | + PR_SENT_REPRESENTING_ENTRYID, |
|
263 | + PR_SENT_REPRESENTING_ADDRTYPE, |
|
264 | + PR_SENT_REPRESENTING_SEARCH_KEY, |
|
265 | + PR_SENDER_NAME, |
|
266 | + PR_SENDER_EMAIL_ADDRESS, |
|
267 | + PR_SENDER_ENTRYID, |
|
268 | + PR_SENDER_ADDRTYPE, |
|
269 | + PR_SENDER_SEARCH_KEY, ]; |
|
270 | + |
|
271 | + // Copy sender information from the e-mail |
|
272 | + $props = mapi_getprops($this->message, $senderProps); |
|
273 | + mapi_setprops($task, $props); |
|
274 | + } |
|
275 | + else { |
|
276 | + // If there are multiple, just use the first |
|
277 | + $entryid = $rows[0][PR_ENTRYID]; |
|
278 | + |
|
279 | + $store = $this->getTaskFolderStore(); |
|
280 | + $task = mapi_msgstore_openentry($store, $entryid); |
|
281 | + } |
|
282 | + |
|
283 | + return $task; |
|
284 | + } |
|
285 | + |
|
286 | + /** |
|
287 | + * Function which checks that if we have received a task request/response |
|
288 | + * for an already updated task in task folder. |
|
289 | + * |
|
290 | + * @return bool true if task request is updated later |
|
291 | + */ |
|
292 | + public function isTaskRequestUpdated() { |
|
293 | + $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->props['task_goid'], $this->props['updatecount']]); |
|
294 | + $result = false; |
|
295 | + $associatedTask = $this->getAssociatedTask(false); |
|
296 | + if ($this->isTaskRequest($props[PR_MESSAGE_CLASS])) { |
|
297 | + if ($associatedTask) { |
|
298 | + return true; |
|
299 | + } |
|
300 | + $folder = $this->getDefaultTasksFolder(); |
|
301 | + $goid = $props[$this->props['task_goid']]; |
|
302 | + |
|
303 | + // Find the task by looking for the task_goid |
|
304 | + $restriction = [RES_PROPERTY, [ |
|
305 | + RELOP => RELOP_EQ, |
|
306 | + ULPROPTAG => $this->props['task_goid'], |
|
307 | + VALUE => $goid, ], |
|
308 | + ]; |
|
309 | + |
|
310 | + $table = mapi_folder_getcontentstable($folder, MAPI_DEFERRED_ERRORS | SHOW_SOFT_DELETES); |
|
311 | + $softDeletedItems = mapi_table_queryallrows($table, [PR_ENTRYID], $restriction); |
|
312 | + if (!empty($softDeletedItems)) { |
|
313 | + return true; |
|
314 | + } |
|
315 | + } |
|
316 | + |
|
317 | + if ($associatedTask !== false) { |
|
318 | + $taskItemProps = mapi_getprops($associatedTask, [$this->props['updatecount']]); |
|
319 | + /* |
|
320 | 320 | * if(message_counter < task_counter) task object is newer then task response (task is updated) |
321 | 321 | * if(message_counter >= task_counter) task is not updated, do normal processing |
322 | 322 | */ |
323 | - if (isset($taskItemProps[$this->props['updatecount']], $props[$this->props['updatecount']])) { |
|
324 | - if ($props[$this->props['updatecount']] < $taskItemProps[$this->props['updatecount']]) { |
|
325 | - $result = true; |
|
326 | - } |
|
327 | - } |
|
328 | - } |
|
329 | - |
|
330 | - return $result; |
|
331 | - } |
|
332 | - |
|
333 | - // Organizer functions (called by the organizer) |
|
334 | - |
|
335 | - /** |
|
336 | - * Processes a task request response, which can be any of the following: |
|
337 | - * - Task accept (task history is marked as accepted) |
|
338 | - * - Task decline (task history is marked as declined) |
|
339 | - * - Task update (updates completion %, etc). |
|
340 | - */ |
|
341 | - public function processTaskResponse() { |
|
342 | - $messageProps = mapi_getprops($this->message, [PR_PROCESSED, $this->props["taskupdates"], PR_MESSAGE_TO_ME]); |
|
343 | - if (isset($messageProps[PR_PROCESSED]) && $messageProps[PR_PROCESSED]) { |
|
344 | - return true; |
|
345 | - } |
|
346 | - mapi_setprops($this->message, [PR_PROCESSED => true]); |
|
347 | - mapi_savechanges($this->message); |
|
348 | - |
|
349 | - // Get the embedded task information. |
|
350 | - $sub = $this->getEmbeddedTask($this->message); |
|
351 | - |
|
352 | - // If task is updated in task folder then we don't need to process |
|
353 | - // old response |
|
354 | - if ($this->isTaskRequestUpdated()) { |
|
355 | - return true; |
|
356 | - } |
|
357 | - |
|
358 | - $isReceivedItem = $this->isReceivedItem($messageProps); |
|
359 | - |
|
360 | - $isCreateAssociatedTask = false; |
|
361 | - $isAllowUpdateAssociatedTask = $messageProps[$this->props["taskupdates"]]; |
|
362 | - $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]); |
|
363 | - // Set correct taskmode and taskhistory depending on response type |
|
364 | - switch ($props[PR_MESSAGE_CLASS]) { |
|
365 | - case 'IPM.TaskRequest.Accept': |
|
366 | - $taskHistory = thAccepted; |
|
367 | - $taskState = $isReceivedItem ? tdsACC : tdsOWN; |
|
368 | - $taskOwner = $isReceivedItem ? olDelegatedTask : olOwnTask; |
|
369 | - $taskAcceptanceState = $isReceivedItem ? olTaskDelegationAccepted : olTaskNotDelegated; |
|
370 | - |
|
371 | - break; |
|
372 | - |
|
373 | - case 'IPM.TaskRequest.Decline': |
|
374 | - $isCreateAssociatedTask = $isReceivedItem; |
|
375 | - $isAllowUpdateAssociatedTask = $isReceivedItem; |
|
376 | - $taskHistory = thDeclined; |
|
377 | - $taskState = $isReceivedItem ? tdsDEC : tdsACC; |
|
378 | - $taskOwner = $isReceivedItem ? olOwnTask : olDelegatedTask; |
|
379 | - $taskAcceptanceState = $isReceivedItem ? olTaskDelegationDeclined : olTaskDelegationUnknown; |
|
380 | - |
|
381 | - break; |
|
382 | - |
|
383 | - case 'IPM.TaskRequest.Update': |
|
384 | - case 'IPM.TaskRequest.Complete': |
|
385 | - $taskHistory = thUpdated; |
|
386 | - $taskState = $isReceivedItem ? tdsACC : tdsOWN; |
|
387 | - $taskAcceptanceState = olTaskNotDelegated; |
|
388 | - $taskOwner = $isReceivedItem ? olDelegatedTask : olOwnTask; |
|
389 | - |
|
390 | - break; |
|
391 | - } |
|
392 | - |
|
393 | - $props = [ |
|
394 | - $this->props['taskhistory'] => $taskHistory, |
|
395 | - $this->props['taskstate'] => $taskState, |
|
396 | - $this->props['task_acceptance_state'] => $taskAcceptanceState, |
|
397 | - $this->props['ownership'] => $taskOwner, |
|
398 | - ]; |
|
399 | - |
|
400 | - // Get the task for this response |
|
401 | - $task = $this->getAssociatedTask($isCreateAssociatedTask); |
|
402 | - if ($task && $isAllowUpdateAssociatedTask) { |
|
403 | - // To avoid duplication of attachments in associated task. we simple remove the |
|
404 | - // all attachments from associated task. |
|
405 | - $taskAttachTable = mapi_message_getattachmenttable($task); |
|
406 | - $taskAttachments = mapi_table_queryallrows($taskAttachTable, [PR_ATTACH_NUM]); |
|
407 | - foreach ($taskAttachments as $taskAttach) { |
|
408 | - mapi_message_deleteattach($task, $taskAttach[PR_ATTACH_NUM]); |
|
409 | - } |
|
410 | - |
|
411 | - $ignoreProps = [ |
|
412 | - $this->props['taskstate'], |
|
413 | - $this->props['taskhistory'], |
|
414 | - $this->props['taskmode'], |
|
415 | - $this->props['taskfcreator'], |
|
416 | - ]; |
|
417 | - // Ignore PR_ICON_INDEX when task request response |
|
418 | - // is not received item. |
|
419 | - if ($isReceivedItem === false) { |
|
420 | - $ignoreProps[] = PR_ICON_INDEX; |
|
421 | - } |
|
422 | - |
|
423 | - // We copy all properties except taskstate, taskhistory, taskmode and taskfcreator properties |
|
424 | - // from $sub message to $task even also we copy all attachments from $sub to $task message. |
|
425 | - mapi_copyto($sub, [], $ignoreProps, $task); |
|
426 | - $senderProps = mapi_getprops($this->message, [ |
|
427 | - PR_SENDER_NAME, |
|
428 | - PR_SENDER_EMAIL_ADDRESS, |
|
429 | - PR_SENDER_ENTRYID, |
|
430 | - PR_SENDER_ADDRTYPE, |
|
431 | - PR_SENDER_SEARCH_KEY, |
|
432 | - PR_MESSAGE_DELIVERY_TIME, |
|
433 | - PR_SENT_REPRESENTING_NAME, |
|
434 | - PR_SENT_REPRESENTING_EMAIL_ADDRESS, |
|
435 | - PR_SENT_REPRESENTING_ADDRTYPE, |
|
436 | - PR_SENT_REPRESENTING_ENTRYID, |
|
437 | - PR_SENT_REPRESENTING_SEARCH_KEY, ]); |
|
438 | - |
|
439 | - mapi_setprops($task, $senderProps); |
|
440 | - |
|
441 | - // Update taskstate and task history (last action done by the assignee) |
|
442 | - mapi_setprops($task, $props); |
|
443 | - |
|
444 | - mapi_savechanges($task); |
|
445 | - } |
|
446 | - |
|
447 | - mapi_setprops($this->message, $props); |
|
448 | - mapi_savechanges($this->message); |
|
449 | - |
|
450 | - if ($isReceivedItem) { |
|
451 | - $this->updateSentTaskRequest(); |
|
452 | - } |
|
453 | - |
|
454 | - return true; |
|
455 | - } |
|
456 | - |
|
457 | - /** |
|
458 | - * Update the sent task request in sent items folder. |
|
459 | - * |
|
460 | - * @return bool |
|
461 | - */ |
|
462 | - public function updateSentTaskRequest() { |
|
463 | - $props = mapi_getprops($this->message, [ |
|
464 | - $this->props['taskhistory'], |
|
465 | - $this->props["taskstate"], |
|
466 | - $this->props["ownership"], |
|
467 | - $this->props['task_goid'], |
|
468 | - $this->props['task_acceptance_state'], |
|
469 | - $this->props["tasklastuser"], |
|
470 | - $this->props["tasklastdelegate"], ]); |
|
471 | - |
|
472 | - $store = $this->getDefaultStore(); |
|
473 | - $storeProps = mapi_getprops($store, [PR_IPM_SENTMAIL_ENTRYID]); |
|
474 | - |
|
475 | - $sentFolder = mapi_msgstore_openentry($store, $storeProps[PR_IPM_SENTMAIL_ENTRYID]); |
|
476 | - if (!$sentFolder) { |
|
477 | - return false; |
|
478 | - } |
|
479 | - |
|
480 | - // Find the task by looking for the task_goid |
|
481 | - $restriction = [ |
|
482 | - RES_PROPERTY, [ |
|
483 | - RELOP => RELOP_EQ, |
|
484 | - ULPROPTAG => $this->props['task_goid'], |
|
485 | - VALUE => $props[$this->props['task_goid']], |
|
486 | - ], |
|
487 | - ]; |
|
488 | - |
|
489 | - $contentsTable = mapi_folder_getcontentstable($sentFolder); |
|
490 | - |
|
491 | - $rows = mapi_table_queryallrows($contentsTable, [PR_ENTRYID], $restriction); |
|
492 | - |
|
493 | - if (!empty($rows)) { |
|
494 | - foreach ($rows as $row) { |
|
495 | - $sentTaskRequest = mapi_msgstore_openentry($store, $row[PR_ENTRYID]); |
|
496 | - mapi_setprops($sentTaskRequest, $props); |
|
497 | - mapi_setprops($sentTaskRequest, [PR_PROCESSED => true]); |
|
498 | - mapi_savechanges($sentTaskRequest); |
|
499 | - } |
|
500 | - } |
|
501 | - |
|
502 | - return true; |
|
503 | - } |
|
504 | - |
|
505 | - /* Create a new message in the current user's outbox and submit it |
|
323 | + if (isset($taskItemProps[$this->props['updatecount']], $props[$this->props['updatecount']])) { |
|
324 | + if ($props[$this->props['updatecount']] < $taskItemProps[$this->props['updatecount']]) { |
|
325 | + $result = true; |
|
326 | + } |
|
327 | + } |
|
328 | + } |
|
329 | + |
|
330 | + return $result; |
|
331 | + } |
|
332 | + |
|
333 | + // Organizer functions (called by the organizer) |
|
334 | + |
|
335 | + /** |
|
336 | + * Processes a task request response, which can be any of the following: |
|
337 | + * - Task accept (task history is marked as accepted) |
|
338 | + * - Task decline (task history is marked as declined) |
|
339 | + * - Task update (updates completion %, etc). |
|
340 | + */ |
|
341 | + public function processTaskResponse() { |
|
342 | + $messageProps = mapi_getprops($this->message, [PR_PROCESSED, $this->props["taskupdates"], PR_MESSAGE_TO_ME]); |
|
343 | + if (isset($messageProps[PR_PROCESSED]) && $messageProps[PR_PROCESSED]) { |
|
344 | + return true; |
|
345 | + } |
|
346 | + mapi_setprops($this->message, [PR_PROCESSED => true]); |
|
347 | + mapi_savechanges($this->message); |
|
348 | + |
|
349 | + // Get the embedded task information. |
|
350 | + $sub = $this->getEmbeddedTask($this->message); |
|
351 | + |
|
352 | + // If task is updated in task folder then we don't need to process |
|
353 | + // old response |
|
354 | + if ($this->isTaskRequestUpdated()) { |
|
355 | + return true; |
|
356 | + } |
|
357 | + |
|
358 | + $isReceivedItem = $this->isReceivedItem($messageProps); |
|
359 | + |
|
360 | + $isCreateAssociatedTask = false; |
|
361 | + $isAllowUpdateAssociatedTask = $messageProps[$this->props["taskupdates"]]; |
|
362 | + $props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]); |
|
363 | + // Set correct taskmode and taskhistory depending on response type |
|
364 | + switch ($props[PR_MESSAGE_CLASS]) { |
|
365 | + case 'IPM.TaskRequest.Accept': |
|
366 | + $taskHistory = thAccepted; |
|
367 | + $taskState = $isReceivedItem ? tdsACC : tdsOWN; |
|
368 | + $taskOwner = $isReceivedItem ? olDelegatedTask : olOwnTask; |
|
369 | + $taskAcceptanceState = $isReceivedItem ? olTaskDelegationAccepted : olTaskNotDelegated; |
|
370 | + |
|
371 | + break; |
|
372 | + |
|
373 | + case 'IPM.TaskRequest.Decline': |
|
374 | + $isCreateAssociatedTask = $isReceivedItem; |
|
375 | + $isAllowUpdateAssociatedTask = $isReceivedItem; |
|
376 | + $taskHistory = thDeclined; |
|
377 | + $taskState = $isReceivedItem ? tdsDEC : tdsACC; |
|
378 | + $taskOwner = $isReceivedItem ? olOwnTask : olDelegatedTask; |
|
379 | + $taskAcceptanceState = $isReceivedItem ? olTaskDelegationDeclined : olTaskDelegationUnknown; |
|
380 | + |
|
381 | + break; |
|
382 | + |
|
383 | + case 'IPM.TaskRequest.Update': |
|
384 | + case 'IPM.TaskRequest.Complete': |
|
385 | + $taskHistory = thUpdated; |
|
386 | + $taskState = $isReceivedItem ? tdsACC : tdsOWN; |
|
387 | + $taskAcceptanceState = olTaskNotDelegated; |
|
388 | + $taskOwner = $isReceivedItem ? olDelegatedTask : olOwnTask; |
|
389 | + |
|
390 | + break; |
|
391 | + } |
|
392 | + |
|
393 | + $props = [ |
|
394 | + $this->props['taskhistory'] => $taskHistory, |
|
395 | + $this->props['taskstate'] => $taskState, |
|
396 | + $this->props['task_acceptance_state'] => $taskAcceptanceState, |
|
397 | + $this->props['ownership'] => $taskOwner, |
|
398 | + ]; |
|
399 | + |
|
400 | + // Get the task for this response |
|
401 | + $task = $this->getAssociatedTask($isCreateAssociatedTask); |
|
402 | + if ($task && $isAllowUpdateAssociatedTask) { |
|
403 | + // To avoid duplication of attachments in associated task. we simple remove the |
|
404 | + // all attachments from associated task. |
|
405 | + $taskAttachTable = mapi_message_getattachmenttable($task); |
|
406 | + $taskAttachments = mapi_table_queryallrows($taskAttachTable, [PR_ATTACH_NUM]); |
|
407 | + foreach ($taskAttachments as $taskAttach) { |
|
408 | + mapi_message_deleteattach($task, $taskAttach[PR_ATTACH_NUM]); |
|
409 | + } |
|
410 | + |
|
411 | + $ignoreProps = [ |
|
412 | + $this->props['taskstate'], |
|
413 | + $this->props['taskhistory'], |
|
414 | + $this->props['taskmode'], |
|
415 | + $this->props['taskfcreator'], |
|
416 | + ]; |
|
417 | + // Ignore PR_ICON_INDEX when task request response |
|
418 | + // is not received item. |
|
419 | + if ($isReceivedItem === false) { |
|
420 | + $ignoreProps[] = PR_ICON_INDEX; |
|
421 | + } |
|
422 | + |
|
423 | + // We copy all properties except taskstate, taskhistory, taskmode and taskfcreator properties |
|
424 | + // from $sub message to $task even also we copy all attachments from $sub to $task message. |
|
425 | + mapi_copyto($sub, [], $ignoreProps, $task); |
|
426 | + $senderProps = mapi_getprops($this->message, [ |
|
427 | + PR_SENDER_NAME, |
|
428 | + PR_SENDER_EMAIL_ADDRESS, |
|
429 | + PR_SENDER_ENTRYID, |
|
430 | + PR_SENDER_ADDRTYPE, |
|
431 | + PR_SENDER_SEARCH_KEY, |
|
432 | + PR_MESSAGE_DELIVERY_TIME, |
|
433 | + PR_SENT_REPRESENTING_NAME, |
|
434 | + PR_SENT_REPRESENTING_EMAIL_ADDRESS, |
|
435 | + PR_SENT_REPRESENTING_ADDRTYPE, |
|
436 | + PR_SENT_REPRESENTING_ENTRYID, |
|
437 | + PR_SENT_REPRESENTING_SEARCH_KEY, ]); |
|
438 | + |
|
439 | + mapi_setprops($task, $senderProps); |
|
440 | + |
|
441 | + // Update taskstate and task history (last action done by the assignee) |
|
442 | + mapi_setprops($task, $props); |
|
443 | + |
|
444 | + mapi_savechanges($task); |
|
445 | + } |
|
446 | + |
|
447 | + mapi_setprops($this->message, $props); |
|
448 | + mapi_savechanges($this->message); |
|
449 | + |
|
450 | + if ($isReceivedItem) { |
|
451 | + $this->updateSentTaskRequest(); |
|
452 | + } |
|
453 | + |
|
454 | + return true; |
|
455 | + } |
|
456 | + |
|
457 | + /** |
|
458 | + * Update the sent task request in sent items folder. |
|
459 | + * |
|
460 | + * @return bool |
|
461 | + */ |
|
462 | + public function updateSentTaskRequest() { |
|
463 | + $props = mapi_getprops($this->message, [ |
|
464 | + $this->props['taskhistory'], |
|
465 | + $this->props["taskstate"], |
|
466 | + $this->props["ownership"], |
|
467 | + $this->props['task_goid'], |
|
468 | + $this->props['task_acceptance_state'], |
|
469 | + $this->props["tasklastuser"], |
|
470 | + $this->props["tasklastdelegate"], ]); |
|
471 | + |
|
472 | + $store = $this->getDefaultStore(); |
|
473 | + $storeProps = mapi_getprops($store, [PR_IPM_SENTMAIL_ENTRYID]); |
|
474 | + |
|
475 | + $sentFolder = mapi_msgstore_openentry($store, $storeProps[PR_IPM_SENTMAIL_ENTRYID]); |
|
476 | + if (!$sentFolder) { |
|
477 | + return false; |
|
478 | + } |
|
479 | + |
|
480 | + // Find the task by looking for the task_goid |
|
481 | + $restriction = [ |
|
482 | + RES_PROPERTY, [ |
|
483 | + RELOP => RELOP_EQ, |
|
484 | + ULPROPTAG => $this->props['task_goid'], |
|
485 | + VALUE => $props[$this->props['task_goid']], |
|
486 | + ], |
|
487 | + ]; |
|
488 | + |
|
489 | + $contentsTable = mapi_folder_getcontentstable($sentFolder); |
|
490 | + |
|
491 | + $rows = mapi_table_queryallrows($contentsTable, [PR_ENTRYID], $restriction); |
|
492 | + |
|
493 | + if (!empty($rows)) { |
|
494 | + foreach ($rows as $row) { |
|
495 | + $sentTaskRequest = mapi_msgstore_openentry($store, $row[PR_ENTRYID]); |
|
496 | + mapi_setprops($sentTaskRequest, $props); |
|
497 | + mapi_setprops($sentTaskRequest, [PR_PROCESSED => true]); |
|
498 | + mapi_savechanges($sentTaskRequest); |
|
499 | + } |
|
500 | + } |
|
501 | + |
|
502 | + return true; |
|
503 | + } |
|
504 | + |
|
505 | + /* Create a new message in the current user's outbox and submit it |
|
506 | 506 | * |
507 | 507 | * Takes the task passed in the constructor as the task to be sent; recipient should |
508 | 508 | * be pre-existing. The task request will be sent to all recipients. |
509 | 509 | */ |
510 | - public function sendTaskRequest($prefix) { |
|
511 | - // Generate a TaskGlobalObjectId |
|
512 | - $taskid = $this->createTGOID(); |
|
513 | - $messageprops = mapi_getprops($this->message, [PR_SUBJECT]); |
|
514 | - |
|
515 | - // Set properties on Task Request |
|
516 | - mapi_setprops($this->message, [ |
|
517 | - $this->props['task_goid'] => $taskid, /* our new task_goid */ |
|
518 | - $this->props['taskstate'] => tdsACC, /* state for our outgoing request */ |
|
519 | - $this->props['taskmode'] => tdmtNothing, /* we're not sending a change */ |
|
520 | - $this->props['updatecount'] => 2, /* version 2 (no idea) */ |
|
521 | - $this->props['task_acceptance_state'] => olTaskDelegationUnknown, /* no reply yet */ |
|
522 | - $this->props['ownership'] => olDelegatedTask, /* Task has been assigned */ |
|
523 | - $this->props['taskhistory'] => thAssigned, /* Task has been assigned */ |
|
524 | - PR_CONVERSATION_TOPIC => $messageprops[PR_SUBJECT], |
|
525 | - PR_ICON_INDEX => ICON_TASK_ASSIGNER, /* Task request icon */ |
|
526 | - ]); |
|
527 | - $this->setLastUser(); |
|
528 | - $this->setOwnerForAssignor(); |
|
529 | - mapi_savechanges($this->message); |
|
530 | - |
|
531 | - // Create outgoing task request message |
|
532 | - $outgoing = $this->createOutgoingMessage(); |
|
533 | - |
|
534 | - // No need to copy PR_ICON_INDEX and PR_SENT_* information in to outgoing message. |
|
535 | - $ignoreProps = [PR_ICON_INDEX, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_SEARCH_KEY]; |
|
536 | - mapi_copyto($this->message, [], $ignoreProps, $outgoing); |
|
537 | - |
|
538 | - // Make it a task request, and put it in sent items after it is sent |
|
539 | - mapi_setprops($outgoing, [ |
|
540 | - PR_MESSAGE_CLASS => "IPM.TaskRequest", /* class is task request */ |
|
541 | - $this->props['taskstate'] => tdsOWN, /* for the recipient he is the task owner */ |
|
542 | - $this->props['taskmode'] => tdmtTaskReq, /* for the recipient it's a request */ |
|
543 | - $this->props['updatecount'] => 1, /* version 2 is in the attachment */ |
|
544 | - PR_SUBJECT_PREFIX => $prefix, |
|
545 | - PR_SUBJECT => $prefix . $messageprops[PR_SUBJECT], |
|
546 | - ]); |
|
547 | - |
|
548 | - $attach = mapi_message_createattach($outgoing); |
|
549 | - mapi_setprops($attach, [ |
|
550 | - PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG, |
|
551 | - PR_ATTACHMENT_HIDDEN => true, |
|
552 | - PR_DISPLAY_NAME => $messageprops[PR_SUBJECT], ]); |
|
553 | - |
|
554 | - $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_MODIFY | MAPI_CREATE); |
|
555 | - |
|
556 | - mapi_copyto($this->message, [], [], $sub); |
|
557 | - mapi_savechanges($sub); |
|
558 | - |
|
559 | - mapi_savechanges($attach); |
|
560 | - |
|
561 | - mapi_savechanges($outgoing); |
|
562 | - mapi_message_submitmessage($outgoing); |
|
563 | - |
|
564 | - return true; |
|
565 | - } |
|
566 | - |
|
567 | - // Assignee functions (called by the assignee) |
|
568 | - |
|
569 | - /* Update task version counter |
|
510 | + public function sendTaskRequest($prefix) { |
|
511 | + // Generate a TaskGlobalObjectId |
|
512 | + $taskid = $this->createTGOID(); |
|
513 | + $messageprops = mapi_getprops($this->message, [PR_SUBJECT]); |
|
514 | + |
|
515 | + // Set properties on Task Request |
|
516 | + mapi_setprops($this->message, [ |
|
517 | + $this->props['task_goid'] => $taskid, /* our new task_goid */ |
|
518 | + $this->props['taskstate'] => tdsACC, /* state for our outgoing request */ |
|
519 | + $this->props['taskmode'] => tdmtNothing, /* we're not sending a change */ |
|
520 | + $this->props['updatecount'] => 2, /* version 2 (no idea) */ |
|
521 | + $this->props['task_acceptance_state'] => olTaskDelegationUnknown, /* no reply yet */ |
|
522 | + $this->props['ownership'] => olDelegatedTask, /* Task has been assigned */ |
|
523 | + $this->props['taskhistory'] => thAssigned, /* Task has been assigned */ |
|
524 | + PR_CONVERSATION_TOPIC => $messageprops[PR_SUBJECT], |
|
525 | + PR_ICON_INDEX => ICON_TASK_ASSIGNER, /* Task request icon */ |
|
526 | + ]); |
|
527 | + $this->setLastUser(); |
|
528 | + $this->setOwnerForAssignor(); |
|
529 | + mapi_savechanges($this->message); |
|
530 | + |
|
531 | + // Create outgoing task request message |
|
532 | + $outgoing = $this->createOutgoingMessage(); |
|
533 | + |
|
534 | + // No need to copy PR_ICON_INDEX and PR_SENT_* information in to outgoing message. |
|
535 | + $ignoreProps = [PR_ICON_INDEX, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_SEARCH_KEY]; |
|
536 | + mapi_copyto($this->message, [], $ignoreProps, $outgoing); |
|
537 | + |
|
538 | + // Make it a task request, and put it in sent items after it is sent |
|
539 | + mapi_setprops($outgoing, [ |
|
540 | + PR_MESSAGE_CLASS => "IPM.TaskRequest", /* class is task request */ |
|
541 | + $this->props['taskstate'] => tdsOWN, /* for the recipient he is the task owner */ |
|
542 | + $this->props['taskmode'] => tdmtTaskReq, /* for the recipient it's a request */ |
|
543 | + $this->props['updatecount'] => 1, /* version 2 is in the attachment */ |
|
544 | + PR_SUBJECT_PREFIX => $prefix, |
|
545 | + PR_SUBJECT => $prefix . $messageprops[PR_SUBJECT], |
|
546 | + ]); |
|
547 | + |
|
548 | + $attach = mapi_message_createattach($outgoing); |
|
549 | + mapi_setprops($attach, [ |
|
550 | + PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG, |
|
551 | + PR_ATTACHMENT_HIDDEN => true, |
|
552 | + PR_DISPLAY_NAME => $messageprops[PR_SUBJECT], ]); |
|
553 | + |
|
554 | + $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_MODIFY | MAPI_CREATE); |
|
555 | + |
|
556 | + mapi_copyto($this->message, [], [], $sub); |
|
557 | + mapi_savechanges($sub); |
|
558 | + |
|
559 | + mapi_savechanges($attach); |
|
560 | + |
|
561 | + mapi_savechanges($outgoing); |
|
562 | + mapi_message_submitmessage($outgoing); |
|
563 | + |
|
564 | + return true; |
|
565 | + } |
|
566 | + |
|
567 | + // Assignee functions (called by the assignee) |
|
568 | + |
|
569 | + /* Update task version counter |
|
570 | 570 | * |
571 | 571 | * Must be called before each update to increase counter |
572 | 572 | */ |
573 | - public function updateTaskRequest() { |
|
574 | - $messageprops = mapi_getprops($this->message, [$this->props['updatecount']]); |
|
573 | + public function updateTaskRequest() { |
|
574 | + $messageprops = mapi_getprops($this->message, [$this->props['updatecount']]); |
|
575 | 575 | |
576 | - if (isset($messageprops)) { |
|
577 | - ++$messageprops[$this->props['updatecount']]; |
|
578 | - } |
|
579 | - else { |
|
580 | - $messageprops[$this->props['updatecount']] = 1; |
|
581 | - } |
|
576 | + if (isset($messageprops)) { |
|
577 | + ++$messageprops[$this->props['updatecount']]; |
|
578 | + } |
|
579 | + else { |
|
580 | + $messageprops[$this->props['updatecount']] = 1; |
|
581 | + } |
|
582 | 582 | |
583 | - mapi_setprops($this->message, $messageprops); |
|
584 | - } |
|
583 | + mapi_setprops($this->message, $messageprops); |
|
584 | + } |
|
585 | 585 | |
586 | - /* Process a task request |
|
586 | + /* Process a task request |
|
587 | 587 | * |
588 | 588 | * Message passed should be an IPM.TaskRequest message. The task request is then processed to create |
589 | 589 | * the task in the tasks folder if needed. |
590 | 590 | */ |
591 | - public function processTaskRequest() { |
|
592 | - if (!$this->isTaskRequest()) { |
|
593 | - return false; |
|
594 | - } |
|
595 | - $messageProps = mapi_getprops($this->message, [PR_PROCESSED, $this->props["taskupdates"], PR_MESSAGE_TO_ME]); |
|
596 | - if (isset($messageProps[PR_PROCESSED]) && $messageProps[PR_PROCESSED]) { |
|
597 | - return true; |
|
598 | - } |
|
599 | - |
|
600 | - // if task is updated in task folder then we don't need to process |
|
601 | - // old request. |
|
602 | - if ($this->isTaskRequestUpdated()) { |
|
603 | - return true; |
|
604 | - } |
|
605 | - |
|
606 | - $isReceivedItem = $this->isReceivedItem($messageProps); |
|
607 | - |
|
608 | - $props = []; |
|
609 | - $props[PR_PROCESSED] = true; |
|
610 | - $props[$this->props["taskstate"]] = $isReceivedItem ? tdsOWN : tdsACC; |
|
611 | - $props[$this->props["ownership"]] = $isReceivedItem ? olOwnTask : olDelegatedTask; |
|
612 | - |
|
613 | - mapi_setprops($this->message, $props); |
|
614 | - mapi_savechanges($this->message); |
|
615 | - |
|
616 | - // Don't create associated task in task folder if "taskupdates" is not true. |
|
617 | - if (!$isReceivedItem && !$messageProps[$this->props["taskupdates"]]) { |
|
618 | - return true; |
|
619 | - } |
|
620 | - // create an associated task in task folder while |
|
621 | - // reading/loading task request on client side. |
|
622 | - $task = $this->getAssociatedTask(true); |
|
623 | - $taskProps = mapi_getprops($task, [$this->props['taskmultrecips']]); |
|
624 | - $taskProps[$this->props["taskstate"]] = $isReceivedItem ? tdsOWN : tdsACC; |
|
625 | - $taskProps[$this->props["taskhistory"]] = thAssigned; |
|
626 | - $taskProps[$this->props["taskmode"]] = tdmtNothing; |
|
627 | - $taskProps[$this->props["taskaccepted"]] = false; |
|
628 | - $taskProps[$this->props["taskfcreator"]] = false; |
|
629 | - $taskProps[$this->props["ownership"]] = $isReceivedItem ? olOwnTask : olDelegatedTask; |
|
630 | - $taskProps[$this->props["task_acceptance_state"]] = olTaskNotDelegated; |
|
631 | - $taskProps[PR_ICON_INDEX] = ICON_TASK_ASSIGNEE; |
|
632 | - |
|
633 | - mapi_setprops($task, $taskProps); |
|
634 | - $this->setAssignorInRecipients($task); |
|
635 | - |
|
636 | - mapi_savechanges($task); |
|
637 | - |
|
638 | - return true; |
|
639 | - } |
|
640 | - |
|
641 | - /** |
|
642 | - * Accept a task request and send the response. |
|
643 | - * |
|
644 | - * Message passed should be an IPM.Task (eg the task from getAssociatedTask()) |
|
645 | - * |
|
646 | - * Copies the task to the user's task folder, sets it to accepted, and sends the acceptation |
|
647 | - * message back to the organizer. The caller is responsible for removing the message. |
|
648 | - * |
|
649 | - * @return entryid EntryID of the accepted task |
|
650 | - */ |
|
651 | - public function doAccept() { |
|
652 | - $prefix = _("Task Accepted:") . " "; |
|
653 | - $messageProps = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->props['taskstate']]); |
|
654 | - |
|
655 | - if (!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
|
656 | - // Can only accept assignee task |
|
657 | - return false; |
|
658 | - } |
|
659 | - |
|
660 | - $this->setLastUser(); |
|
661 | - $this->updateTaskRequest(); |
|
662 | - |
|
663 | - $props = [ |
|
664 | - $this->props['taskhistory'] => thAccepted, |
|
665 | - $this->props['task_assigned_time'] => time(), |
|
666 | - $this->props['taskaccepted'] => true, |
|
667 | - $this->props['task_acceptance_state'] => olTaskNotDelegated, ]; |
|
668 | - |
|
669 | - // Message is TaskRequest then update the associated task as well. |
|
670 | - if ($this->isTaskRequest($messageProps[PR_MESSAGE_CLASS])) { |
|
671 | - $task = $this->getAssociatedTask(false); |
|
672 | - if ($task) { |
|
673 | - mapi_setprops($task, $props); |
|
674 | - mapi_savechanges($task); |
|
675 | - } |
|
676 | - } |
|
677 | - |
|
678 | - // Set as accepted |
|
679 | - mapi_setprops($this->message, $props); |
|
680 | - |
|
681 | - // As we copy the all properties from received message we need to remove following |
|
682 | - // properties from accept response. |
|
683 | - mapi_deleteprops($this->message, [PR_MESSAGE_RECIP_ME, PR_MESSAGE_TO_ME, PR_MESSAGE_CC_ME, PR_PROCESSED]); |
|
684 | - |
|
685 | - mapi_savechanges($this->message); |
|
686 | - |
|
687 | - $this->sendResponse(tdmtTaskAcc, $prefix); |
|
688 | - |
|
689 | - return $this->deleteReceivedTR(); |
|
690 | - } |
|
691 | - |
|
692 | - /* Decline a task request and send the response. |
|
591 | + public function processTaskRequest() { |
|
592 | + if (!$this->isTaskRequest()) { |
|
593 | + return false; |
|
594 | + } |
|
595 | + $messageProps = mapi_getprops($this->message, [PR_PROCESSED, $this->props["taskupdates"], PR_MESSAGE_TO_ME]); |
|
596 | + if (isset($messageProps[PR_PROCESSED]) && $messageProps[PR_PROCESSED]) { |
|
597 | + return true; |
|
598 | + } |
|
599 | + |
|
600 | + // if task is updated in task folder then we don't need to process |
|
601 | + // old request. |
|
602 | + if ($this->isTaskRequestUpdated()) { |
|
603 | + return true; |
|
604 | + } |
|
605 | + |
|
606 | + $isReceivedItem = $this->isReceivedItem($messageProps); |
|
607 | + |
|
608 | + $props = []; |
|
609 | + $props[PR_PROCESSED] = true; |
|
610 | + $props[$this->props["taskstate"]] = $isReceivedItem ? tdsOWN : tdsACC; |
|
611 | + $props[$this->props["ownership"]] = $isReceivedItem ? olOwnTask : olDelegatedTask; |
|
612 | + |
|
613 | + mapi_setprops($this->message, $props); |
|
614 | + mapi_savechanges($this->message); |
|
615 | + |
|
616 | + // Don't create associated task in task folder if "taskupdates" is not true. |
|
617 | + if (!$isReceivedItem && !$messageProps[$this->props["taskupdates"]]) { |
|
618 | + return true; |
|
619 | + } |
|
620 | + // create an associated task in task folder while |
|
621 | + // reading/loading task request on client side. |
|
622 | + $task = $this->getAssociatedTask(true); |
|
623 | + $taskProps = mapi_getprops($task, [$this->props['taskmultrecips']]); |
|
624 | + $taskProps[$this->props["taskstate"]] = $isReceivedItem ? tdsOWN : tdsACC; |
|
625 | + $taskProps[$this->props["taskhistory"]] = thAssigned; |
|
626 | + $taskProps[$this->props["taskmode"]] = tdmtNothing; |
|
627 | + $taskProps[$this->props["taskaccepted"]] = false; |
|
628 | + $taskProps[$this->props["taskfcreator"]] = false; |
|
629 | + $taskProps[$this->props["ownership"]] = $isReceivedItem ? olOwnTask : olDelegatedTask; |
|
630 | + $taskProps[$this->props["task_acceptance_state"]] = olTaskNotDelegated; |
|
631 | + $taskProps[PR_ICON_INDEX] = ICON_TASK_ASSIGNEE; |
|
632 | + |
|
633 | + mapi_setprops($task, $taskProps); |
|
634 | + $this->setAssignorInRecipients($task); |
|
635 | + |
|
636 | + mapi_savechanges($task); |
|
637 | + |
|
638 | + return true; |
|
639 | + } |
|
640 | + |
|
641 | + /** |
|
642 | + * Accept a task request and send the response. |
|
643 | + * |
|
644 | + * Message passed should be an IPM.Task (eg the task from getAssociatedTask()) |
|
645 | + * |
|
646 | + * Copies the task to the user's task folder, sets it to accepted, and sends the acceptation |
|
647 | + * message back to the organizer. The caller is responsible for removing the message. |
|
648 | + * |
|
649 | + * @return entryid EntryID of the accepted task |
|
650 | + */ |
|
651 | + public function doAccept() { |
|
652 | + $prefix = _("Task Accepted:") . " "; |
|
653 | + $messageProps = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->props['taskstate']]); |
|
654 | + |
|
655 | + if (!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
|
656 | + // Can only accept assignee task |
|
657 | + return false; |
|
658 | + } |
|
659 | + |
|
660 | + $this->setLastUser(); |
|
661 | + $this->updateTaskRequest(); |
|
662 | + |
|
663 | + $props = [ |
|
664 | + $this->props['taskhistory'] => thAccepted, |
|
665 | + $this->props['task_assigned_time'] => time(), |
|
666 | + $this->props['taskaccepted'] => true, |
|
667 | + $this->props['task_acceptance_state'] => olTaskNotDelegated, ]; |
|
668 | + |
|
669 | + // Message is TaskRequest then update the associated task as well. |
|
670 | + if ($this->isTaskRequest($messageProps[PR_MESSAGE_CLASS])) { |
|
671 | + $task = $this->getAssociatedTask(false); |
|
672 | + if ($task) { |
|
673 | + mapi_setprops($task, $props); |
|
674 | + mapi_savechanges($task); |
|
675 | + } |
|
676 | + } |
|
677 | + |
|
678 | + // Set as accepted |
|
679 | + mapi_setprops($this->message, $props); |
|
680 | + |
|
681 | + // As we copy the all properties from received message we need to remove following |
|
682 | + // properties from accept response. |
|
683 | + mapi_deleteprops($this->message, [PR_MESSAGE_RECIP_ME, PR_MESSAGE_TO_ME, PR_MESSAGE_CC_ME, PR_PROCESSED]); |
|
684 | + |
|
685 | + mapi_savechanges($this->message); |
|
686 | + |
|
687 | + $this->sendResponse(tdmtTaskAcc, $prefix); |
|
688 | + |
|
689 | + return $this->deleteReceivedTR(); |
|
690 | + } |
|
691 | + |
|
692 | + /* Decline a task request and send the response. |
|
693 | 693 | * |
694 | 694 | * Passed message must be a task request message, ie isTaskRequest() must return TRUE. |
695 | 695 | * |
@@ -697,591 +697,591 @@ discard block |
||
697 | 697 | * |
698 | 698 | * @return boolean TRUE on success, FALSE on failure |
699 | 699 | */ |
700 | - public function doDecline() { |
|
701 | - $prefix = _("Task Declined:") . " "; |
|
702 | - $messageProps = mapi_getprops($this->message, [$this->props['taskstate']]); |
|
703 | - |
|
704 | - if (!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
|
705 | - return false; // Can only decline assignee task |
|
706 | - } |
|
707 | - |
|
708 | - $this->setLastUser(); |
|
709 | - $this->updateTaskRequest(); |
|
710 | - |
|
711 | - // Set as declined |
|
712 | - mapi_setprops($this->message, [ |
|
713 | - $this->props['taskhistory'] => thDeclined, |
|
714 | - $this->props['task_acceptance_state'] => olTaskDelegationDeclined, |
|
715 | - ]); |
|
716 | - mapi_deleteprops($this->message, [PR_MESSAGE_RECIP_ME, PR_MESSAGE_TO_ME, PR_MESSAGE_CC_ME, PR_PROCESSED]); |
|
717 | - mapi_savechanges($this->message); |
|
718 | - |
|
719 | - $this->sendResponse(tdmtTaskDec, $prefix); |
|
720 | - |
|
721 | - // Delete the associated task when task request is declined by the assignee. |
|
722 | - $task = $this->getAssociatedTask(false); |
|
723 | - if ($task) { |
|
724 | - $taskFolder = $this->getDefaultTasksFolder(); |
|
725 | - $props = mapi_getprops($task, [PR_ENTRYID]); |
|
726 | - mapi_folder_deletemessages($taskFolder, [$props[PR_ENTRYID]]); |
|
727 | - } |
|
728 | - |
|
729 | - return $this->deleteReceivedTR(); |
|
730 | - } |
|
731 | - |
|
732 | - /** |
|
733 | - * Send an update of the task if requested, and send the Status-On-Completion report if complete and requested. |
|
734 | - * |
|
735 | - * If no updates were requested from the organizer, this function does nothing. |
|
736 | - * |
|
737 | - * @return bool TRUE if the update succeeded, FALSE otherwise |
|
738 | - */ |
|
739 | - public function doUpdate() { |
|
740 | - $messageProps = mapi_getprops($this->message, [$this->props['taskstate'], PR_SUBJECT]); |
|
741 | - |
|
742 | - if (!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
|
743 | - return false; // Can only update assignee task |
|
744 | - } |
|
745 | - |
|
746 | - $this->setLastUser(); |
|
747 | - $this->updateTaskRequest(); |
|
748 | - |
|
749 | - // Set as updated |
|
750 | - mapi_setprops($this->message, [$this->props['taskhistory'] => thUpdated]); |
|
751 | - |
|
752 | - mapi_savechanges($this->message); |
|
753 | - |
|
754 | - $props = mapi_getprops($this->message, [$this->props['taskupdates'], $this->props['tasksoc'], $this->props['recurring'], $this->props['complete']]); |
|
755 | - if (!$props[$this->props['complete']] && $props[$this->props['taskupdates']] && !(isset($props[$this->props['recurring']]) && $props[$this->props['recurring']])) { |
|
756 | - $this->sendResponse(tdmtTaskUpd, _("Task Updated:") . " "); |
|
757 | - } |
|
758 | - elseif ($props[$this->props['complete']]) { |
|
759 | - $this->sendResponse(tdmtTaskUpd, _("Task Completed:") . " "); |
|
760 | - } |
|
761 | - |
|
762 | - return true; |
|
763 | - } |
|
764 | - |
|
765 | - /** |
|
766 | - * Get the store associated with the task. |
|
767 | - * |
|
768 | - * Normally this will just open the store that the processed message is in. However, if the message is opened |
|
769 | - * by a delegate, this function opens the store that the message was delegated from. |
|
770 | - */ |
|
771 | - public function getTaskFolderStore() { |
|
772 | - $ownerentryid = false; |
|
773 | - |
|
774 | - $rcvdprops = mapi_getprops($this->message, [PR_RCVD_REPRESENTING_ENTRYID]); |
|
775 | - if (isset($rcvdprops[PR_RCVD_REPRESENTING_ENTRYID])) { |
|
776 | - $ownerentryid = $rcvdprops; |
|
777 | - } |
|
778 | - |
|
779 | - if (!$ownerentryid) { |
|
780 | - $store = $this->store; |
|
781 | - } |
|
782 | - else { |
|
783 | - $ab = mapi_openaddressbook($this->session); |
|
784 | - if (!$ab) { |
|
785 | - return false; |
|
786 | - } |
|
787 | - |
|
788 | - $mailuser = mapi_ab_openentry($ab, $ownerentryid); |
|
789 | - if (!$mailuser) { |
|
790 | - return false; |
|
791 | - } |
|
792 | - |
|
793 | - $mailuserprops = mapi_getprops($mailuser, [PR_EMAIL_ADDRESS]); |
|
794 | - if (!isset($mailuserprops[PR_EMAIL_ADDRESS])) { |
|
795 | - return false; |
|
796 | - } |
|
797 | - |
|
798 | - $storeid = mapi_msgstore_createentryid($this->store, $mailuserprops[PR_EMAIL_ADDRESS]); |
|
799 | - |
|
800 | - $store = mapi_openmsgstore($this->session, $storeid); |
|
801 | - } |
|
802 | - |
|
803 | - return $store; |
|
804 | - } |
|
805 | - |
|
806 | - /** |
|
807 | - * Open the default task folder for the current user, or the specified user if passed. |
|
808 | - */ |
|
809 | - public function getDefaultTasksFolder() { |
|
810 | - $store = $this->getTaskFolderStore(); |
|
811 | - |
|
812 | - $inbox = mapi_msgstore_getreceivefolder($store); |
|
813 | - $inboxprops = mapi_getprops($inbox, [PR_IPM_TASK_ENTRYID]); |
|
814 | - if (!isset($inboxprops[PR_IPM_TASK_ENTRYID])) { |
|
815 | - return false; |
|
816 | - } |
|
817 | - |
|
818 | - return mapi_msgstore_openentry($store, $inboxprops[PR_IPM_TASK_ENTRYID]); |
|
819 | - } |
|
820 | - |
|
821 | - /** |
|
822 | - * Function prepare the sent representing properties from given MAPI store. |
|
823 | - * |
|
824 | - * @param $store MAPI store object |
|
825 | - * |
|
826 | - * @return array|bool if store is not mail box owner entryid then |
|
827 | - * return false else prepare the sent representing props and return it |
|
828 | - */ |
|
829 | - public function getSentReprProps($store) { |
|
830 | - $storeprops = mapi_getprops($store, [PR_MAILBOX_OWNER_ENTRYID]); |
|
831 | - if (!isset($storeprops[PR_MAILBOX_OWNER_ENTRYID])) { |
|
832 | - return false; |
|
833 | - } |
|
834 | - |
|
835 | - $ab = mapi_openaddressbook($this->session); |
|
836 | - $mailuser = mapi_ab_openentry($ab, $storeprops[PR_MAILBOX_OWNER_ENTRYID]); |
|
837 | - $mailuserprops = mapi_getprops($mailuser, [PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_DISPLAY_NAME, PR_SEARCH_KEY, PR_ENTRYID]); |
|
838 | - |
|
839 | - $props = []; |
|
840 | - $props[PR_SENT_REPRESENTING_ADDRTYPE] = $mailuserprops[PR_ADDRTYPE]; |
|
841 | - $props[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $mailuserprops[PR_EMAIL_ADDRESS]; |
|
842 | - $props[PR_SENT_REPRESENTING_NAME] = $mailuserprops[PR_DISPLAY_NAME]; |
|
843 | - $props[PR_SENT_REPRESENTING_SEARCH_KEY] = $mailuserprops[PR_SEARCH_KEY]; |
|
844 | - $props[PR_SENT_REPRESENTING_ENTRYID] = $mailuserprops[PR_ENTRYID]; |
|
845 | - |
|
846 | - return $props; |
|
847 | - } |
|
848 | - |
|
849 | - /** |
|
850 | - * Creates an outgoing message based on the passed message - will set delegate information |
|
851 | - * and sent mail folder. |
|
852 | - */ |
|
853 | - public function createOutgoingMessage() { |
|
854 | - // Open our default store for this user (that's the only store we can submit in) |
|
855 | - $store = $this->getDefaultStore(); |
|
856 | - $storeprops = mapi_getprops($store, [PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID]); |
|
857 | - |
|
858 | - $outbox = mapi_msgstore_openentry($store, $storeprops[PR_IPM_OUTBOX_ENTRYID]); |
|
859 | - if (!$outbox) { |
|
860 | - return false; |
|
861 | - } |
|
862 | - |
|
863 | - $outgoing = mapi_folder_createmessage($outbox); |
|
864 | - if (!$outgoing) { |
|
865 | - return false; |
|
866 | - } |
|
867 | - |
|
868 | - // Set SENT_REPRESENTING in case we're sending as a delegate |
|
869 | - $ownerstore = $this->getTaskFolderStore(); |
|
870 | - $sentreprprops = $this->getSentReprProps($ownerstore); |
|
871 | - mapi_setprops($outgoing, $sentreprprops); |
|
872 | - |
|
873 | - mapi_setprops($outgoing, [PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID]]); |
|
874 | - |
|
875 | - return $outgoing; |
|
876 | - } |
|
877 | - |
|
878 | - /** |
|
879 | - * Send a response message (from assignee back to organizer). |
|
880 | - * |
|
881 | - * @param $type int Type of response (tdmtTaskAcc, tdmtTaskDec, tdmtTaskUpd); |
|
882 | - * @param mixed $prefix |
|
883 | - * |
|
884 | - * @return bool TRUE on success |
|
885 | - */ |
|
886 | - public function sendResponse($type, $prefix) { |
|
887 | - // Create a message in our outbox |
|
888 | - $outgoing = $this->createOutgoingMessage(); |
|
889 | - $messageprops = mapi_getprops($this->message, [PR_CONVERSATION_TOPIC, PR_MESSAGE_CLASS, $this->props['complete']]); |
|
890 | - |
|
891 | - $attach = mapi_message_createattach($outgoing); |
|
892 | - mapi_setprops($attach, [PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG, PR_DISPLAY_NAME => $messageprops[PR_CONVERSATION_TOPIC], PR_ATTACHMENT_HIDDEN => true]); |
|
893 | - $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_CREATE | MAPI_MODIFY); |
|
894 | - |
|
895 | - $message = !$this->isTaskRequest() ? $this->message : $this->getAssociatedTask(false); |
|
896 | - |
|
897 | - $ignoreProps = [PR_ICON_INDEX, $this->props["categories"], PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_SEARCH_KEY]; |
|
898 | - |
|
899 | - mapi_copyto($message, [], $ignoreProps, $outgoing); |
|
900 | - mapi_copyto($message, [], [], $sub); |
|
901 | - |
|
902 | - if (!$this->setRecipientsForResponse($outgoing, $type)) { |
|
903 | - return false; |
|
904 | - } |
|
905 | - |
|
906 | - $props = []; |
|
907 | - |
|
908 | - switch ($type) { |
|
909 | - case tdmtTaskAcc: |
|
910 | - $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Accept"; |
|
911 | - mapi_setprops($sub, [PR_ICON_INDEX => ICON_TASK_ASSIGNER]); |
|
912 | - |
|
913 | - break; |
|
914 | - |
|
915 | - case tdmtTaskDec: |
|
916 | - $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Decline"; |
|
917 | - mapi_setprops($sub, [PR_ICON_INDEX => ICON_TASK_DECLINE]); |
|
918 | - |
|
919 | - break; |
|
920 | - |
|
921 | - case tdmtTaskUpd: |
|
922 | - mapi_setprops($sub, [PR_ICON_INDEX => ICON_TASK_ASSIGNER]); |
|
923 | - if ($messageprops[$this->props['complete']]) { |
|
924 | - $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Complete"; |
|
925 | - } |
|
926 | - else { |
|
927 | - $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Update"; |
|
928 | - } |
|
929 | - |
|
930 | - break; |
|
931 | - } |
|
932 | - |
|
933 | - mapi_savechanges($sub); |
|
934 | - mapi_savechanges($attach); |
|
935 | - |
|
936 | - $props[PR_SUBJECT] = $prefix . $messageprops[PR_CONVERSATION_TOPIC]; |
|
937 | - $props[$this->props['taskmode']] = $type; |
|
938 | - $props[$this->props['task_assigned_time']] = time(); |
|
939 | - |
|
940 | - mapi_setprops($outgoing, $props); |
|
941 | - |
|
942 | - // taskCommentsInfo contains some comments which added by assignee while |
|
943 | - // edit response before sending task response. |
|
944 | - if ($this->taskCommentsInfo) { |
|
945 | - $comments = $this->getTaskCommentsInfo(); |
|
946 | - $stream = mapi_openproperty($outgoing, PR_BODY, IID_IStream, STGM_TRANSACTED, MAPI_CREATE | MAPI_MODIFY); |
|
947 | - mapi_stream_setsize($stream, strlen($comments)); |
|
948 | - mapi_stream_write($stream, $comments); |
|
949 | - mapi_stream_commit($stream); |
|
950 | - } |
|
951 | - |
|
952 | - mapi_savechanges($outgoing); |
|
953 | - mapi_message_submitmessage($outgoing); |
|
954 | - |
|
955 | - return true; |
|
956 | - } |
|
957 | - |
|
958 | - public function getDefaultStore() { |
|
959 | - $table = mapi_getmsgstorestable($this->session); |
|
960 | - $rows = mapi_table_queryallrows($table, [PR_DEFAULT_STORE, PR_ENTRYID]); |
|
961 | - |
|
962 | - foreach ($rows as $row) { |
|
963 | - if ($row[PR_DEFAULT_STORE]) { |
|
964 | - return mapi_openmsgstore($this->session, $row[PR_ENTRYID]); |
|
965 | - } |
|
966 | - } |
|
967 | - |
|
968 | - return false; |
|
969 | - } |
|
970 | - |
|
971 | - /** |
|
972 | - * Creates a new TaskGlobalObjId. |
|
973 | - * |
|
974 | - * Just 16 bytes of random data |
|
975 | - */ |
|
976 | - public function createTGOID() { |
|
977 | - $goid = ""; |
|
978 | - for ($i = 0; $i < 16; ++$i) { |
|
979 | - $goid .= chr(rand(0, 255)); |
|
980 | - } |
|
981 | - |
|
982 | - return $goid; |
|
983 | - } |
|
984 | - |
|
985 | - /** |
|
986 | - * Function used to get the embedded task of task request. Which further used to |
|
987 | - * Create/Update associated task of assigner/assignee. |
|
988 | - * |
|
989 | - * @param object $message which contains embedded task |
|
990 | - * |
|
991 | - * @return false|object $task if found embedded task else false |
|
992 | - */ |
|
993 | - public function getEmbeddedTask($message) { |
|
994 | - $task = false; |
|
995 | - $goid = mapi_getprops($message, [$this->props["task_goid"]]); |
|
996 | - $attachmentTable = mapi_message_getattachmenttable($message); |
|
997 | - $restriction = [ |
|
998 | - RES_PROPERTY, |
|
999 | - [ |
|
1000 | - RELOP => RELOP_EQ, |
|
1001 | - ULPROPTAG => PR_ATTACH_METHOD, |
|
1002 | - VALUE => ATTACH_EMBEDDED_MSG, ], |
|
1003 | - ]; |
|
1004 | - $rows = mapi_table_queryallrows($attachmentTable, [PR_ATTACH_NUM], $restriction); |
|
1005 | - |
|
1006 | - if (empty($rows)) { |
|
1007 | - return $task; |
|
1008 | - } |
|
1009 | - |
|
1010 | - foreach ($rows as $row) { |
|
1011 | - try { |
|
1012 | - $attach = mapi_message_openattach($message, $row[PR_ATTACH_NUM]); |
|
1013 | - $task = mapi_attach_openobj($attach); |
|
1014 | - } |
|
1015 | - catch (MAPIException $e) { |
|
1016 | - continue; |
|
1017 | - } |
|
1018 | - |
|
1019 | - $taskGoid = mapi_getprops($task, [$this->props["task_goid"]]); |
|
1020 | - if ($goid[$this->props["task_goid"]] === $taskGoid[$this->props["task_goid"]]) { |
|
1021 | - mapi_setprops($attach, [PR_ATTACHMENT_HIDDEN => true]); |
|
1022 | - mapi_savechanges($attach); |
|
1023 | - mapi_savechanges($message); |
|
1024 | - |
|
1025 | - break; |
|
1026 | - } |
|
1027 | - } |
|
1028 | - |
|
1029 | - return $task; |
|
1030 | - } |
|
1031 | - |
|
1032 | - /** |
|
1033 | - * Function was used to set the user name who has last used this task also it was |
|
1034 | - * update the tasklastdelegate and task_assigned_time. |
|
1035 | - */ |
|
1036 | - public function setLastUser() { |
|
1037 | - $delegatestore = $this->getDefaultStore(); |
|
1038 | - $taskstore = $this->getTaskFolderStore(); |
|
1039 | - |
|
1040 | - $delegateprops = mapi_getprops($delegatestore, [PR_MAILBOX_OWNER_NAME]); |
|
1041 | - $taskprops = mapi_getprops($taskstore, [PR_MAILBOX_OWNER_NAME]); |
|
1042 | - |
|
1043 | - // The owner of the task |
|
1044 | - $username = $delegateprops[PR_MAILBOX_OWNER_NAME]; |
|
1045 | - // This is me (the one calling the script) |
|
1046 | - $delegate = $taskprops[PR_MAILBOX_OWNER_NAME]; |
|
1047 | - |
|
1048 | - if ($this->isTaskRequest()) { |
|
1049 | - $task = $this->getAssociatedTask(false); |
|
1050 | - mapi_setprops($task, [$this->props["tasklastuser"] => $username, $this->props["tasklastdelegate"] => $delegate, $this->props['task_assigned_time'] => time()]); |
|
1051 | - mapi_savechanges($task); |
|
1052 | - } |
|
1053 | - mapi_setprops($this->message, [$this->props["tasklastuser"] => $username, $this->props["tasklastdelegate"] => $delegate, $this->props['task_assigned_time'] => time()]); |
|
1054 | - } |
|
1055 | - |
|
1056 | - /** |
|
1057 | - * Assignee becomes the owner when a user/assignor assigns any task to someone. Also there can be more than one assignee. |
|
1058 | - * This function sets assignee as owner in the assignor's copy of task. |
|
1059 | - */ |
|
1060 | - public function setOwnerForAssignor() { |
|
1061 | - $recipTable = mapi_message_getrecipienttable($this->message); |
|
1062 | - $recips = mapi_table_queryallrows($recipTable, [PR_DISPLAY_NAME]); |
|
1063 | - |
|
1064 | - if (!empty($recips)) { |
|
1065 | - $owner = []; |
|
1066 | - foreach ($recips as $value) { |
|
1067 | - $owner[] = $value[PR_DISPLAY_NAME]; |
|
1068 | - } |
|
1069 | - |
|
1070 | - $props = [$this->props['owner'] => implode("; ", $owner)]; |
|
1071 | - mapi_setprops($this->message, $props); |
|
1072 | - } |
|
1073 | - } |
|
1074 | - |
|
1075 | - /** |
|
1076 | - * Sets assignor as recipients in assignee's copy of task. |
|
1077 | - * |
|
1078 | - * If assignor has requested task updates then the assignor is added as recipient type MAPI_CC. |
|
1079 | - * |
|
1080 | - * Also if assignor has request SOC then the assignor is also add as recipient type MAPI_BCC |
|
1081 | - * |
|
1082 | - * @param $task message MAPI message which assignee's copy of task |
|
1083 | - */ |
|
1084 | - public function setAssignorInRecipients($task) { |
|
1085 | - $recipTable = mapi_message_getrecipienttable($task); |
|
1086 | - |
|
1087 | - // Delete all MAPI_TO recipients |
|
1088 | - $recips = mapi_table_queryallrows($recipTable, [PR_ROWID], [ |
|
1089 | - RES_PROPERTY, |
|
1090 | - [ |
|
1091 | - RELOP => RELOP_EQ, |
|
1092 | - ULPROPTAG => PR_RECIPIENT_TYPE, |
|
1093 | - VALUE => MAPI_TO, |
|
1094 | - ], ]); |
|
1095 | - foreach ($recips as $recip) { |
|
1096 | - mapi_message_modifyrecipients($task, MODRECIP_REMOVE, [$recip]); |
|
1097 | - } |
|
1098 | - |
|
1099 | - $recips = []; |
|
1100 | - $taskReqProps = mapi_getprops($this->message, [PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_SEARCH_KEY]); |
|
1101 | - $associatedTaskProps = mapi_getprops($task, [$this->props['taskupdates'], $this->props['tasksoc'], $this->props['taskmultrecips']]); |
|
1102 | - |
|
1103 | - // Build assignor info |
|
1104 | - $assignor = [ |
|
1105 | - PR_ENTRYID => $taskReqProps[PR_SENT_REPRESENTING_ENTRYID], |
|
1106 | - PR_DISPLAY_NAME => $taskReqProps[PR_SENT_REPRESENTING_NAME], |
|
1107 | - PR_EMAIL_ADDRESS => $taskReqProps[PR_SENT_REPRESENTING_EMAIL_ADDRESS], |
|
1108 | - PR_RECIPIENT_DISPLAY_NAME => $taskReqProps[PR_SENT_REPRESENTING_NAME], |
|
1109 | - PR_ADDRTYPE => empty($taskReqProps[PR_SENT_REPRESENTING_ADDRTYPE]) ? 'SMTP' : $taskReqProps[PR_SENT_REPRESENTING_ADDRTYPE], |
|
1110 | - PR_RECIPIENT_FLAGS => recipSendable, |
|
1111 | - PR_SEARCH_KEY => $taskReqProps[PR_SENT_REPRESENTING_SEARCH_KEY], |
|
1112 | - ]; |
|
1113 | - |
|
1114 | - // Assignor has requested task updates, so set him/her as MAPI_CC in recipienttable. |
|
1115 | - if ((isset($associatedTaskProps[$this->props['taskupdates']]) && $associatedTaskProps[$this->props['taskupdates']]) && |
|
1116 | - !(isset($associatedTaskProps[$this->props['taskmultrecips']]) && $associatedTaskProps[$this->props['taskmultrecips']] == tmrReceived)) { |
|
1117 | - $assignor[PR_RECIPIENT_TYPE] = MAPI_CC; |
|
1118 | - $recips[] = $assignor; |
|
1119 | - } |
|
1120 | - |
|
1121 | - // Assignor wants to receive an email report when task is mark as 'Complete', so in recipients as MAPI_BCC |
|
1122 | - if ($associatedTaskProps[$this->props['tasksoc']]) { |
|
1123 | - $assignor[PR_RECIPIENT_TYPE] = MAPI_BCC; |
|
1124 | - $recips[] = $assignor; |
|
1125 | - } |
|
1126 | - |
|
1127 | - if (!empty($recips)) { |
|
1128 | - mapi_message_modifyrecipients($task, MODRECIP_ADD, $recips); |
|
1129 | - } |
|
1130 | - } |
|
1131 | - |
|
1132 | - /** |
|
1133 | - * Deletes incoming task request from Inbox. |
|
1134 | - * |
|
1135 | - * @returns array returns PR_ENTRYID, PR_STORE_ENTRYID and PR_PARENT_ENTRYID of the deleted task request |
|
1136 | - */ |
|
1137 | - public function deleteReceivedTR() { |
|
1138 | - $store = $this->getTaskFolderStore(); |
|
1139 | - $storeType = mapi_getprops($store, [PR_MDB_PROVIDER]); |
|
1140 | - if ($storeType[PR_MDB_PROVIDER] === ZARAFA_STORE_PUBLIC_GUID) { |
|
1141 | - $store = $this->getDefaultStore(); |
|
1142 | - } |
|
1143 | - $inbox = mapi_msgstore_getreceivefolder($store); |
|
1144 | - |
|
1145 | - $storeProps = mapi_getprops($store, [PR_IPM_WASTEBASKET_ENTRYID]); |
|
1146 | - $props = mapi_getprops($this->message, [$this->props['task_goid']]); |
|
1147 | - $goid = $props[$this->props['task_goid']]; |
|
1148 | - |
|
1149 | - // Find the task by looking for the task_goid |
|
1150 | - $restriction = [ |
|
1151 | - RES_PROPERTY, |
|
1152 | - [ |
|
1153 | - RELOP => RELOP_EQ, |
|
1154 | - ULPROPTAG => $this->props['task_goid'], |
|
1155 | - VALUE => $goid, ], |
|
1156 | - ]; |
|
1157 | - |
|
1158 | - $contents = mapi_folder_getcontentstable($inbox); |
|
1159 | - |
|
1160 | - $rows = mapi_table_queryallrows($contents, [PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID], $restriction); |
|
1161 | - |
|
1162 | - if (!empty($rows)) { |
|
1163 | - // If there are multiple, just use the first |
|
1164 | - $entryid = $rows[0][PR_ENTRYID]; |
|
1165 | - $wastebasket = mapi_msgstore_openentry($store, $storeProps[PR_IPM_WASTEBASKET_ENTRYID]); |
|
1166 | - mapi_folder_copymessages($inbox, [$entryid], $wastebasket, MESSAGE_MOVE); |
|
1167 | - |
|
1168 | - return [PR_ENTRYID => $entryid, PR_PARENT_ENTRYID => $rows[0][PR_PARENT_ENTRYID], PR_STORE_ENTRYID => $rows[0][PR_STORE_ENTRYID]]; |
|
1169 | - } |
|
1170 | - |
|
1171 | - return false; |
|
1172 | - } |
|
1173 | - |
|
1174 | - /** |
|
1175 | - * Sets recipients for the outgoing message according to type of the response. |
|
1176 | - * |
|
1177 | - * If it is a task update, then only recipient type MAPI_CC are taken from the task message. |
|
1178 | - * |
|
1179 | - * If it is accept/decline response, then PR_SENT_REPRESENTATING_XXXX are taken as recipient. |
|
1180 | - * |
|
1181 | - *@param $outgoing MAPI_message outgoing mapi message |
|
1182 | - *@param $responseType String response type |
|
1183 | - */ |
|
1184 | - public function setRecipientsForResponse($outgoing, $responseType) { |
|
1185 | - // Clear recipients from outgoing msg |
|
1186 | - $this->deleteAllRecipients($outgoing); |
|
1187 | - |
|
1188 | - // If it is a task update then get MAPI_CC recipients which are assignors who has asked for task update. |
|
1189 | - if ($responseType == tdmtTaskUpd) { |
|
1190 | - $props = mapi_getprops($this->message, [$this->props['complete']]); |
|
1191 | - $isComplete = $props[$this->props['complete']]; |
|
1192 | - |
|
1193 | - $recipTable = mapi_message_getrecipienttable($this->message); |
|
1194 | - $recips = mapi_table_queryallrows($recipTable, $this->recipProps, [ |
|
1195 | - RES_PROPERTY, |
|
1196 | - [ |
|
1197 | - RELOP => RELOP_EQ, |
|
1198 | - ULPROPTAG => PR_RECIPIENT_TYPE, |
|
1199 | - VALUE => ($isComplete ? MAPI_BCC : MAPI_CC), |
|
1200 | - ], |
|
1201 | - ]); |
|
1202 | - |
|
1203 | - // No recipients found, return error |
|
1204 | - if (empty($recips)) { |
|
1205 | - return false; |
|
1206 | - } |
|
1207 | - |
|
1208 | - foreach ($recips as $recip) { |
|
1209 | - $recip[PR_RECIPIENT_TYPE] = MAPI_TO; // Change recipient type to MAPI_TO |
|
1210 | - mapi_message_modifyrecipients($outgoing, MODRECIP_ADD, [$recip]); |
|
1211 | - } |
|
1212 | - |
|
1213 | - return true; |
|
1214 | - } |
|
1215 | - |
|
1216 | - $orgprops = mapi_getprops($this->message, [PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_ENTRYID, PR_SUBJECT]); |
|
1217 | - $recip = [ |
|
1218 | - PR_DISPLAY_NAME => $orgprops[PR_SENT_REPRESENTING_NAME], |
|
1219 | - PR_EMAIL_ADDRESS => $orgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS], |
|
1220 | - PR_ADDRTYPE => $orgprops[PR_SENT_REPRESENTING_ADDRTYPE], |
|
1221 | - PR_ENTRYID => $orgprops[PR_SENT_REPRESENTING_ENTRYID], |
|
1222 | - PR_RECIPIENT_TYPE => MAPI_TO, ]; |
|
1223 | - |
|
1224 | - mapi_message_modifyrecipients($outgoing, MODRECIP_ADD, [$recip]); |
|
1225 | - |
|
1226 | - return true; |
|
1227 | - } |
|
1228 | - |
|
1229 | - /** |
|
1230 | - * Deletes all recipients from given message object. |
|
1231 | - * |
|
1232 | - * @param $message MAPI message from which recipients are to be removed |
|
1233 | - */ |
|
1234 | - public function deleteAllRecipients($message) { |
|
1235 | - $recipTable = mapi_message_getrecipienttable($message); |
|
1236 | - $recipRows = mapi_table_queryallrows($recipTable, [PR_ROWID]); |
|
1237 | - |
|
1238 | - foreach ($recipRows as $recipient) { |
|
1239 | - mapi_message_modifyrecipients($message, MODRECIP_REMOVE, [$recipient]); |
|
1240 | - } |
|
1241 | - } |
|
1242 | - |
|
1243 | - /** |
|
1244 | - * Function used to mark the record to complete and send complete update |
|
1245 | - * notification to assigner. |
|
1246 | - * |
|
1247 | - * @return bool TRUE if the update succeeded, FALSE otherwise |
|
1248 | - */ |
|
1249 | - public function sendCompleteUpdate() { |
|
1250 | - $messageprops = mapi_getprops($this->message, [$this->props['taskstate']]); |
|
1251 | - |
|
1252 | - if (!isset($messageprops[$this->props['taskstate']]) || $messageprops[$this->props['taskstate']] != tdsOWN) { |
|
1253 | - return false; // Can only decline assignee task |
|
1254 | - } |
|
1255 | - |
|
1256 | - mapi_setprops( |
|
1257 | - $this->message, |
|
1258 | - [ |
|
1259 | - $this->props['complete'] => true, |
|
1260 | - $this->props['datecompleted'] => time(), |
|
1261 | - $this->props['status'] => 2, |
|
1262 | - $this->props['percent_complete'] => 1, ] |
|
1263 | - ); |
|
1264 | - |
|
1265 | - return $this->doUpdate(); |
|
1266 | - } |
|
1267 | - |
|
1268 | - /** |
|
1269 | - * Function returns extra info about task request comments along with message body |
|
1270 | - * which will be included in body while sending task request/response. |
|
1271 | - * |
|
1272 | - * @return string info about task request comments along with message body |
|
1273 | - */ |
|
1274 | - public function getTaskCommentsInfo() { |
|
1275 | - return $this->taskCommentsInfo; |
|
1276 | - } |
|
1277 | - |
|
1278 | - /** |
|
1279 | - * Function sets extra info about task request comments along with message body |
|
1280 | - * which will be included in body while sending task request/response. |
|
1281 | - * |
|
1282 | - * @param string $taskCommentsInfo info about task request comments along with message body |
|
1283 | - */ |
|
1284 | - public function setTaskCommentsInfo($taskCommentsInfo) { |
|
1285 | - $this->taskCommentsInfo = $taskCommentsInfo; |
|
1286 | - } |
|
1287 | - } |
|
700 | + public function doDecline() { |
|
701 | + $prefix = _("Task Declined:") . " "; |
|
702 | + $messageProps = mapi_getprops($this->message, [$this->props['taskstate']]); |
|
703 | + |
|
704 | + if (!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
|
705 | + return false; // Can only decline assignee task |
|
706 | + } |
|
707 | + |
|
708 | + $this->setLastUser(); |
|
709 | + $this->updateTaskRequest(); |
|
710 | + |
|
711 | + // Set as declined |
|
712 | + mapi_setprops($this->message, [ |
|
713 | + $this->props['taskhistory'] => thDeclined, |
|
714 | + $this->props['task_acceptance_state'] => olTaskDelegationDeclined, |
|
715 | + ]); |
|
716 | + mapi_deleteprops($this->message, [PR_MESSAGE_RECIP_ME, PR_MESSAGE_TO_ME, PR_MESSAGE_CC_ME, PR_PROCESSED]); |
|
717 | + mapi_savechanges($this->message); |
|
718 | + |
|
719 | + $this->sendResponse(tdmtTaskDec, $prefix); |
|
720 | + |
|
721 | + // Delete the associated task when task request is declined by the assignee. |
|
722 | + $task = $this->getAssociatedTask(false); |
|
723 | + if ($task) { |
|
724 | + $taskFolder = $this->getDefaultTasksFolder(); |
|
725 | + $props = mapi_getprops($task, [PR_ENTRYID]); |
|
726 | + mapi_folder_deletemessages($taskFolder, [$props[PR_ENTRYID]]); |
|
727 | + } |
|
728 | + |
|
729 | + return $this->deleteReceivedTR(); |
|
730 | + } |
|
731 | + |
|
732 | + /** |
|
733 | + * Send an update of the task if requested, and send the Status-On-Completion report if complete and requested. |
|
734 | + * |
|
735 | + * If no updates were requested from the organizer, this function does nothing. |
|
736 | + * |
|
737 | + * @return bool TRUE if the update succeeded, FALSE otherwise |
|
738 | + */ |
|
739 | + public function doUpdate() { |
|
740 | + $messageProps = mapi_getprops($this->message, [$this->props['taskstate'], PR_SUBJECT]); |
|
741 | + |
|
742 | + if (!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
|
743 | + return false; // Can only update assignee task |
|
744 | + } |
|
745 | + |
|
746 | + $this->setLastUser(); |
|
747 | + $this->updateTaskRequest(); |
|
748 | + |
|
749 | + // Set as updated |
|
750 | + mapi_setprops($this->message, [$this->props['taskhistory'] => thUpdated]); |
|
751 | + |
|
752 | + mapi_savechanges($this->message); |
|
753 | + |
|
754 | + $props = mapi_getprops($this->message, [$this->props['taskupdates'], $this->props['tasksoc'], $this->props['recurring'], $this->props['complete']]); |
|
755 | + if (!$props[$this->props['complete']] && $props[$this->props['taskupdates']] && !(isset($props[$this->props['recurring']]) && $props[$this->props['recurring']])) { |
|
756 | + $this->sendResponse(tdmtTaskUpd, _("Task Updated:") . " "); |
|
757 | + } |
|
758 | + elseif ($props[$this->props['complete']]) { |
|
759 | + $this->sendResponse(tdmtTaskUpd, _("Task Completed:") . " "); |
|
760 | + } |
|
761 | + |
|
762 | + return true; |
|
763 | + } |
|
764 | + |
|
765 | + /** |
|
766 | + * Get the store associated with the task. |
|
767 | + * |
|
768 | + * Normally this will just open the store that the processed message is in. However, if the message is opened |
|
769 | + * by a delegate, this function opens the store that the message was delegated from. |
|
770 | + */ |
|
771 | + public function getTaskFolderStore() { |
|
772 | + $ownerentryid = false; |
|
773 | + |
|
774 | + $rcvdprops = mapi_getprops($this->message, [PR_RCVD_REPRESENTING_ENTRYID]); |
|
775 | + if (isset($rcvdprops[PR_RCVD_REPRESENTING_ENTRYID])) { |
|
776 | + $ownerentryid = $rcvdprops; |
|
777 | + } |
|
778 | + |
|
779 | + if (!$ownerentryid) { |
|
780 | + $store = $this->store; |
|
781 | + } |
|
782 | + else { |
|
783 | + $ab = mapi_openaddressbook($this->session); |
|
784 | + if (!$ab) { |
|
785 | + return false; |
|
786 | + } |
|
787 | + |
|
788 | + $mailuser = mapi_ab_openentry($ab, $ownerentryid); |
|
789 | + if (!$mailuser) { |
|
790 | + return false; |
|
791 | + } |
|
792 | + |
|
793 | + $mailuserprops = mapi_getprops($mailuser, [PR_EMAIL_ADDRESS]); |
|
794 | + if (!isset($mailuserprops[PR_EMAIL_ADDRESS])) { |
|
795 | + return false; |
|
796 | + } |
|
797 | + |
|
798 | + $storeid = mapi_msgstore_createentryid($this->store, $mailuserprops[PR_EMAIL_ADDRESS]); |
|
799 | + |
|
800 | + $store = mapi_openmsgstore($this->session, $storeid); |
|
801 | + } |
|
802 | + |
|
803 | + return $store; |
|
804 | + } |
|
805 | + |
|
806 | + /** |
|
807 | + * Open the default task folder for the current user, or the specified user if passed. |
|
808 | + */ |
|
809 | + public function getDefaultTasksFolder() { |
|
810 | + $store = $this->getTaskFolderStore(); |
|
811 | + |
|
812 | + $inbox = mapi_msgstore_getreceivefolder($store); |
|
813 | + $inboxprops = mapi_getprops($inbox, [PR_IPM_TASK_ENTRYID]); |
|
814 | + if (!isset($inboxprops[PR_IPM_TASK_ENTRYID])) { |
|
815 | + return false; |
|
816 | + } |
|
817 | + |
|
818 | + return mapi_msgstore_openentry($store, $inboxprops[PR_IPM_TASK_ENTRYID]); |
|
819 | + } |
|
820 | + |
|
821 | + /** |
|
822 | + * Function prepare the sent representing properties from given MAPI store. |
|
823 | + * |
|
824 | + * @param $store MAPI store object |
|
825 | + * |
|
826 | + * @return array|bool if store is not mail box owner entryid then |
|
827 | + * return false else prepare the sent representing props and return it |
|
828 | + */ |
|
829 | + public function getSentReprProps($store) { |
|
830 | + $storeprops = mapi_getprops($store, [PR_MAILBOX_OWNER_ENTRYID]); |
|
831 | + if (!isset($storeprops[PR_MAILBOX_OWNER_ENTRYID])) { |
|
832 | + return false; |
|
833 | + } |
|
834 | + |
|
835 | + $ab = mapi_openaddressbook($this->session); |
|
836 | + $mailuser = mapi_ab_openentry($ab, $storeprops[PR_MAILBOX_OWNER_ENTRYID]); |
|
837 | + $mailuserprops = mapi_getprops($mailuser, [PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_DISPLAY_NAME, PR_SEARCH_KEY, PR_ENTRYID]); |
|
838 | + |
|
839 | + $props = []; |
|
840 | + $props[PR_SENT_REPRESENTING_ADDRTYPE] = $mailuserprops[PR_ADDRTYPE]; |
|
841 | + $props[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $mailuserprops[PR_EMAIL_ADDRESS]; |
|
842 | + $props[PR_SENT_REPRESENTING_NAME] = $mailuserprops[PR_DISPLAY_NAME]; |
|
843 | + $props[PR_SENT_REPRESENTING_SEARCH_KEY] = $mailuserprops[PR_SEARCH_KEY]; |
|
844 | + $props[PR_SENT_REPRESENTING_ENTRYID] = $mailuserprops[PR_ENTRYID]; |
|
845 | + |
|
846 | + return $props; |
|
847 | + } |
|
848 | + |
|
849 | + /** |
|
850 | + * Creates an outgoing message based on the passed message - will set delegate information |
|
851 | + * and sent mail folder. |
|
852 | + */ |
|
853 | + public function createOutgoingMessage() { |
|
854 | + // Open our default store for this user (that's the only store we can submit in) |
|
855 | + $store = $this->getDefaultStore(); |
|
856 | + $storeprops = mapi_getprops($store, [PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID]); |
|
857 | + |
|
858 | + $outbox = mapi_msgstore_openentry($store, $storeprops[PR_IPM_OUTBOX_ENTRYID]); |
|
859 | + if (!$outbox) { |
|
860 | + return false; |
|
861 | + } |
|
862 | + |
|
863 | + $outgoing = mapi_folder_createmessage($outbox); |
|
864 | + if (!$outgoing) { |
|
865 | + return false; |
|
866 | + } |
|
867 | + |
|
868 | + // Set SENT_REPRESENTING in case we're sending as a delegate |
|
869 | + $ownerstore = $this->getTaskFolderStore(); |
|
870 | + $sentreprprops = $this->getSentReprProps($ownerstore); |
|
871 | + mapi_setprops($outgoing, $sentreprprops); |
|
872 | + |
|
873 | + mapi_setprops($outgoing, [PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID]]); |
|
874 | + |
|
875 | + return $outgoing; |
|
876 | + } |
|
877 | + |
|
878 | + /** |
|
879 | + * Send a response message (from assignee back to organizer). |
|
880 | + * |
|
881 | + * @param $type int Type of response (tdmtTaskAcc, tdmtTaskDec, tdmtTaskUpd); |
|
882 | + * @param mixed $prefix |
|
883 | + * |
|
884 | + * @return bool TRUE on success |
|
885 | + */ |
|
886 | + public function sendResponse($type, $prefix) { |
|
887 | + // Create a message in our outbox |
|
888 | + $outgoing = $this->createOutgoingMessage(); |
|
889 | + $messageprops = mapi_getprops($this->message, [PR_CONVERSATION_TOPIC, PR_MESSAGE_CLASS, $this->props['complete']]); |
|
890 | + |
|
891 | + $attach = mapi_message_createattach($outgoing); |
|
892 | + mapi_setprops($attach, [PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG, PR_DISPLAY_NAME => $messageprops[PR_CONVERSATION_TOPIC], PR_ATTACHMENT_HIDDEN => true]); |
|
893 | + $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_CREATE | MAPI_MODIFY); |
|
894 | + |
|
895 | + $message = !$this->isTaskRequest() ? $this->message : $this->getAssociatedTask(false); |
|
896 | + |
|
897 | + $ignoreProps = [PR_ICON_INDEX, $this->props["categories"], PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_SEARCH_KEY]; |
|
898 | + |
|
899 | + mapi_copyto($message, [], $ignoreProps, $outgoing); |
|
900 | + mapi_copyto($message, [], [], $sub); |
|
901 | + |
|
902 | + if (!$this->setRecipientsForResponse($outgoing, $type)) { |
|
903 | + return false; |
|
904 | + } |
|
905 | + |
|
906 | + $props = []; |
|
907 | + |
|
908 | + switch ($type) { |
|
909 | + case tdmtTaskAcc: |
|
910 | + $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Accept"; |
|
911 | + mapi_setprops($sub, [PR_ICON_INDEX => ICON_TASK_ASSIGNER]); |
|
912 | + |
|
913 | + break; |
|
914 | + |
|
915 | + case tdmtTaskDec: |
|
916 | + $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Decline"; |
|
917 | + mapi_setprops($sub, [PR_ICON_INDEX => ICON_TASK_DECLINE]); |
|
918 | + |
|
919 | + break; |
|
920 | + |
|
921 | + case tdmtTaskUpd: |
|
922 | + mapi_setprops($sub, [PR_ICON_INDEX => ICON_TASK_ASSIGNER]); |
|
923 | + if ($messageprops[$this->props['complete']]) { |
|
924 | + $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Complete"; |
|
925 | + } |
|
926 | + else { |
|
927 | + $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Update"; |
|
928 | + } |
|
929 | + |
|
930 | + break; |
|
931 | + } |
|
932 | + |
|
933 | + mapi_savechanges($sub); |
|
934 | + mapi_savechanges($attach); |
|
935 | + |
|
936 | + $props[PR_SUBJECT] = $prefix . $messageprops[PR_CONVERSATION_TOPIC]; |
|
937 | + $props[$this->props['taskmode']] = $type; |
|
938 | + $props[$this->props['task_assigned_time']] = time(); |
|
939 | + |
|
940 | + mapi_setprops($outgoing, $props); |
|
941 | + |
|
942 | + // taskCommentsInfo contains some comments which added by assignee while |
|
943 | + // edit response before sending task response. |
|
944 | + if ($this->taskCommentsInfo) { |
|
945 | + $comments = $this->getTaskCommentsInfo(); |
|
946 | + $stream = mapi_openproperty($outgoing, PR_BODY, IID_IStream, STGM_TRANSACTED, MAPI_CREATE | MAPI_MODIFY); |
|
947 | + mapi_stream_setsize($stream, strlen($comments)); |
|
948 | + mapi_stream_write($stream, $comments); |
|
949 | + mapi_stream_commit($stream); |
|
950 | + } |
|
951 | + |
|
952 | + mapi_savechanges($outgoing); |
|
953 | + mapi_message_submitmessage($outgoing); |
|
954 | + |
|
955 | + return true; |
|
956 | + } |
|
957 | + |
|
958 | + public function getDefaultStore() { |
|
959 | + $table = mapi_getmsgstorestable($this->session); |
|
960 | + $rows = mapi_table_queryallrows($table, [PR_DEFAULT_STORE, PR_ENTRYID]); |
|
961 | + |
|
962 | + foreach ($rows as $row) { |
|
963 | + if ($row[PR_DEFAULT_STORE]) { |
|
964 | + return mapi_openmsgstore($this->session, $row[PR_ENTRYID]); |
|
965 | + } |
|
966 | + } |
|
967 | + |
|
968 | + return false; |
|
969 | + } |
|
970 | + |
|
971 | + /** |
|
972 | + * Creates a new TaskGlobalObjId. |
|
973 | + * |
|
974 | + * Just 16 bytes of random data |
|
975 | + */ |
|
976 | + public function createTGOID() { |
|
977 | + $goid = ""; |
|
978 | + for ($i = 0; $i < 16; ++$i) { |
|
979 | + $goid .= chr(rand(0, 255)); |
|
980 | + } |
|
981 | + |
|
982 | + return $goid; |
|
983 | + } |
|
984 | + |
|
985 | + /** |
|
986 | + * Function used to get the embedded task of task request. Which further used to |
|
987 | + * Create/Update associated task of assigner/assignee. |
|
988 | + * |
|
989 | + * @param object $message which contains embedded task |
|
990 | + * |
|
991 | + * @return false|object $task if found embedded task else false |
|
992 | + */ |
|
993 | + public function getEmbeddedTask($message) { |
|
994 | + $task = false; |
|
995 | + $goid = mapi_getprops($message, [$this->props["task_goid"]]); |
|
996 | + $attachmentTable = mapi_message_getattachmenttable($message); |
|
997 | + $restriction = [ |
|
998 | + RES_PROPERTY, |
|
999 | + [ |
|
1000 | + RELOP => RELOP_EQ, |
|
1001 | + ULPROPTAG => PR_ATTACH_METHOD, |
|
1002 | + VALUE => ATTACH_EMBEDDED_MSG, ], |
|
1003 | + ]; |
|
1004 | + $rows = mapi_table_queryallrows($attachmentTable, [PR_ATTACH_NUM], $restriction); |
|
1005 | + |
|
1006 | + if (empty($rows)) { |
|
1007 | + return $task; |
|
1008 | + } |
|
1009 | + |
|
1010 | + foreach ($rows as $row) { |
|
1011 | + try { |
|
1012 | + $attach = mapi_message_openattach($message, $row[PR_ATTACH_NUM]); |
|
1013 | + $task = mapi_attach_openobj($attach); |
|
1014 | + } |
|
1015 | + catch (MAPIException $e) { |
|
1016 | + continue; |
|
1017 | + } |
|
1018 | + |
|
1019 | + $taskGoid = mapi_getprops($task, [$this->props["task_goid"]]); |
|
1020 | + if ($goid[$this->props["task_goid"]] === $taskGoid[$this->props["task_goid"]]) { |
|
1021 | + mapi_setprops($attach, [PR_ATTACHMENT_HIDDEN => true]); |
|
1022 | + mapi_savechanges($attach); |
|
1023 | + mapi_savechanges($message); |
|
1024 | + |
|
1025 | + break; |
|
1026 | + } |
|
1027 | + } |
|
1028 | + |
|
1029 | + return $task; |
|
1030 | + } |
|
1031 | + |
|
1032 | + /** |
|
1033 | + * Function was used to set the user name who has last used this task also it was |
|
1034 | + * update the tasklastdelegate and task_assigned_time. |
|
1035 | + */ |
|
1036 | + public function setLastUser() { |
|
1037 | + $delegatestore = $this->getDefaultStore(); |
|
1038 | + $taskstore = $this->getTaskFolderStore(); |
|
1039 | + |
|
1040 | + $delegateprops = mapi_getprops($delegatestore, [PR_MAILBOX_OWNER_NAME]); |
|
1041 | + $taskprops = mapi_getprops($taskstore, [PR_MAILBOX_OWNER_NAME]); |
|
1042 | + |
|
1043 | + // The owner of the task |
|
1044 | + $username = $delegateprops[PR_MAILBOX_OWNER_NAME]; |
|
1045 | + // This is me (the one calling the script) |
|
1046 | + $delegate = $taskprops[PR_MAILBOX_OWNER_NAME]; |
|
1047 | + |
|
1048 | + if ($this->isTaskRequest()) { |
|
1049 | + $task = $this->getAssociatedTask(false); |
|
1050 | + mapi_setprops($task, [$this->props["tasklastuser"] => $username, $this->props["tasklastdelegate"] => $delegate, $this->props['task_assigned_time'] => time()]); |
|
1051 | + mapi_savechanges($task); |
|
1052 | + } |
|
1053 | + mapi_setprops($this->message, [$this->props["tasklastuser"] => $username, $this->props["tasklastdelegate"] => $delegate, $this->props['task_assigned_time'] => time()]); |
|
1054 | + } |
|
1055 | + |
|
1056 | + /** |
|
1057 | + * Assignee becomes the owner when a user/assignor assigns any task to someone. Also there can be more than one assignee. |
|
1058 | + * This function sets assignee as owner in the assignor's copy of task. |
|
1059 | + */ |
|
1060 | + public function setOwnerForAssignor() { |
|
1061 | + $recipTable = mapi_message_getrecipienttable($this->message); |
|
1062 | + $recips = mapi_table_queryallrows($recipTable, [PR_DISPLAY_NAME]); |
|
1063 | + |
|
1064 | + if (!empty($recips)) { |
|
1065 | + $owner = []; |
|
1066 | + foreach ($recips as $value) { |
|
1067 | + $owner[] = $value[PR_DISPLAY_NAME]; |
|
1068 | + } |
|
1069 | + |
|
1070 | + $props = [$this->props['owner'] => implode("; ", $owner)]; |
|
1071 | + mapi_setprops($this->message, $props); |
|
1072 | + } |
|
1073 | + } |
|
1074 | + |
|
1075 | + /** |
|
1076 | + * Sets assignor as recipients in assignee's copy of task. |
|
1077 | + * |
|
1078 | + * If assignor has requested task updates then the assignor is added as recipient type MAPI_CC. |
|
1079 | + * |
|
1080 | + * Also if assignor has request SOC then the assignor is also add as recipient type MAPI_BCC |
|
1081 | + * |
|
1082 | + * @param $task message MAPI message which assignee's copy of task |
|
1083 | + */ |
|
1084 | + public function setAssignorInRecipients($task) { |
|
1085 | + $recipTable = mapi_message_getrecipienttable($task); |
|
1086 | + |
|
1087 | + // Delete all MAPI_TO recipients |
|
1088 | + $recips = mapi_table_queryallrows($recipTable, [PR_ROWID], [ |
|
1089 | + RES_PROPERTY, |
|
1090 | + [ |
|
1091 | + RELOP => RELOP_EQ, |
|
1092 | + ULPROPTAG => PR_RECIPIENT_TYPE, |
|
1093 | + VALUE => MAPI_TO, |
|
1094 | + ], ]); |
|
1095 | + foreach ($recips as $recip) { |
|
1096 | + mapi_message_modifyrecipients($task, MODRECIP_REMOVE, [$recip]); |
|
1097 | + } |
|
1098 | + |
|
1099 | + $recips = []; |
|
1100 | + $taskReqProps = mapi_getprops($this->message, [PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_SEARCH_KEY]); |
|
1101 | + $associatedTaskProps = mapi_getprops($task, [$this->props['taskupdates'], $this->props['tasksoc'], $this->props['taskmultrecips']]); |
|
1102 | + |
|
1103 | + // Build assignor info |
|
1104 | + $assignor = [ |
|
1105 | + PR_ENTRYID => $taskReqProps[PR_SENT_REPRESENTING_ENTRYID], |
|
1106 | + PR_DISPLAY_NAME => $taskReqProps[PR_SENT_REPRESENTING_NAME], |
|
1107 | + PR_EMAIL_ADDRESS => $taskReqProps[PR_SENT_REPRESENTING_EMAIL_ADDRESS], |
|
1108 | + PR_RECIPIENT_DISPLAY_NAME => $taskReqProps[PR_SENT_REPRESENTING_NAME], |
|
1109 | + PR_ADDRTYPE => empty($taskReqProps[PR_SENT_REPRESENTING_ADDRTYPE]) ? 'SMTP' : $taskReqProps[PR_SENT_REPRESENTING_ADDRTYPE], |
|
1110 | + PR_RECIPIENT_FLAGS => recipSendable, |
|
1111 | + PR_SEARCH_KEY => $taskReqProps[PR_SENT_REPRESENTING_SEARCH_KEY], |
|
1112 | + ]; |
|
1113 | + |
|
1114 | + // Assignor has requested task updates, so set him/her as MAPI_CC in recipienttable. |
|
1115 | + if ((isset($associatedTaskProps[$this->props['taskupdates']]) && $associatedTaskProps[$this->props['taskupdates']]) && |
|
1116 | + !(isset($associatedTaskProps[$this->props['taskmultrecips']]) && $associatedTaskProps[$this->props['taskmultrecips']] == tmrReceived)) { |
|
1117 | + $assignor[PR_RECIPIENT_TYPE] = MAPI_CC; |
|
1118 | + $recips[] = $assignor; |
|
1119 | + } |
|
1120 | + |
|
1121 | + // Assignor wants to receive an email report when task is mark as 'Complete', so in recipients as MAPI_BCC |
|
1122 | + if ($associatedTaskProps[$this->props['tasksoc']]) { |
|
1123 | + $assignor[PR_RECIPIENT_TYPE] = MAPI_BCC; |
|
1124 | + $recips[] = $assignor; |
|
1125 | + } |
|
1126 | + |
|
1127 | + if (!empty($recips)) { |
|
1128 | + mapi_message_modifyrecipients($task, MODRECIP_ADD, $recips); |
|
1129 | + } |
|
1130 | + } |
|
1131 | + |
|
1132 | + /** |
|
1133 | + * Deletes incoming task request from Inbox. |
|
1134 | + * |
|
1135 | + * @returns array returns PR_ENTRYID, PR_STORE_ENTRYID and PR_PARENT_ENTRYID of the deleted task request |
|
1136 | + */ |
|
1137 | + public function deleteReceivedTR() { |
|
1138 | + $store = $this->getTaskFolderStore(); |
|
1139 | + $storeType = mapi_getprops($store, [PR_MDB_PROVIDER]); |
|
1140 | + if ($storeType[PR_MDB_PROVIDER] === ZARAFA_STORE_PUBLIC_GUID) { |
|
1141 | + $store = $this->getDefaultStore(); |
|
1142 | + } |
|
1143 | + $inbox = mapi_msgstore_getreceivefolder($store); |
|
1144 | + |
|
1145 | + $storeProps = mapi_getprops($store, [PR_IPM_WASTEBASKET_ENTRYID]); |
|
1146 | + $props = mapi_getprops($this->message, [$this->props['task_goid']]); |
|
1147 | + $goid = $props[$this->props['task_goid']]; |
|
1148 | + |
|
1149 | + // Find the task by looking for the task_goid |
|
1150 | + $restriction = [ |
|
1151 | + RES_PROPERTY, |
|
1152 | + [ |
|
1153 | + RELOP => RELOP_EQ, |
|
1154 | + ULPROPTAG => $this->props['task_goid'], |
|
1155 | + VALUE => $goid, ], |
|
1156 | + ]; |
|
1157 | + |
|
1158 | + $contents = mapi_folder_getcontentstable($inbox); |
|
1159 | + |
|
1160 | + $rows = mapi_table_queryallrows($contents, [PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID], $restriction); |
|
1161 | + |
|
1162 | + if (!empty($rows)) { |
|
1163 | + // If there are multiple, just use the first |
|
1164 | + $entryid = $rows[0][PR_ENTRYID]; |
|
1165 | + $wastebasket = mapi_msgstore_openentry($store, $storeProps[PR_IPM_WASTEBASKET_ENTRYID]); |
|
1166 | + mapi_folder_copymessages($inbox, [$entryid], $wastebasket, MESSAGE_MOVE); |
|
1167 | + |
|
1168 | + return [PR_ENTRYID => $entryid, PR_PARENT_ENTRYID => $rows[0][PR_PARENT_ENTRYID], PR_STORE_ENTRYID => $rows[0][PR_STORE_ENTRYID]]; |
|
1169 | + } |
|
1170 | + |
|
1171 | + return false; |
|
1172 | + } |
|
1173 | + |
|
1174 | + /** |
|
1175 | + * Sets recipients for the outgoing message according to type of the response. |
|
1176 | + * |
|
1177 | + * If it is a task update, then only recipient type MAPI_CC are taken from the task message. |
|
1178 | + * |
|
1179 | + * If it is accept/decline response, then PR_SENT_REPRESENTATING_XXXX are taken as recipient. |
|
1180 | + * |
|
1181 | + *@param $outgoing MAPI_message outgoing mapi message |
|
1182 | + *@param $responseType String response type |
|
1183 | + */ |
|
1184 | + public function setRecipientsForResponse($outgoing, $responseType) { |
|
1185 | + // Clear recipients from outgoing msg |
|
1186 | + $this->deleteAllRecipients($outgoing); |
|
1187 | + |
|
1188 | + // If it is a task update then get MAPI_CC recipients which are assignors who has asked for task update. |
|
1189 | + if ($responseType == tdmtTaskUpd) { |
|
1190 | + $props = mapi_getprops($this->message, [$this->props['complete']]); |
|
1191 | + $isComplete = $props[$this->props['complete']]; |
|
1192 | + |
|
1193 | + $recipTable = mapi_message_getrecipienttable($this->message); |
|
1194 | + $recips = mapi_table_queryallrows($recipTable, $this->recipProps, [ |
|
1195 | + RES_PROPERTY, |
|
1196 | + [ |
|
1197 | + RELOP => RELOP_EQ, |
|
1198 | + ULPROPTAG => PR_RECIPIENT_TYPE, |
|
1199 | + VALUE => ($isComplete ? MAPI_BCC : MAPI_CC), |
|
1200 | + ], |
|
1201 | + ]); |
|
1202 | + |
|
1203 | + // No recipients found, return error |
|
1204 | + if (empty($recips)) { |
|
1205 | + return false; |
|
1206 | + } |
|
1207 | + |
|
1208 | + foreach ($recips as $recip) { |
|
1209 | + $recip[PR_RECIPIENT_TYPE] = MAPI_TO; // Change recipient type to MAPI_TO |
|
1210 | + mapi_message_modifyrecipients($outgoing, MODRECIP_ADD, [$recip]); |
|
1211 | + } |
|
1212 | + |
|
1213 | + return true; |
|
1214 | + } |
|
1215 | + |
|
1216 | + $orgprops = mapi_getprops($this->message, [PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_ENTRYID, PR_SUBJECT]); |
|
1217 | + $recip = [ |
|
1218 | + PR_DISPLAY_NAME => $orgprops[PR_SENT_REPRESENTING_NAME], |
|
1219 | + PR_EMAIL_ADDRESS => $orgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS], |
|
1220 | + PR_ADDRTYPE => $orgprops[PR_SENT_REPRESENTING_ADDRTYPE], |
|
1221 | + PR_ENTRYID => $orgprops[PR_SENT_REPRESENTING_ENTRYID], |
|
1222 | + PR_RECIPIENT_TYPE => MAPI_TO, ]; |
|
1223 | + |
|
1224 | + mapi_message_modifyrecipients($outgoing, MODRECIP_ADD, [$recip]); |
|
1225 | + |
|
1226 | + return true; |
|
1227 | + } |
|
1228 | + |
|
1229 | + /** |
|
1230 | + * Deletes all recipients from given message object. |
|
1231 | + * |
|
1232 | + * @param $message MAPI message from which recipients are to be removed |
|
1233 | + */ |
|
1234 | + public function deleteAllRecipients($message) { |
|
1235 | + $recipTable = mapi_message_getrecipienttable($message); |
|
1236 | + $recipRows = mapi_table_queryallrows($recipTable, [PR_ROWID]); |
|
1237 | + |
|
1238 | + foreach ($recipRows as $recipient) { |
|
1239 | + mapi_message_modifyrecipients($message, MODRECIP_REMOVE, [$recipient]); |
|
1240 | + } |
|
1241 | + } |
|
1242 | + |
|
1243 | + /** |
|
1244 | + * Function used to mark the record to complete and send complete update |
|
1245 | + * notification to assigner. |
|
1246 | + * |
|
1247 | + * @return bool TRUE if the update succeeded, FALSE otherwise |
|
1248 | + */ |
|
1249 | + public function sendCompleteUpdate() { |
|
1250 | + $messageprops = mapi_getprops($this->message, [$this->props['taskstate']]); |
|
1251 | + |
|
1252 | + if (!isset($messageprops[$this->props['taskstate']]) || $messageprops[$this->props['taskstate']] != tdsOWN) { |
|
1253 | + return false; // Can only decline assignee task |
|
1254 | + } |
|
1255 | + |
|
1256 | + mapi_setprops( |
|
1257 | + $this->message, |
|
1258 | + [ |
|
1259 | + $this->props['complete'] => true, |
|
1260 | + $this->props['datecompleted'] => time(), |
|
1261 | + $this->props['status'] => 2, |
|
1262 | + $this->props['percent_complete'] => 1, ] |
|
1263 | + ); |
|
1264 | + |
|
1265 | + return $this->doUpdate(); |
|
1266 | + } |
|
1267 | + |
|
1268 | + /** |
|
1269 | + * Function returns extra info about task request comments along with message body |
|
1270 | + * which will be included in body while sending task request/response. |
|
1271 | + * |
|
1272 | + * @return string info about task request comments along with message body |
|
1273 | + */ |
|
1274 | + public function getTaskCommentsInfo() { |
|
1275 | + return $this->taskCommentsInfo; |
|
1276 | + } |
|
1277 | + |
|
1278 | + /** |
|
1279 | + * Function sets extra info about task request comments along with message body |
|
1280 | + * which will be included in body while sending task request/response. |
|
1281 | + * |
|
1282 | + * @param string $taskCommentsInfo info about task request comments along with message body |
|
1283 | + */ |
|
1284 | + public function setTaskCommentsInfo($taskCommentsInfo) { |
|
1285 | + $this->taskCommentsInfo = $taskCommentsInfo; |
|
1286 | + } |
|
1287 | + } |
@@ -23,12 +23,12 @@ discard block |
||
23 | 23 | * carried in the IPM.TaskRequest item (although this information seems |
24 | 24 | * redundant due to that information already being available in PR_MESSAGE_CLASS). |
25 | 25 | */ |
26 | - define('tdmtNothing', 0); // Value in IPM.Task items |
|
27 | - define('tdmtTaskReq', 1); // Assigner -> Assignee |
|
28 | - define('tdmtTaskAcc', 2); // Assignee -> Assigner |
|
29 | - define('tdmtTaskDec', 3); // Assignee -> Assigner |
|
30 | - define('tdmtTaskUpd', 4); // Assignee -> Assigner |
|
31 | - define('tdmtTaskSELF', 5); // Assigner -> Assigner (?) |
|
26 | + define('tdmtNothing', 0); // Value in IPM.Task items |
|
27 | + define('tdmtTaskReq', 1); // Assigner -> Assignee |
|
28 | + define('tdmtTaskAcc', 2); // Assignee -> Assigner |
|
29 | + define('tdmtTaskDec', 3); // Assignee -> Assigner |
|
30 | + define('tdmtTaskUpd', 4); // Assignee -> Assigner |
|
31 | + define('tdmtTaskSELF', 5); // Assigner -> Assigner (?) |
|
32 | 32 | |
33 | 33 | /* The TaskHistory is used to show the last action on the task |
34 | 34 | * on both the assigner and the assignee's side. |
@@ -38,22 +38,22 @@ discard block |
||
38 | 38 | * the format 'Accepted by <user> on 01-01-2010 11:00'. |
39 | 39 | */ |
40 | 40 | define('thNone', 0); |
41 | - define('thAccepted', 1); // Set by assignee |
|
42 | - define('thDeclined', 2); // Set by assignee |
|
43 | - define('thUpdated', 3); // Set by assignee |
|
41 | + define('thAccepted', 1); // Set by assignee |
|
42 | + define('thDeclined', 2); // Set by assignee |
|
43 | + define('thUpdated', 3); // Set by assignee |
|
44 | 44 | define('thDueDateChanged', 4); |
45 | - define('thAssigned', 5); // Set by assigner |
|
45 | + define('thAssigned', 5); // Set by assigner |
|
46 | 46 | |
47 | 47 | /* The TaskState value is used to differentiate the version of a task |
48 | 48 | * in the assigner's folder and the version in the |
49 | 49 | * assignee's folder. The buttons shown depend on this and |
50 | 50 | * the 'taskaccepted' boolean (for the assignee) |
51 | 51 | */ |
52 | - define('tdsNOM', 0); // Got a response to a deleted task, and re-created the task for the assigner |
|
53 | - define('tdsOWNNEW', 1); // Not assigned |
|
54 | - define('tdsOWN', 2); // Assignee version |
|
55 | - define('tdsACC', 3); // Assigner version |
|
56 | - define('tdsDEC', 4); // Assigner version, but assignee declined |
|
52 | + define('tdsNOM', 0); // Got a response to a deleted task, and re-created the task for the assigner |
|
53 | + define('tdsOWNNEW', 1); // Not assigned |
|
54 | + define('tdsOWN', 2); // Assignee version |
|
55 | + define('tdsACC', 3); // Assigner version |
|
56 | + define('tdsDEC', 4); // Assigner version, but assignee declined |
|
57 | 57 | |
58 | 58 | /* The TaskAcceptanceState is used for the assigner to indicate state */ |
59 | 59 | define('olTaskNotDelegated', 0); |
@@ -63,13 +63,13 @@ discard block |
||
63 | 63 | |
64 | 64 | /* The task ownership indicates the role of the current user relative to the task. */ |
65 | 65 | define('olNewTask', 0); |
66 | - define('olDelegatedTask', 1); // Task has been assigned |
|
67 | - define('olOwnTask', 2); // Task owned |
|
66 | + define('olDelegatedTask', 1); // Task has been assigned |
|
67 | + define('olOwnTask', 2); // Task owned |
|
68 | 68 | |
69 | 69 | /* taskmultrecips indicates whether the task request sent or received has multiple assignees or not. */ |
70 | 70 | define('tmrNone', 0); |
71 | - define('tmrSent', 1); // Task has been sent to multiple assignee |
|
72 | - define('tmrReceived', 2); // Task Request received has multiple assignee |
|
71 | + define('tmrSent', 1); // Task has been sent to multiple assignee |
|
72 | + define('tmrReceived', 2); // Task Request received has multiple assignee |
|
73 | 73 | |
74 | 74 | // Task icon index. |
75 | 75 | define('ICON_TASK_ASSIGNEE', 0x00000502); |
@@ -307,7 +307,7 @@ discard block |
||
307 | 307 | VALUE => $goid, ], |
308 | 308 | ]; |
309 | 309 | |
310 | - $table = mapi_folder_getcontentstable($folder, MAPI_DEFERRED_ERRORS | SHOW_SOFT_DELETES); |
|
310 | + $table = mapi_folder_getcontentstable($folder, MAPI_DEFERRED_ERRORS|SHOW_SOFT_DELETES); |
|
311 | 311 | $softDeletedItems = mapi_table_queryallrows($table, [PR_ENTRYID], $restriction); |
312 | 312 | if (!empty($softDeletedItems)) { |
313 | 313 | return true; |
@@ -515,14 +515,14 @@ discard block |
||
515 | 515 | // Set properties on Task Request |
516 | 516 | mapi_setprops($this->message, [ |
517 | 517 | $this->props['task_goid'] => $taskid, /* our new task_goid */ |
518 | - $this->props['taskstate'] => tdsACC, /* state for our outgoing request */ |
|
519 | - $this->props['taskmode'] => tdmtNothing, /* we're not sending a change */ |
|
520 | - $this->props['updatecount'] => 2, /* version 2 (no idea) */ |
|
518 | + $this->props['taskstate'] => tdsACC, /* state for our outgoing request */ |
|
519 | + $this->props['taskmode'] => tdmtNothing, /* we're not sending a change */ |
|
520 | + $this->props['updatecount'] => 2, /* version 2 (no idea) */ |
|
521 | 521 | $this->props['task_acceptance_state'] => olTaskDelegationUnknown, /* no reply yet */ |
522 | 522 | $this->props['ownership'] => olDelegatedTask, /* Task has been assigned */ |
523 | - $this->props['taskhistory'] => thAssigned, /* Task has been assigned */ |
|
523 | + $this->props['taskhistory'] => thAssigned, /* Task has been assigned */ |
|
524 | 524 | PR_CONVERSATION_TOPIC => $messageprops[PR_SUBJECT], |
525 | - PR_ICON_INDEX => ICON_TASK_ASSIGNER, /* Task request icon */ |
|
525 | + PR_ICON_INDEX => ICON_TASK_ASSIGNER, /* Task request icon */ |
|
526 | 526 | ]); |
527 | 527 | $this->setLastUser(); |
528 | 528 | $this->setOwnerForAssignor(); |
@@ -537,12 +537,12 @@ discard block |
||
537 | 537 | |
538 | 538 | // Make it a task request, and put it in sent items after it is sent |
539 | 539 | mapi_setprops($outgoing, [ |
540 | - PR_MESSAGE_CLASS => "IPM.TaskRequest", /* class is task request */ |
|
541 | - $this->props['taskstate'] => tdsOWN, /* for the recipient he is the task owner */ |
|
542 | - $this->props['taskmode'] => tdmtTaskReq, /* for the recipient it's a request */ |
|
543 | - $this->props['updatecount'] => 1, /* version 2 is in the attachment */ |
|
540 | + PR_MESSAGE_CLASS => "IPM.TaskRequest", /* class is task request */ |
|
541 | + $this->props['taskstate'] => tdsOWN, /* for the recipient he is the task owner */ |
|
542 | + $this->props['taskmode'] => tdmtTaskReq, /* for the recipient it's a request */ |
|
543 | + $this->props['updatecount'] => 1, /* version 2 is in the attachment */ |
|
544 | 544 | PR_SUBJECT_PREFIX => $prefix, |
545 | - PR_SUBJECT => $prefix . $messageprops[PR_SUBJECT], |
|
545 | + PR_SUBJECT => $prefix.$messageprops[PR_SUBJECT], |
|
546 | 546 | ]); |
547 | 547 | |
548 | 548 | $attach = mapi_message_createattach($outgoing); |
@@ -551,7 +551,7 @@ discard block |
||
551 | 551 | PR_ATTACHMENT_HIDDEN => true, |
552 | 552 | PR_DISPLAY_NAME => $messageprops[PR_SUBJECT], ]); |
553 | 553 | |
554 | - $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_MODIFY | MAPI_CREATE); |
|
554 | + $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_MODIFY|MAPI_CREATE); |
|
555 | 555 | |
556 | 556 | mapi_copyto($this->message, [], [], $sub); |
557 | 557 | mapi_savechanges($sub); |
@@ -649,7 +649,7 @@ discard block |
||
649 | 649 | * @return entryid EntryID of the accepted task |
650 | 650 | */ |
651 | 651 | public function doAccept() { |
652 | - $prefix = _("Task Accepted:") . " "; |
|
652 | + $prefix = _("Task Accepted:")." "; |
|
653 | 653 | $messageProps = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->props['taskstate']]); |
654 | 654 | |
655 | 655 | if (!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
@@ -698,7 +698,7 @@ discard block |
||
698 | 698 | * @return boolean TRUE on success, FALSE on failure |
699 | 699 | */ |
700 | 700 | public function doDecline() { |
701 | - $prefix = _("Task Declined:") . " "; |
|
701 | + $prefix = _("Task Declined:")." "; |
|
702 | 702 | $messageProps = mapi_getprops($this->message, [$this->props['taskstate']]); |
703 | 703 | |
704 | 704 | if (!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
@@ -753,10 +753,10 @@ discard block |
||
753 | 753 | |
754 | 754 | $props = mapi_getprops($this->message, [$this->props['taskupdates'], $this->props['tasksoc'], $this->props['recurring'], $this->props['complete']]); |
755 | 755 | if (!$props[$this->props['complete']] && $props[$this->props['taskupdates']] && !(isset($props[$this->props['recurring']]) && $props[$this->props['recurring']])) { |
756 | - $this->sendResponse(tdmtTaskUpd, _("Task Updated:") . " "); |
|
756 | + $this->sendResponse(tdmtTaskUpd, _("Task Updated:")." "); |
|
757 | 757 | } |
758 | 758 | elseif ($props[$this->props['complete']]) { |
759 | - $this->sendResponse(tdmtTaskUpd, _("Task Completed:") . " "); |
|
759 | + $this->sendResponse(tdmtTaskUpd, _("Task Completed:")." "); |
|
760 | 760 | } |
761 | 761 | |
762 | 762 | return true; |
@@ -890,7 +890,7 @@ discard block |
||
890 | 890 | |
891 | 891 | $attach = mapi_message_createattach($outgoing); |
892 | 892 | mapi_setprops($attach, [PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG, PR_DISPLAY_NAME => $messageprops[PR_CONVERSATION_TOPIC], PR_ATTACHMENT_HIDDEN => true]); |
893 | - $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_CREATE | MAPI_MODIFY); |
|
893 | + $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_CREATE|MAPI_MODIFY); |
|
894 | 894 | |
895 | 895 | $message = !$this->isTaskRequest() ? $this->message : $this->getAssociatedTask(false); |
896 | 896 | |
@@ -933,7 +933,7 @@ discard block |
||
933 | 933 | mapi_savechanges($sub); |
934 | 934 | mapi_savechanges($attach); |
935 | 935 | |
936 | - $props[PR_SUBJECT] = $prefix . $messageprops[PR_CONVERSATION_TOPIC]; |
|
936 | + $props[PR_SUBJECT] = $prefix.$messageprops[PR_CONVERSATION_TOPIC]; |
|
937 | 937 | $props[$this->props['taskmode']] = $type; |
938 | 938 | $props[$this->props['task_assigned_time']] = time(); |
939 | 939 | |
@@ -943,7 +943,7 @@ discard block |
||
943 | 943 | // edit response before sending task response. |
944 | 944 | if ($this->taskCommentsInfo) { |
945 | 945 | $comments = $this->getTaskCommentsInfo(); |
946 | - $stream = mapi_openproperty($outgoing, PR_BODY, IID_IStream, STGM_TRANSACTED, MAPI_CREATE | MAPI_MODIFY); |
|
946 | + $stream = mapi_openproperty($outgoing, PR_BODY, IID_IStream, STGM_TRANSACTED, MAPI_CREATE|MAPI_MODIFY); |
|
947 | 947 | mapi_stream_setsize($stream, strlen($comments)); |
948 | 948 | mapi_stream_write($stream, $comments); |
949 | 949 | mapi_stream_commit($stream); |
@@ -1206,7 +1206,7 @@ discard block |
||
1206 | 1206 | } |
1207 | 1207 | |
1208 | 1208 | foreach ($recips as $recip) { |
1209 | - $recip[PR_RECIPIENT_TYPE] = MAPI_TO; // Change recipient type to MAPI_TO |
|
1209 | + $recip[PR_RECIPIENT_TYPE] = MAPI_TO; // Change recipient type to MAPI_TO |
|
1210 | 1210 | mapi_message_modifyrecipients($outgoing, MODRECIP_ADD, [$recip]); |
1211 | 1211 | } |
1212 | 1212 |
@@ -271,8 +271,7 @@ discard block |
||
271 | 271 | // Copy sender information from the e-mail |
272 | 272 | $props = mapi_getprops($this->message, $senderProps); |
273 | 273 | mapi_setprops($task, $props); |
274 | - } |
|
275 | - else { |
|
274 | + } else { |
|
276 | 275 | // If there are multiple, just use the first |
277 | 276 | $entryid = $rows[0][PR_ENTRYID]; |
278 | 277 | |
@@ -575,8 +574,7 @@ discard block |
||
575 | 574 | |
576 | 575 | if (isset($messageprops)) { |
577 | 576 | ++$messageprops[$this->props['updatecount']]; |
578 | - } |
|
579 | - else { |
|
577 | + } else { |
|
580 | 578 | $messageprops[$this->props['updatecount']] = 1; |
581 | 579 | } |
582 | 580 | |
@@ -754,8 +752,7 @@ discard block |
||
754 | 752 | $props = mapi_getprops($this->message, [$this->props['taskupdates'], $this->props['tasksoc'], $this->props['recurring'], $this->props['complete']]); |
755 | 753 | if (!$props[$this->props['complete']] && $props[$this->props['taskupdates']] && !(isset($props[$this->props['recurring']]) && $props[$this->props['recurring']])) { |
756 | 754 | $this->sendResponse(tdmtTaskUpd, _("Task Updated:") . " "); |
757 | - } |
|
758 | - elseif ($props[$this->props['complete']]) { |
|
755 | + } elseif ($props[$this->props['complete']]) { |
|
759 | 756 | $this->sendResponse(tdmtTaskUpd, _("Task Completed:") . " "); |
760 | 757 | } |
761 | 758 | |
@@ -778,8 +775,7 @@ discard block |
||
778 | 775 | |
779 | 776 | if (!$ownerentryid) { |
780 | 777 | $store = $this->store; |
781 | - } |
|
782 | - else { |
|
778 | + } else { |
|
783 | 779 | $ab = mapi_openaddressbook($this->session); |
784 | 780 | if (!$ab) { |
785 | 781 | return false; |
@@ -922,8 +918,7 @@ discard block |
||
922 | 918 | mapi_setprops($sub, [PR_ICON_INDEX => ICON_TASK_ASSIGNER]); |
923 | 919 | if ($messageprops[$this->props['complete']]) { |
924 | 920 | $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Complete"; |
925 | - } |
|
926 | - else { |
|
921 | + } else { |
|
927 | 922 | $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Update"; |
928 | 923 | } |
929 | 924 | |
@@ -1011,8 +1006,7 @@ discard block |
||
1011 | 1006 | try { |
1012 | 1007 | $attach = mapi_message_openattach($message, $row[PR_ATTACH_NUM]); |
1013 | 1008 | $task = mapi_attach_openobj($attach); |
1014 | - } |
|
1015 | - catch (MAPIException $e) { |
|
1009 | + } catch (MAPIException $e) { |
|
1016 | 1010 | continue; |
1017 | 1011 | } |
1018 | 1012 |
@@ -11,7 +11,7 @@ discard block |
||
11 | 11 | |
12 | 12 | require_once 'vendor/autoload.php'; |
13 | 13 | if (!defined('GSYNC_CONFIG')) { |
14 | - define('GSYNC_CONFIG', 'config.php'); |
|
14 | + define('GSYNC_CONFIG', 'config.php'); |
|
15 | 15 | } |
16 | 16 | |
17 | 17 | include_once GSYNC_CONFIG; |
@@ -19,777 +19,777 @@ discard block |
||
19 | 19 | /* |
20 | 20 | * MAIN |
21 | 21 | */ |
22 | - declare(ticks=1); |
|
23 | - define('BASE_PATH_CLI', dirname(__FILE__) . "/"); |
|
24 | - set_include_path(get_include_path() . PATH_SEPARATOR . BASE_PATH_CLI); |
|
22 | + declare(ticks=1); |
|
23 | + define('BASE_PATH_CLI', dirname(__FILE__) . "/"); |
|
24 | + set_include_path(get_include_path() . PATH_SEPARATOR . BASE_PATH_CLI); |
|
25 | 25 | |
26 | - if (!defined('GSYNC_CONFIG')) { |
|
27 | - define('GSYNC_CONFIG', BASE_PATH_CLI . 'config.php'); |
|
28 | - } |
|
26 | + if (!defined('GSYNC_CONFIG')) { |
|
27 | + define('GSYNC_CONFIG', BASE_PATH_CLI . 'config.php'); |
|
28 | + } |
|
29 | 29 | |
30 | - include_once GSYNC_CONFIG; |
|
30 | + include_once GSYNC_CONFIG; |
|
31 | 31 | |
32 | - try { |
|
33 | - GSync::CheckConfig(); |
|
34 | - if (!function_exists("pcntl_signal")) { |
|
35 | - throw new FatalException("Function pcntl_signal() is not available. Please install package 'php5-pcntl' (or similar) on your system."); |
|
36 | - } |
|
32 | + try { |
|
33 | + GSync::CheckConfig(); |
|
34 | + if (!function_exists("pcntl_signal")) { |
|
35 | + throw new FatalException("Function pcntl_signal() is not available. Please install package 'php5-pcntl' (or similar) on your system."); |
|
36 | + } |
|
37 | 37 | |
38 | - if (php_sapi_name() != "cli") { |
|
39 | - throw new FatalException("This script can only be called from the CLI."); |
|
40 | - } |
|
38 | + if (php_sapi_name() != "cli") { |
|
39 | + throw new FatalException("This script can only be called from the CLI."); |
|
40 | + } |
|
41 | 41 | |
42 | - $zpt = new GSyncTop(); |
|
42 | + $zpt = new GSyncTop(); |
|
43 | 43 | |
44 | - // check if help was requested from CLI |
|
45 | - if (in_array('-h', $argv) || in_array('--help', $argv)) { |
|
46 | - echo $zpt->UsageInstructions(); |
|
44 | + // check if help was requested from CLI |
|
45 | + if (in_array('-h', $argv) || in_array('--help', $argv)) { |
|
46 | + echo $zpt->UsageInstructions(); |
|
47 | 47 | |
48 | - exit(0); |
|
49 | - } |
|
48 | + exit(0); |
|
49 | + } |
|
50 | 50 | |
51 | - if ($zpt->IsAvailable()) { |
|
52 | - pcntl_signal(SIGINT, [$zpt, "SignalHandler"]); |
|
53 | - $zpt->run(); |
|
54 | - $zpt->scrClear(); |
|
55 | - system("stty sane"); |
|
56 | - } |
|
57 | - else { |
|
58 | - echo "grommunio-sync interprocess communication (IPC) is not available or TopCollector is disabled.\n"; |
|
59 | - } |
|
60 | - } |
|
61 | - catch (GSyncException $zpe) { |
|
62 | - fwrite(STDERR, get_class($zpe) . ": " . $zpe->getMessage() . "\n"); |
|
51 | + if ($zpt->IsAvailable()) { |
|
52 | + pcntl_signal(SIGINT, [$zpt, "SignalHandler"]); |
|
53 | + $zpt->run(); |
|
54 | + $zpt->scrClear(); |
|
55 | + system("stty sane"); |
|
56 | + } |
|
57 | + else { |
|
58 | + echo "grommunio-sync interprocess communication (IPC) is not available or TopCollector is disabled.\n"; |
|
59 | + } |
|
60 | + } |
|
61 | + catch (GSyncException $zpe) { |
|
62 | + fwrite(STDERR, get_class($zpe) . ": " . $zpe->getMessage() . "\n"); |
|
63 | 63 | |
64 | - exit(1); |
|
65 | - } |
|
64 | + exit(1); |
|
65 | + } |
|
66 | 66 | |
67 | - echo "terminated\n"; |
|
67 | + echo "terminated\n"; |
|
68 | 68 | |
69 | 69 | /* |
70 | 70 | * grommunio-sync-top |
71 | 71 | */ |
72 | 72 | class GSyncTop { |
73 | - // show options |
|
74 | - public const SHOW_DEFAULT = 0; |
|
75 | - public const SHOW_ACTIVE_ONLY = 1; |
|
76 | - public const SHOW_UNKNOWN_ONLY = 2; |
|
77 | - public const SHOW_TERM_DEFAULT_TIME = 5; // 5 secs |
|
78 | - |
|
79 | - private $topCollector; |
|
80 | - private $starttime; |
|
81 | - private $action; |
|
82 | - private $filter; |
|
83 | - private $status; |
|
84 | - private $statusexpire; |
|
85 | - private $wide; |
|
86 | - private $wasEnabled; |
|
87 | - private $terminate; |
|
88 | - private $scrSize; |
|
89 | - private $pingInterval; |
|
90 | - private $showPush; |
|
91 | - private $showTermSec; |
|
92 | - |
|
93 | - private $linesActive = []; |
|
94 | - private $linesOpen = []; |
|
95 | - private $linesUnknown = []; |
|
96 | - private $linesTerm = []; |
|
97 | - private $pushConn = 0; |
|
98 | - private $activeConn = []; |
|
99 | - private $activeHosts = []; |
|
100 | - private $activeUsers = []; |
|
101 | - private $activeDevices = []; |
|
102 | - |
|
103 | - /** |
|
104 | - * Constructor. |
|
105 | - */ |
|
106 | - public function __construct() { |
|
107 | - $this->starttime = time(); |
|
108 | - $this->currenttime = time(); |
|
109 | - $this->action = ""; |
|
110 | - $this->filter = false; |
|
111 | - $this->status = false; |
|
112 | - $this->statusexpire = 0; |
|
113 | - $this->helpexpire = 0; |
|
114 | - $this->doingTail = false; |
|
115 | - $this->wide = false; |
|
116 | - $this->terminate = false; |
|
117 | - $this->showPush = true; |
|
118 | - $this->showOption = self::SHOW_DEFAULT; |
|
119 | - $this->showTermSec = self::SHOW_TERM_DEFAULT_TIME; |
|
120 | - $this->scrSize = ['width' => 80, 'height' => 24]; |
|
121 | - $this->pingInterval = (defined('PING_INTERVAL') && PING_INTERVAL > 0) ? PING_INTERVAL : 12; |
|
122 | - |
|
123 | - // get a TopCollector |
|
124 | - $this->topCollector = new TopCollector(); |
|
125 | - } |
|
126 | - |
|
127 | - /** |
|
128 | - * Requests data from the running grommunio-sync processes. |
|
129 | - * |
|
130 | - * @return |
|
131 | - */ |
|
132 | - private function initialize() { |
|
133 | - // request feedback from active processes |
|
134 | - $this->wasEnabled = $this->topCollector->CollectData(); |
|
135 | - |
|
136 | - // remove obsolete data |
|
137 | - $this->topCollector->ClearLatest(true); |
|
138 | - |
|
139 | - // start with default colours |
|
140 | - $this->scrDefaultColors(); |
|
141 | - } |
|
142 | - |
|
143 | - /** |
|
144 | - * Main loop of grommunio-sync-top |
|
145 | - * Runs until termination is requested. |
|
146 | - * |
|
147 | - * @return |
|
148 | - */ |
|
149 | - public function run() { |
|
150 | - $this->initialize(); |
|
151 | - |
|
152 | - do { |
|
153 | - $this->currenttime = time(); |
|
154 | - |
|
155 | - // see if shared memory is active |
|
156 | - if (!$this->IsAvailable()) { |
|
157 | - $this->terminate = true; |
|
158 | - } |
|
159 | - |
|
160 | - // active processes should continue sending data |
|
161 | - $this->topCollector->CollectData(); |
|
162 | - |
|
163 | - // get and process data from processes |
|
164 | - $this->topCollector->ClearLatest(); |
|
165 | - $topdata = $this->topCollector->ReadLatest(); |
|
166 | - $this->processData($topdata); |
|
167 | - |
|
168 | - // clear screen |
|
169 | - $this->scrClear(); |
|
170 | - |
|
171 | - // check if screen size changed |
|
172 | - $s = $this->scrGetSize(); |
|
173 | - if ($this->scrSize['width'] != $s['width']) { |
|
174 | - if ($s['width'] > 180) { |
|
175 | - $this->wide = true; |
|
176 | - } |
|
177 | - else { |
|
178 | - $this->wide = false; |
|
179 | - } |
|
180 | - } |
|
181 | - $this->scrSize = $s; |
|
182 | - |
|
183 | - // print overview |
|
184 | - $this->scrOverview(); |
|
185 | - |
|
186 | - // wait for user input |
|
187 | - $this->readLineProcess(); |
|
188 | - } |
|
189 | - while ($this->terminate != true); |
|
190 | - } |
|
191 | - |
|
192 | - /** |
|
193 | - * Indicates if TopCollector is available collecting data. |
|
194 | - * |
|
195 | - * @return bool |
|
196 | - */ |
|
197 | - public function IsAvailable() { |
|
198 | - if (defined('TOPCOLLECTOR_DISABLED') && constant('TOPCOLLECTOR_DISABLED') === true) { |
|
199 | - return false; |
|
200 | - } |
|
201 | - |
|
202 | - return $this->topCollector->IsActive(); |
|
203 | - } |
|
204 | - |
|
205 | - /** |
|
206 | - * Processes data written by the running processes. |
|
207 | - * |
|
208 | - * @param array $data |
|
209 | - * |
|
210 | - * @return |
|
211 | - */ |
|
212 | - private function processData($data) { |
|
213 | - $this->linesActive = []; |
|
214 | - $this->linesOpen = []; |
|
215 | - $this->linesUnknown = []; |
|
216 | - $this->linesTerm = []; |
|
217 | - $this->pushConn = 0; |
|
218 | - $this->activeConn = []; |
|
219 | - $this->activeHosts = []; |
|
220 | - $this->activeUsers = []; |
|
221 | - $this->activeDevices = []; |
|
222 | - |
|
223 | - if (!is_array($data)) { |
|
224 | - return; |
|
225 | - } |
|
226 | - |
|
227 | - foreach ($data as $devid => $users) { |
|
228 | - foreach ($users as $user => $pids) { |
|
229 | - foreach ($pids as $pid => $line) { |
|
230 | - if (!is_array($line)) { |
|
231 | - continue; |
|
232 | - } |
|
233 | - |
|
234 | - $line['command'] = Utils::GetCommandFromCode($line['command']); |
|
235 | - |
|
236 | - if ($line["ended"] == 0) { |
|
237 | - $this->activeDevices[$devid] = 1; |
|
238 | - $this->activeUsers[$user] = 1; |
|
239 | - $this->activeConn[$pid] = 1; |
|
240 | - $this->activeHosts[$line['ip']] = 1; |
|
241 | - |
|
242 | - $line["time"] = $this->currenttime - $line['start']; |
|
243 | - if ($line['push'] === true) { |
|
244 | - ++$this->pushConn; |
|
245 | - } |
|
246 | - |
|
247 | - // ignore push connections |
|
248 | - if ($line['push'] === true && !$this->showPush) { |
|
249 | - continue; |
|
250 | - } |
|
251 | - |
|
252 | - if ($this->filter !== false) { |
|
253 | - $f = $this->filter; |
|
254 | - if (!($line["pid"] == $f || $line["ip"] == $f || strtolower($line['command']) == strtolower($f) || preg_match("/.*?{$f}.*?/i", $line['user']) || |
|
255 | - preg_match("/.*?{$f}.*?/i", $line['devagent']) || preg_match("/.*?{$f}.*?/i", $line['devid']) || preg_match("/.*?{$f}.*?/i", $line['addinfo']))) { |
|
256 | - continue; |
|
257 | - } |
|
258 | - } |
|
259 | - |
|
260 | - $lastUpdate = $this->currenttime - $line["update"]; |
|
261 | - if ($this->currenttime - $line["update"] < 2) { |
|
262 | - $this->linesActive[$line["update"] . $line["pid"]] = $line; |
|
263 | - } |
|
264 | - elseif (($line['push'] === true && $lastUpdate > ($this->pingInterval + 2)) || ($line['push'] !== true && $lastUpdate > 4)) { |
|
265 | - $this->linesUnknown[$line["update"] . $line["pid"]] = $line; |
|
266 | - } |
|
267 | - else { |
|
268 | - $this->linesOpen[$line["update"] . $line["pid"]] = $line; |
|
269 | - } |
|
270 | - } |
|
271 | - else { |
|
272 | - // do not show terminated + expired connections |
|
273 | - if ($this->currenttime > $line['ended'] + $this->showTermSec) { |
|
274 | - continue; |
|
275 | - } |
|
276 | - |
|
277 | - if ($this->filter !== false) { |
|
278 | - $f = $this->filter; |
|
279 | - if ( |
|
280 | - !( |
|
281 | - $line['pid'] == $f || |
|
282 | - $line['ip'] == $f || |
|
283 | - strtolower($line['command']) == strtolower($f) || |
|
284 | - preg_match("/.*?{$f}.*?/i", $line['user']) || |
|
285 | - preg_match("/.*?{$f}.*?/i", $line['devagent']) || |
|
286 | - preg_match("/.*?{$f}.*?/i", $line['devid']) || |
|
287 | - preg_match("/.*?{$f}.*?/i", $line['addinfo']) |
|
288 | - )) { |
|
289 | - continue; |
|
290 | - } |
|
291 | - } |
|
292 | - |
|
293 | - $line['time'] = $line['ended'] - $line['start']; |
|
294 | - $this->linesTerm[$line['update'] . $line['pid']] = $line; |
|
295 | - } |
|
296 | - } |
|
297 | - } |
|
298 | - } |
|
299 | - |
|
300 | - // sort by execution time |
|
301 | - krsort($this->linesActive); |
|
302 | - krsort($this->linesOpen); |
|
303 | - krsort($this->linesUnknown); |
|
304 | - krsort($this->linesTerm); |
|
305 | - } |
|
306 | - |
|
307 | - /** |
|
308 | - * Prints data to the terminal. |
|
309 | - * |
|
310 | - * @return |
|
311 | - */ |
|
312 | - private function scrOverview() { |
|
313 | - $linesAvail = $this->scrSize['height'] - 8; |
|
314 | - $lc = 1; |
|
315 | - $this->scrPrintAt($lc, 0, "\033[1mgrommunio-sync-top live statistics\033[0m\t\t\t\t\t" . @strftime("%d/%m/%Y %T") . "\n"); |
|
316 | - ++$lc; |
|
317 | - |
|
318 | - $this->scrPrintAt($lc, 0, sprintf("Open connections: %d\t\t\t\tUsers:\t %d\tgrommunio-sync: %s ", count($this->activeConn), count($this->activeUsers), $this->getVersion())); |
|
319 | - ++$lc; |
|
320 | - $this->scrPrintAt($lc, 0, sprintf("Push connections: %d\t\t\t\tDevices: %d\tPHP-MAPI: %s", $this->pushConn, count($this->activeDevices), phpversion("mapi"))); |
|
321 | - ++$lc; |
|
322 | - $this->scrPrintAt($lc, 0, sprintf(" Hosts:\t %d", count($this->activeHosts))); |
|
323 | - ++$lc; |
|
324 | - ++$lc; |
|
325 | - |
|
326 | - $this->scrPrintAt($lc, 0, "\033[4m" . $this->getLine(['pid' => 'PID', 'ip' => 'IP', 'user' => 'USER', 'command' => 'COMMAND', 'time' => 'TIME', 'devagent' => 'AGENT', 'devid' => 'DEVID', 'addinfo' => 'Additional Information']) . str_repeat(" ", 20) . "\033[0m"); |
|
327 | - ++$lc; |
|
328 | - |
|
329 | - // print help text if requested |
|
330 | - $hl = 0; |
|
331 | - if ($this->helpexpire > $this->currenttime) { |
|
332 | - $help = $this->scrHelp(); |
|
333 | - $linesAvail -= count($help); |
|
334 | - $hl = $this->scrSize['height'] - count($help) - 1; |
|
335 | - foreach ($help as $h) { |
|
336 | - $this->scrPrintAt($hl, 0, $h); |
|
337 | - ++$hl; |
|
338 | - } |
|
339 | - } |
|
340 | - |
|
341 | - $toPrintActive = $linesAvail; |
|
342 | - $toPrintOpen = $linesAvail; |
|
343 | - $toPrintUnknown = $linesAvail; |
|
344 | - $toPrintTerm = $linesAvail; |
|
345 | - |
|
346 | - // default view: show all unknown, no terminated and half active+open |
|
347 | - if (count($this->linesActive) + count($this->linesOpen) + count($this->linesUnknown) > $linesAvail) { |
|
348 | - $toPrintUnknown = count($this->linesUnknown); |
|
349 | - $toPrintActive = count($this->linesActive); |
|
350 | - $toPrintOpen = $linesAvail - $toPrintUnknown - $toPrintActive; |
|
351 | - $toPrintTerm = 0; |
|
352 | - } |
|
353 | - |
|
354 | - if ($this->showOption == self::SHOW_ACTIVE_ONLY) { |
|
355 | - $toPrintActive = $linesAvail; |
|
356 | - $toPrintOpen = 0; |
|
357 | - $toPrintUnknown = 0; |
|
358 | - $toPrintTerm = 0; |
|
359 | - } |
|
360 | - |
|
361 | - if ($this->showOption == self::SHOW_UNKNOWN_ONLY) { |
|
362 | - $toPrintActive = 0; |
|
363 | - $toPrintOpen = 0; |
|
364 | - $toPrintUnknown = $linesAvail; |
|
365 | - $toPrintTerm = 0; |
|
366 | - } |
|
367 | - |
|
368 | - $linesprinted = 0; |
|
369 | - foreach ($this->linesActive as $time => $l) { |
|
370 | - if ($linesprinted >= $toPrintActive) { |
|
371 | - break; |
|
372 | - } |
|
373 | - |
|
374 | - $this->scrPrintAt($lc, 0, "\033[01m" . $this->getLine($l) . "\033[0m"); |
|
375 | - ++$lc; |
|
376 | - ++$linesprinted; |
|
377 | - } |
|
378 | - |
|
379 | - $linesprinted = 0; |
|
380 | - foreach ($this->linesOpen as $time => $l) { |
|
381 | - if ($linesprinted >= $toPrintOpen) { |
|
382 | - break; |
|
383 | - } |
|
384 | - |
|
385 | - $this->scrPrintAt($lc, 0, $this->getLine($l)); |
|
386 | - ++$lc; |
|
387 | - ++$linesprinted; |
|
388 | - } |
|
389 | - |
|
390 | - $linesprinted = 0; |
|
391 | - foreach ($this->linesUnknown as $time => $l) { |
|
392 | - if ($linesprinted >= $toPrintUnknown) { |
|
393 | - break; |
|
394 | - } |
|
395 | - |
|
396 | - $color = "0;31m"; |
|
397 | - if ($l['push'] == false && $time - $l["start"] > 30) { |
|
398 | - $color = "1;31m"; |
|
399 | - } |
|
400 | - $this->scrPrintAt($lc, 0, "\033[0" . $color . $this->getLine($l) . "\033[0m"); |
|
401 | - ++$lc; |
|
402 | - ++$linesprinted; |
|
403 | - } |
|
404 | - |
|
405 | - if ($toPrintTerm > 0) { |
|
406 | - $toPrintTerm = $linesAvail - $lc + 6; |
|
407 | - } |
|
408 | - |
|
409 | - $linesprinted = 0; |
|
410 | - foreach ($this->linesTerm as $time => $l) { |
|
411 | - if ($linesprinted >= $toPrintTerm) { |
|
412 | - break; |
|
413 | - } |
|
414 | - |
|
415 | - $this->scrPrintAt($lc, 0, "\033[01;30m" . $this->getLine($l) . "\033[0m"); |
|
416 | - ++$lc; |
|
417 | - ++$linesprinted; |
|
418 | - } |
|
419 | - |
|
420 | - // add the lines used when displaying the help text |
|
421 | - $lc += $hl; |
|
422 | - $this->scrPrintAt($lc, 0, "\033[K"); |
|
423 | - ++$lc; |
|
424 | - $this->scrPrintAt($lc, 0, "Colorscheme: \033[01mActive \033[0mOpen \033[01;31mUnknown \033[01;30mTerminated\033[0m"); |
|
425 | - |
|
426 | - // remove old status |
|
427 | - if ($this->statusexpire < $this->currenttime) { |
|
428 | - $this->status = false; |
|
429 | - } |
|
430 | - |
|
431 | - // show request information and help command |
|
432 | - if ($this->starttime + 6 > $this->currenttime) { |
|
433 | - $this->status = sprintf("Requesting information (takes up to %dsecs)", $this->pingInterval) . str_repeat(".", ($this->currenttime - $this->starttime)) . " type \033[01;31mh\033[00;31m or \033[01;31mhelp\033[00;31m for usage instructions"; |
|
434 | - $this->statusexpire = $this->currenttime + 1; |
|
435 | - } |
|
436 | - |
|
437 | - $str = ""; |
|
438 | - if (!$this->showPush) { |
|
439 | - $str .= "\033[00;32mPush: \033[01;32mNo\033[0m "; |
|
440 | - } |
|
441 | - |
|
442 | - if ($this->showOption == self::SHOW_ACTIVE_ONLY) { |
|
443 | - $str .= "\033[01;32mActive only\033[0m "; |
|
444 | - } |
|
445 | - |
|
446 | - if ($this->showOption == self::SHOW_UNKNOWN_ONLY) { |
|
447 | - $str .= "\033[01;32mUnknown only\033[0m "; |
|
448 | - } |
|
449 | - |
|
450 | - if ($this->showTermSec != self::SHOW_TERM_DEFAULT_TIME) { |
|
451 | - $str .= "\033[01;32mTerminated: " . $this->showTermSec . "s\033[0m "; |
|
452 | - } |
|
453 | - |
|
454 | - if ($this->filter !== false || ($this->status !== false && $this->statusexpire > $this->currenttime)) { |
|
455 | - // print filter in green |
|
456 | - if ($this->filter !== false) { |
|
457 | - $str .= "\033[00;32mFilter: \033[01;32m{$this->filter}\033[0m "; |
|
458 | - } |
|
459 | - // print status in red |
|
460 | - if ($this->status !== false) { |
|
461 | - $str .= "\033[00;31m{$this->status}\033[0m"; |
|
462 | - } |
|
463 | - } |
|
464 | - $this->scrPrintAt(5, 0, $str); |
|
465 | - |
|
466 | - $this->scrPrintAt(4, 0, "Action: \033[01m" . $this->action . "\033[0m"); |
|
467 | - } |
|
468 | - |
|
469 | - /** |
|
470 | - * Waits for a keystroke and processes the requested command. |
|
471 | - * |
|
472 | - * @return |
|
473 | - */ |
|
474 | - private function readLineProcess() { |
|
475 | - $ans = explode("^^", `bash -c "read -n 1 -t 1 ANS ; echo \\\$?^^\\\$ANS;"`); |
|
476 | - |
|
477 | - if ($ans[0] < 128) { |
|
478 | - if (isset($ans[1]) && bin2hex(trim($ans[1])) == "7f") { |
|
479 | - $this->action = substr($this->action, 0, -1); |
|
480 | - } |
|
481 | - |
|
482 | - if (isset($ans[1]) && $ans[1] != "") { |
|
483 | - $this->action .= trim(preg_replace("/[^A-Za-z0-9:]/", "", $ans[1])); |
|
484 | - } |
|
485 | - |
|
486 | - if (bin2hex($ans[0]) == "30" && bin2hex($ans[1]) == "0a") { |
|
487 | - $cmds = explode(':', $this->action); |
|
488 | - if ($cmds[0] == "quit" || $cmds[0] == "q" || (isset($cmds[1]) && $cmds[0] == "" && $cmds[1] == "q")) { |
|
489 | - $this->topCollector->CollectData(true); |
|
490 | - $this->topCollector->ClearLatest(true); |
|
491 | - |
|
492 | - $this->terminate = true; |
|
493 | - } |
|
494 | - elseif ($cmds[0] == "clear") { |
|
495 | - $this->topCollector->ClearLatest(true); |
|
496 | - $this->topCollector->CollectData(true); |
|
497 | - $this->topCollector->ReInitIPC(); |
|
498 | - } |
|
499 | - elseif ($cmds[0] == "filter" || $cmds[0] == "f") { |
|
500 | - if (!isset($cmds[1]) || $cmds[1] == "") { |
|
501 | - $this->filter = false; |
|
502 | - $this->status = "No filter"; |
|
503 | - $this->statusexpire = $this->currenttime + 5; |
|
504 | - } |
|
505 | - else { |
|
506 | - $this->filter = $cmds[1]; |
|
507 | - $this->status = false; |
|
508 | - } |
|
509 | - } |
|
510 | - elseif ($cmds[0] == "option" || $cmds[0] == "o") { |
|
511 | - if (!isset($cmds[1]) || $cmds[1] == "") { |
|
512 | - $this->status = "Option value needs to be specified. See 'help' or 'h' for instructions"; |
|
513 | - $this->statusexpire = $this->currenttime + 5; |
|
514 | - } |
|
515 | - elseif ($cmds[1] == "p" || $cmds[1] == "push" || $cmds[1] == "ping") { |
|
516 | - $this->showPush = !$this->showPush; |
|
517 | - } |
|
518 | - elseif ($cmds[1] == "a" || $cmds[1] == "active") { |
|
519 | - $this->showOption = self::SHOW_ACTIVE_ONLY; |
|
520 | - } |
|
521 | - elseif ($cmds[1] == "u" || $cmds[1] == "unknown") { |
|
522 | - $this->showOption = self::SHOW_UNKNOWN_ONLY; |
|
523 | - } |
|
524 | - elseif ($cmds[1] == "d" || $cmds[1] == "default") { |
|
525 | - $this->showOption = self::SHOW_DEFAULT; |
|
526 | - $this->showTermSec = self::SHOW_TERM_DEFAULT_TIME; |
|
527 | - $this->showPush = true; |
|
528 | - } |
|
529 | - elseif (is_numeric($cmds[1])) { |
|
530 | - $this->showTermSec = $cmds[1]; |
|
531 | - } |
|
532 | - else { |
|
533 | - $this->status = sprintf("Option '%s' unknown", $cmds[1]); |
|
534 | - $this->statusexpire = $this->currenttime + 5; |
|
535 | - } |
|
536 | - } |
|
537 | - elseif ($cmds[0] == "reset" || $cmds[0] == "r") { |
|
538 | - $this->filter = false; |
|
539 | - $this->wide = false; |
|
540 | - $this->helpexpire = 0; |
|
541 | - $this->status = "reset"; |
|
542 | - $this->statusexpire = $this->currenttime + 2; |
|
543 | - } |
|
544 | - // enable/disable wide view |
|
545 | - elseif ($cmds[0] == "wide" || $cmds[0] == "w") { |
|
546 | - $this->wide = !$this->wide; |
|
547 | - $this->status = ($this->wide) ? "w i d e view" : "normal view"; |
|
548 | - $this->statusexpire = $this->currenttime + 2; |
|
549 | - } |
|
550 | - elseif ($cmds[0] == "help" || $cmds[0] == "h") { |
|
551 | - $this->helpexpire = $this->currenttime + 20; |
|
552 | - } |
|
553 | - // grep the log file |
|
554 | - elseif (($cmds[0] == "log" || $cmds[0] == "l") && isset($cmds[1])) { |
|
555 | - if (!file_exists(LOGFILE)) { |
|
556 | - $this->status = "Logfile can not be found: " . LOGFILE; |
|
557 | - } |
|
558 | - else { |
|
559 | - system('bash -c "fgrep -a ' . escapeshellarg($cmds[1]) . ' ' . LOGFILE . ' | less +G" > `tty`'); |
|
560 | - $this->status = "Returning from log, updating data"; |
|
561 | - } |
|
562 | - $this->statusexpire = time() + 5; // it might be much "later" now |
|
563 | - } |
|
564 | - // tail the log file |
|
565 | - elseif (($cmds[0] == "tail" || $cmds[0] == "t")) { |
|
566 | - if (!file_exists(LOGFILE)) { |
|
567 | - $this->status = "Logfile can not be found: " . LOGFILE; |
|
568 | - } |
|
569 | - else { |
|
570 | - $this->doingTail = true; |
|
571 | - $this->scrClear(); |
|
572 | - $this->scrPrintAt(1, 0, $this->scrAsBold("Press CTRL+C to return to grommunio-sync-top\n\n")); |
|
573 | - $secondary = ""; |
|
574 | - if (isset($cmds[1])) { |
|
575 | - $secondary = " -n 200 | grep " . escapeshellarg($cmds[1]); |
|
576 | - } |
|
577 | - system('bash -c "tail -f ' . LOGFILE . $secondary . '" > `tty`'); |
|
578 | - $this->doingTail = false; |
|
579 | - $this->status = "Returning from tail, updating data"; |
|
580 | - } |
|
581 | - $this->statusexpire = time() + 5; // it might be much "later" now |
|
582 | - } |
|
583 | - // tail the error log file |
|
584 | - elseif (($cmds[0] == "error" || $cmds[0] == "e")) { |
|
585 | - if (!file_exists(LOGERRORFILE)) { |
|
586 | - $this->status = "Error logfile can not be found: " . LOGERRORFILE; |
|
587 | - } |
|
588 | - else { |
|
589 | - $this->doingTail = true; |
|
590 | - $this->scrClear(); |
|
591 | - $this->scrPrintAt(1, 0, $this->scrAsBold("Press CTRL+C to return to grommunio-sync-top\n\n")); |
|
592 | - $secondary = ""; |
|
593 | - if (isset($cmds[1])) { |
|
594 | - $secondary = " -n 200 | grep " . escapeshellarg($cmds[1]); |
|
595 | - } |
|
596 | - system('bash -c "tail -f ' . LOGERRORFILE . $secondary . '" > `tty`'); |
|
597 | - $this->doingTail = false; |
|
598 | - $this->status = "Returning from tail, updating data"; |
|
599 | - } |
|
600 | - $this->statusexpire = time() + 5; // it might be much "later" now |
|
601 | - } |
|
602 | - elseif ($cmds[0] != "") { |
|
603 | - $this->status = sprintf("Command '%s' unknown", $cmds[0]); |
|
604 | - $this->statusexpire = $this->currenttime + 8; |
|
605 | - } |
|
606 | - $this->action = ""; |
|
607 | - } |
|
608 | - } |
|
609 | - } |
|
610 | - |
|
611 | - /** |
|
612 | - * Signal handler function. |
|
613 | - * |
|
614 | - * @param int $signo signal number |
|
615 | - * |
|
616 | - * @return |
|
617 | - */ |
|
618 | - public function SignalHandler($signo) { |
|
619 | - // don't terminate if the signal was sent by terminating tail |
|
620 | - if (!$this->doingTail) { |
|
621 | - $this->topCollector->CollectData(true); |
|
622 | - $this->topCollector->ClearLatest(true); |
|
623 | - $this->terminate = true; |
|
624 | - } |
|
625 | - } |
|
626 | - |
|
627 | - /** |
|
628 | - * Returns usage instructions. |
|
629 | - * |
|
630 | - * @return string |
|
631 | - */ |
|
632 | - public function UsageInstructions() { |
|
633 | - $help = "Usage:\n\tgrommunio-sync-top.php\n\n" . |
|
634 | - " grommunio-sync-top is a live top-like overview of what grommunio-sync is doing. It does not have specific command line options.\n\n" . |
|
635 | - " When grommunio-sync-top is running you can specify certain actions and options which can be executed (listed below).\n" . |
|
636 | - " This help information can also be shown inside grommunio-sync-top by hitting 'help' or 'h'.\n\n"; |
|
637 | - $scrhelp = $this->scrHelp(); |
|
638 | - unset($scrhelp[0]); |
|
639 | - |
|
640 | - $help .= implode("\n", $scrhelp); |
|
641 | - $help .= "\n\n"; |
|
642 | - |
|
643 | - return $help; |
|
644 | - } |
|
645 | - |
|
646 | - /** |
|
647 | - * Prints a 'help' text at the end of the page. |
|
648 | - * |
|
649 | - * @return array with help lines |
|
650 | - */ |
|
651 | - private function scrHelp() { |
|
652 | - $h = []; |
|
653 | - $secs = $this->helpexpire - $this->currenttime; |
|
654 | - $h[] = "Actions supported by grommunio-sync-top (help page still displayed for " . $secs . "secs)"; |
|
655 | - $h[] = " " . $this->scrAsBold("Action") . "\t\t" . $this->scrAsBold("Comment"); |
|
656 | - $h[] = " " . $this->scrAsBold("h") . " or " . $this->scrAsBold("help") . "\t\tDisplays this information."; |
|
657 | - $h[] = " " . $this->scrAsBold("q") . ", " . $this->scrAsBold("quit") . " or " . $this->scrAsBold(":q") . "\t\tExits grommunio-sync-top."; |
|
658 | - $h[] = " " . $this->scrAsBold("w") . " or " . $this->scrAsBold("wide") . "\t\tTries not to truncate data. Automatically done if more than 180 columns available."; |
|
659 | - $h[] = " " . $this->scrAsBold("f:VAL") . " or " . $this->scrAsBold("filter:VAL") . "\tOnly display connections which contain VAL. This value is case-insensitive."; |
|
660 | - $h[] = " " . $this->scrAsBold("f:") . " or " . $this->scrAsBold("filter:") . "\t\tWithout a search word: resets the filter."; |
|
661 | - $h[] = " " . $this->scrAsBold("l:STR") . " or " . $this->scrAsBold("log:STR") . "\tIssues 'less +G' on the logfile, after grepping on the optional STR."; |
|
662 | - $h[] = " " . $this->scrAsBold("t:STR") . " or " . $this->scrAsBold("tail:STR") . "\tIssues 'tail -f' on the logfile, grepping for optional STR."; |
|
663 | - $h[] = " " . $this->scrAsBold("e:STR") . " or " . $this->scrAsBold("error:STR") . "\tIssues 'tail -f' on the error logfile, grepping for optional STR."; |
|
664 | - $h[] = " " . $this->scrAsBold("r") . " or " . $this->scrAsBold("reset") . "\t\tResets 'wide' or 'filter'."; |
|
665 | - $h[] = " " . $this->scrAsBold("o:") . " or " . $this->scrAsBold("option:") . "\t\tSets display options. Valid options specified below"; |
|
666 | - $h[] = " " . $this->scrAsBold(" p") . " or " . $this->scrAsBold("push") . "\t\tLists/not lists active and open push connections."; |
|
667 | - $h[] = " " . $this->scrAsBold(" a") . " or " . $this->scrAsBold("action") . "\t\tLists only active connections."; |
|
668 | - $h[] = " " . $this->scrAsBold(" u") . " or " . $this->scrAsBold("unknown") . "\tLists only unknown connections."; |
|
669 | - $h[] = " " . $this->scrAsBold(" 10") . " or " . $this->scrAsBold("20") . "\t\tLists terminated connections for 10 or 20 seconds. Any other number can be used."; |
|
670 | - $h[] = " " . $this->scrAsBold(" d") . " or " . $this->scrAsBold("default") . "\tUses default options"; |
|
671 | - |
|
672 | - return $h; |
|
673 | - } |
|
674 | - |
|
675 | - /** |
|
676 | - * Encapsulates string with different color escape characters. |
|
677 | - * |
|
678 | - * @param string $text |
|
679 | - * |
|
680 | - * @return string same text as bold |
|
681 | - */ |
|
682 | - private function scrAsBold($text) { |
|
683 | - return "\033[01m" . $text . "\033[0m"; |
|
684 | - } |
|
685 | - |
|
686 | - /** |
|
687 | - * Prints one line of precessed data. |
|
688 | - * |
|
689 | - * @param array $l line information |
|
690 | - * |
|
691 | - * @return string |
|
692 | - */ |
|
693 | - private function getLine($l) { |
|
694 | - if ($this->wide === true) { |
|
695 | - return sprintf("%s%s%s%s%s%s%s%s", $this->ptStr($l['pid'], 6), $this->ptStr($l['ip'], 16), $this->ptStr($l['user'], 24), $this->ptStr($l['command'], 16), $this->ptStr($this->sec2min($l['time']), 8), $this->ptStr($l['devagent'], 28), $this->ptStr($l['devid'], 33, true), $l['addinfo']); |
|
696 | - } |
|
697 | - |
|
698 | - return sprintf("%s%s%s%s%s%s%s%s", $this->ptStr($l['pid'], 6), $this->ptStr($l['ip'], 16), $this->ptStr($l['user'], 8), $this->ptStr($l['command'], 8), $this->ptStr($this->sec2min($l['time']), 6), $this->ptStr($l['devagent'], 20), $this->ptStr($l['devid'], 12, true), $l['addinfo']); |
|
699 | - } |
|
700 | - |
|
701 | - /** |
|
702 | - * Pads and trims string. |
|
703 | - * |
|
704 | - * @param string $str to be trimmed/padded |
|
705 | - * @param int $size characters to be considered |
|
706 | - * @param bool $cutmiddle (optional) indicates where to long information should |
|
707 | - * be trimmed of, false means at the end |
|
708 | - * |
|
709 | - * @return string |
|
710 | - */ |
|
711 | - private function ptStr($str, $size, $cutmiddle = false) { |
|
712 | - if (strlen($str) < $size) { |
|
713 | - return str_pad($str, $size); |
|
714 | - } |
|
715 | - if ($cutmiddle == true) { |
|
716 | - $cut = ($size - 2) / 2; |
|
717 | - |
|
718 | - return $this->ptStr(substr($str, 0, $cut) . ".." . substr($str, (-1) * ($cut - 1)), $size); |
|
719 | - } |
|
720 | - |
|
721 | - return substr($str, 0, $size - 3) . ".. "; |
|
722 | - } |
|
723 | - |
|
724 | - /** |
|
725 | - * Tries to discover the size of the current terminal. |
|
726 | - * |
|
727 | - * @return array 'width' and 'height' as keys |
|
728 | - */ |
|
729 | - private function scrGetSize() { |
|
730 | - $tty = strtolower(exec('stty -a | fgrep columns')); |
|
731 | - if (preg_match_all("/rows.([0-9]+);.columns.([0-9]+);/", $tty, $output) || |
|
732 | - preg_match_all("/([0-9]+).rows;.([0-9]+).columns;/", $tty, $output)) { |
|
733 | - return ['width' => $output[2][0], 'height' => $output[1][0]]; |
|
734 | - } |
|
735 | - |
|
736 | - return ['width' => 80, 'height' => 24]; |
|
737 | - } |
|
738 | - |
|
739 | - /** |
|
740 | - * Returns the version of the current grommunio-sync installation. |
|
741 | - * |
|
742 | - * @return string |
|
743 | - */ |
|
744 | - private function getVersion() { |
|
745 | - return GROMMUNIOSYNC_VERSION; |
|
746 | - } |
|
747 | - |
|
748 | - /** |
|
749 | - * Converts seconds in MM:SS. |
|
750 | - * |
|
751 | - * @param int $s seconds |
|
752 | - * |
|
753 | - * @return string |
|
754 | - */ |
|
755 | - private function sec2min($s) { |
|
756 | - if (!is_int($s)) { |
|
757 | - return $s; |
|
758 | - } |
|
759 | - |
|
760 | - return sprintf("%02.2d:%02.2d", floor($s / 60), $s % 60); |
|
761 | - } |
|
762 | - |
|
763 | - /** |
|
764 | - * Resets the default colors of the terminal. |
|
765 | - * |
|
766 | - * @return |
|
767 | - */ |
|
768 | - private function scrDefaultColors() { |
|
769 | - echo "\033[0m"; |
|
770 | - } |
|
771 | - |
|
772 | - /** |
|
773 | - * Clears screen of the terminal. |
|
774 | - * |
|
775 | - * @param array $data |
|
776 | - * |
|
777 | - * @return |
|
778 | - */ |
|
779 | - public function scrClear() { |
|
780 | - echo "\033[2J"; |
|
781 | - } |
|
782 | - |
|
783 | - /** |
|
784 | - * Prints a text at a specific screen/terminal coordinates. |
|
785 | - * |
|
786 | - * @param int $row row number |
|
787 | - * @param int $col column number |
|
788 | - * @param string $text to be printed |
|
789 | - * |
|
790 | - * @return |
|
791 | - */ |
|
792 | - private function scrPrintAt($row, $col, $text = "") { |
|
793 | - echo "\033[" . $row . ";" . $col . "H" . $text; |
|
794 | - } |
|
73 | + // show options |
|
74 | + public const SHOW_DEFAULT = 0; |
|
75 | + public const SHOW_ACTIVE_ONLY = 1; |
|
76 | + public const SHOW_UNKNOWN_ONLY = 2; |
|
77 | + public const SHOW_TERM_DEFAULT_TIME = 5; // 5 secs |
|
78 | + |
|
79 | + private $topCollector; |
|
80 | + private $starttime; |
|
81 | + private $action; |
|
82 | + private $filter; |
|
83 | + private $status; |
|
84 | + private $statusexpire; |
|
85 | + private $wide; |
|
86 | + private $wasEnabled; |
|
87 | + private $terminate; |
|
88 | + private $scrSize; |
|
89 | + private $pingInterval; |
|
90 | + private $showPush; |
|
91 | + private $showTermSec; |
|
92 | + |
|
93 | + private $linesActive = []; |
|
94 | + private $linesOpen = []; |
|
95 | + private $linesUnknown = []; |
|
96 | + private $linesTerm = []; |
|
97 | + private $pushConn = 0; |
|
98 | + private $activeConn = []; |
|
99 | + private $activeHosts = []; |
|
100 | + private $activeUsers = []; |
|
101 | + private $activeDevices = []; |
|
102 | + |
|
103 | + /** |
|
104 | + * Constructor. |
|
105 | + */ |
|
106 | + public function __construct() { |
|
107 | + $this->starttime = time(); |
|
108 | + $this->currenttime = time(); |
|
109 | + $this->action = ""; |
|
110 | + $this->filter = false; |
|
111 | + $this->status = false; |
|
112 | + $this->statusexpire = 0; |
|
113 | + $this->helpexpire = 0; |
|
114 | + $this->doingTail = false; |
|
115 | + $this->wide = false; |
|
116 | + $this->terminate = false; |
|
117 | + $this->showPush = true; |
|
118 | + $this->showOption = self::SHOW_DEFAULT; |
|
119 | + $this->showTermSec = self::SHOW_TERM_DEFAULT_TIME; |
|
120 | + $this->scrSize = ['width' => 80, 'height' => 24]; |
|
121 | + $this->pingInterval = (defined('PING_INTERVAL') && PING_INTERVAL > 0) ? PING_INTERVAL : 12; |
|
122 | + |
|
123 | + // get a TopCollector |
|
124 | + $this->topCollector = new TopCollector(); |
|
125 | + } |
|
126 | + |
|
127 | + /** |
|
128 | + * Requests data from the running grommunio-sync processes. |
|
129 | + * |
|
130 | + * @return |
|
131 | + */ |
|
132 | + private function initialize() { |
|
133 | + // request feedback from active processes |
|
134 | + $this->wasEnabled = $this->topCollector->CollectData(); |
|
135 | + |
|
136 | + // remove obsolete data |
|
137 | + $this->topCollector->ClearLatest(true); |
|
138 | + |
|
139 | + // start with default colours |
|
140 | + $this->scrDefaultColors(); |
|
141 | + } |
|
142 | + |
|
143 | + /** |
|
144 | + * Main loop of grommunio-sync-top |
|
145 | + * Runs until termination is requested. |
|
146 | + * |
|
147 | + * @return |
|
148 | + */ |
|
149 | + public function run() { |
|
150 | + $this->initialize(); |
|
151 | + |
|
152 | + do { |
|
153 | + $this->currenttime = time(); |
|
154 | + |
|
155 | + // see if shared memory is active |
|
156 | + if (!$this->IsAvailable()) { |
|
157 | + $this->terminate = true; |
|
158 | + } |
|
159 | + |
|
160 | + // active processes should continue sending data |
|
161 | + $this->topCollector->CollectData(); |
|
162 | + |
|
163 | + // get and process data from processes |
|
164 | + $this->topCollector->ClearLatest(); |
|
165 | + $topdata = $this->topCollector->ReadLatest(); |
|
166 | + $this->processData($topdata); |
|
167 | + |
|
168 | + // clear screen |
|
169 | + $this->scrClear(); |
|
170 | + |
|
171 | + // check if screen size changed |
|
172 | + $s = $this->scrGetSize(); |
|
173 | + if ($this->scrSize['width'] != $s['width']) { |
|
174 | + if ($s['width'] > 180) { |
|
175 | + $this->wide = true; |
|
176 | + } |
|
177 | + else { |
|
178 | + $this->wide = false; |
|
179 | + } |
|
180 | + } |
|
181 | + $this->scrSize = $s; |
|
182 | + |
|
183 | + // print overview |
|
184 | + $this->scrOverview(); |
|
185 | + |
|
186 | + // wait for user input |
|
187 | + $this->readLineProcess(); |
|
188 | + } |
|
189 | + while ($this->terminate != true); |
|
190 | + } |
|
191 | + |
|
192 | + /** |
|
193 | + * Indicates if TopCollector is available collecting data. |
|
194 | + * |
|
195 | + * @return bool |
|
196 | + */ |
|
197 | + public function IsAvailable() { |
|
198 | + if (defined('TOPCOLLECTOR_DISABLED') && constant('TOPCOLLECTOR_DISABLED') === true) { |
|
199 | + return false; |
|
200 | + } |
|
201 | + |
|
202 | + return $this->topCollector->IsActive(); |
|
203 | + } |
|
204 | + |
|
205 | + /** |
|
206 | + * Processes data written by the running processes. |
|
207 | + * |
|
208 | + * @param array $data |
|
209 | + * |
|
210 | + * @return |
|
211 | + */ |
|
212 | + private function processData($data) { |
|
213 | + $this->linesActive = []; |
|
214 | + $this->linesOpen = []; |
|
215 | + $this->linesUnknown = []; |
|
216 | + $this->linesTerm = []; |
|
217 | + $this->pushConn = 0; |
|
218 | + $this->activeConn = []; |
|
219 | + $this->activeHosts = []; |
|
220 | + $this->activeUsers = []; |
|
221 | + $this->activeDevices = []; |
|
222 | + |
|
223 | + if (!is_array($data)) { |
|
224 | + return; |
|
225 | + } |
|
226 | + |
|
227 | + foreach ($data as $devid => $users) { |
|
228 | + foreach ($users as $user => $pids) { |
|
229 | + foreach ($pids as $pid => $line) { |
|
230 | + if (!is_array($line)) { |
|
231 | + continue; |
|
232 | + } |
|
233 | + |
|
234 | + $line['command'] = Utils::GetCommandFromCode($line['command']); |
|
235 | + |
|
236 | + if ($line["ended"] == 0) { |
|
237 | + $this->activeDevices[$devid] = 1; |
|
238 | + $this->activeUsers[$user] = 1; |
|
239 | + $this->activeConn[$pid] = 1; |
|
240 | + $this->activeHosts[$line['ip']] = 1; |
|
241 | + |
|
242 | + $line["time"] = $this->currenttime - $line['start']; |
|
243 | + if ($line['push'] === true) { |
|
244 | + ++$this->pushConn; |
|
245 | + } |
|
246 | + |
|
247 | + // ignore push connections |
|
248 | + if ($line['push'] === true && !$this->showPush) { |
|
249 | + continue; |
|
250 | + } |
|
251 | + |
|
252 | + if ($this->filter !== false) { |
|
253 | + $f = $this->filter; |
|
254 | + if (!($line["pid"] == $f || $line["ip"] == $f || strtolower($line['command']) == strtolower($f) || preg_match("/.*?{$f}.*?/i", $line['user']) || |
|
255 | + preg_match("/.*?{$f}.*?/i", $line['devagent']) || preg_match("/.*?{$f}.*?/i", $line['devid']) || preg_match("/.*?{$f}.*?/i", $line['addinfo']))) { |
|
256 | + continue; |
|
257 | + } |
|
258 | + } |
|
259 | + |
|
260 | + $lastUpdate = $this->currenttime - $line["update"]; |
|
261 | + if ($this->currenttime - $line["update"] < 2) { |
|
262 | + $this->linesActive[$line["update"] . $line["pid"]] = $line; |
|
263 | + } |
|
264 | + elseif (($line['push'] === true && $lastUpdate > ($this->pingInterval + 2)) || ($line['push'] !== true && $lastUpdate > 4)) { |
|
265 | + $this->linesUnknown[$line["update"] . $line["pid"]] = $line; |
|
266 | + } |
|
267 | + else { |
|
268 | + $this->linesOpen[$line["update"] . $line["pid"]] = $line; |
|
269 | + } |
|
270 | + } |
|
271 | + else { |
|
272 | + // do not show terminated + expired connections |
|
273 | + if ($this->currenttime > $line['ended'] + $this->showTermSec) { |
|
274 | + continue; |
|
275 | + } |
|
276 | + |
|
277 | + if ($this->filter !== false) { |
|
278 | + $f = $this->filter; |
|
279 | + if ( |
|
280 | + !( |
|
281 | + $line['pid'] == $f || |
|
282 | + $line['ip'] == $f || |
|
283 | + strtolower($line['command']) == strtolower($f) || |
|
284 | + preg_match("/.*?{$f}.*?/i", $line['user']) || |
|
285 | + preg_match("/.*?{$f}.*?/i", $line['devagent']) || |
|
286 | + preg_match("/.*?{$f}.*?/i", $line['devid']) || |
|
287 | + preg_match("/.*?{$f}.*?/i", $line['addinfo']) |
|
288 | + )) { |
|
289 | + continue; |
|
290 | + } |
|
291 | + } |
|
292 | + |
|
293 | + $line['time'] = $line['ended'] - $line['start']; |
|
294 | + $this->linesTerm[$line['update'] . $line['pid']] = $line; |
|
295 | + } |
|
296 | + } |
|
297 | + } |
|
298 | + } |
|
299 | + |
|
300 | + // sort by execution time |
|
301 | + krsort($this->linesActive); |
|
302 | + krsort($this->linesOpen); |
|
303 | + krsort($this->linesUnknown); |
|
304 | + krsort($this->linesTerm); |
|
305 | + } |
|
306 | + |
|
307 | + /** |
|
308 | + * Prints data to the terminal. |
|
309 | + * |
|
310 | + * @return |
|
311 | + */ |
|
312 | + private function scrOverview() { |
|
313 | + $linesAvail = $this->scrSize['height'] - 8; |
|
314 | + $lc = 1; |
|
315 | + $this->scrPrintAt($lc, 0, "\033[1mgrommunio-sync-top live statistics\033[0m\t\t\t\t\t" . @strftime("%d/%m/%Y %T") . "\n"); |
|
316 | + ++$lc; |
|
317 | + |
|
318 | + $this->scrPrintAt($lc, 0, sprintf("Open connections: %d\t\t\t\tUsers:\t %d\tgrommunio-sync: %s ", count($this->activeConn), count($this->activeUsers), $this->getVersion())); |
|
319 | + ++$lc; |
|
320 | + $this->scrPrintAt($lc, 0, sprintf("Push connections: %d\t\t\t\tDevices: %d\tPHP-MAPI: %s", $this->pushConn, count($this->activeDevices), phpversion("mapi"))); |
|
321 | + ++$lc; |
|
322 | + $this->scrPrintAt($lc, 0, sprintf(" Hosts:\t %d", count($this->activeHosts))); |
|
323 | + ++$lc; |
|
324 | + ++$lc; |
|
325 | + |
|
326 | + $this->scrPrintAt($lc, 0, "\033[4m" . $this->getLine(['pid' => 'PID', 'ip' => 'IP', 'user' => 'USER', 'command' => 'COMMAND', 'time' => 'TIME', 'devagent' => 'AGENT', 'devid' => 'DEVID', 'addinfo' => 'Additional Information']) . str_repeat(" ", 20) . "\033[0m"); |
|
327 | + ++$lc; |
|
328 | + |
|
329 | + // print help text if requested |
|
330 | + $hl = 0; |
|
331 | + if ($this->helpexpire > $this->currenttime) { |
|
332 | + $help = $this->scrHelp(); |
|
333 | + $linesAvail -= count($help); |
|
334 | + $hl = $this->scrSize['height'] - count($help) - 1; |
|
335 | + foreach ($help as $h) { |
|
336 | + $this->scrPrintAt($hl, 0, $h); |
|
337 | + ++$hl; |
|
338 | + } |
|
339 | + } |
|
340 | + |
|
341 | + $toPrintActive = $linesAvail; |
|
342 | + $toPrintOpen = $linesAvail; |
|
343 | + $toPrintUnknown = $linesAvail; |
|
344 | + $toPrintTerm = $linesAvail; |
|
345 | + |
|
346 | + // default view: show all unknown, no terminated and half active+open |
|
347 | + if (count($this->linesActive) + count($this->linesOpen) + count($this->linesUnknown) > $linesAvail) { |
|
348 | + $toPrintUnknown = count($this->linesUnknown); |
|
349 | + $toPrintActive = count($this->linesActive); |
|
350 | + $toPrintOpen = $linesAvail - $toPrintUnknown - $toPrintActive; |
|
351 | + $toPrintTerm = 0; |
|
352 | + } |
|
353 | + |
|
354 | + if ($this->showOption == self::SHOW_ACTIVE_ONLY) { |
|
355 | + $toPrintActive = $linesAvail; |
|
356 | + $toPrintOpen = 0; |
|
357 | + $toPrintUnknown = 0; |
|
358 | + $toPrintTerm = 0; |
|
359 | + } |
|
360 | + |
|
361 | + if ($this->showOption == self::SHOW_UNKNOWN_ONLY) { |
|
362 | + $toPrintActive = 0; |
|
363 | + $toPrintOpen = 0; |
|
364 | + $toPrintUnknown = $linesAvail; |
|
365 | + $toPrintTerm = 0; |
|
366 | + } |
|
367 | + |
|
368 | + $linesprinted = 0; |
|
369 | + foreach ($this->linesActive as $time => $l) { |
|
370 | + if ($linesprinted >= $toPrintActive) { |
|
371 | + break; |
|
372 | + } |
|
373 | + |
|
374 | + $this->scrPrintAt($lc, 0, "\033[01m" . $this->getLine($l) . "\033[0m"); |
|
375 | + ++$lc; |
|
376 | + ++$linesprinted; |
|
377 | + } |
|
378 | + |
|
379 | + $linesprinted = 0; |
|
380 | + foreach ($this->linesOpen as $time => $l) { |
|
381 | + if ($linesprinted >= $toPrintOpen) { |
|
382 | + break; |
|
383 | + } |
|
384 | + |
|
385 | + $this->scrPrintAt($lc, 0, $this->getLine($l)); |
|
386 | + ++$lc; |
|
387 | + ++$linesprinted; |
|
388 | + } |
|
389 | + |
|
390 | + $linesprinted = 0; |
|
391 | + foreach ($this->linesUnknown as $time => $l) { |
|
392 | + if ($linesprinted >= $toPrintUnknown) { |
|
393 | + break; |
|
394 | + } |
|
395 | + |
|
396 | + $color = "0;31m"; |
|
397 | + if ($l['push'] == false && $time - $l["start"] > 30) { |
|
398 | + $color = "1;31m"; |
|
399 | + } |
|
400 | + $this->scrPrintAt($lc, 0, "\033[0" . $color . $this->getLine($l) . "\033[0m"); |
|
401 | + ++$lc; |
|
402 | + ++$linesprinted; |
|
403 | + } |
|
404 | + |
|
405 | + if ($toPrintTerm > 0) { |
|
406 | + $toPrintTerm = $linesAvail - $lc + 6; |
|
407 | + } |
|
408 | + |
|
409 | + $linesprinted = 0; |
|
410 | + foreach ($this->linesTerm as $time => $l) { |
|
411 | + if ($linesprinted >= $toPrintTerm) { |
|
412 | + break; |
|
413 | + } |
|
414 | + |
|
415 | + $this->scrPrintAt($lc, 0, "\033[01;30m" . $this->getLine($l) . "\033[0m"); |
|
416 | + ++$lc; |
|
417 | + ++$linesprinted; |
|
418 | + } |
|
419 | + |
|
420 | + // add the lines used when displaying the help text |
|
421 | + $lc += $hl; |
|
422 | + $this->scrPrintAt($lc, 0, "\033[K"); |
|
423 | + ++$lc; |
|
424 | + $this->scrPrintAt($lc, 0, "Colorscheme: \033[01mActive \033[0mOpen \033[01;31mUnknown \033[01;30mTerminated\033[0m"); |
|
425 | + |
|
426 | + // remove old status |
|
427 | + if ($this->statusexpire < $this->currenttime) { |
|
428 | + $this->status = false; |
|
429 | + } |
|
430 | + |
|
431 | + // show request information and help command |
|
432 | + if ($this->starttime + 6 > $this->currenttime) { |
|
433 | + $this->status = sprintf("Requesting information (takes up to %dsecs)", $this->pingInterval) . str_repeat(".", ($this->currenttime - $this->starttime)) . " type \033[01;31mh\033[00;31m or \033[01;31mhelp\033[00;31m for usage instructions"; |
|
434 | + $this->statusexpire = $this->currenttime + 1; |
|
435 | + } |
|
436 | + |
|
437 | + $str = ""; |
|
438 | + if (!$this->showPush) { |
|
439 | + $str .= "\033[00;32mPush: \033[01;32mNo\033[0m "; |
|
440 | + } |
|
441 | + |
|
442 | + if ($this->showOption == self::SHOW_ACTIVE_ONLY) { |
|
443 | + $str .= "\033[01;32mActive only\033[0m "; |
|
444 | + } |
|
445 | + |
|
446 | + if ($this->showOption == self::SHOW_UNKNOWN_ONLY) { |
|
447 | + $str .= "\033[01;32mUnknown only\033[0m "; |
|
448 | + } |
|
449 | + |
|
450 | + if ($this->showTermSec != self::SHOW_TERM_DEFAULT_TIME) { |
|
451 | + $str .= "\033[01;32mTerminated: " . $this->showTermSec . "s\033[0m "; |
|
452 | + } |
|
453 | + |
|
454 | + if ($this->filter !== false || ($this->status !== false && $this->statusexpire > $this->currenttime)) { |
|
455 | + // print filter in green |
|
456 | + if ($this->filter !== false) { |
|
457 | + $str .= "\033[00;32mFilter: \033[01;32m{$this->filter}\033[0m "; |
|
458 | + } |
|
459 | + // print status in red |
|
460 | + if ($this->status !== false) { |
|
461 | + $str .= "\033[00;31m{$this->status}\033[0m"; |
|
462 | + } |
|
463 | + } |
|
464 | + $this->scrPrintAt(5, 0, $str); |
|
465 | + |
|
466 | + $this->scrPrintAt(4, 0, "Action: \033[01m" . $this->action . "\033[0m"); |
|
467 | + } |
|
468 | + |
|
469 | + /** |
|
470 | + * Waits for a keystroke and processes the requested command. |
|
471 | + * |
|
472 | + * @return |
|
473 | + */ |
|
474 | + private function readLineProcess() { |
|
475 | + $ans = explode("^^", `bash -c "read -n 1 -t 1 ANS ; echo \\\$?^^\\\$ANS;"`); |
|
476 | + |
|
477 | + if ($ans[0] < 128) { |
|
478 | + if (isset($ans[1]) && bin2hex(trim($ans[1])) == "7f") { |
|
479 | + $this->action = substr($this->action, 0, -1); |
|
480 | + } |
|
481 | + |
|
482 | + if (isset($ans[1]) && $ans[1] != "") { |
|
483 | + $this->action .= trim(preg_replace("/[^A-Za-z0-9:]/", "", $ans[1])); |
|
484 | + } |
|
485 | + |
|
486 | + if (bin2hex($ans[0]) == "30" && bin2hex($ans[1]) == "0a") { |
|
487 | + $cmds = explode(':', $this->action); |
|
488 | + if ($cmds[0] == "quit" || $cmds[0] == "q" || (isset($cmds[1]) && $cmds[0] == "" && $cmds[1] == "q")) { |
|
489 | + $this->topCollector->CollectData(true); |
|
490 | + $this->topCollector->ClearLatest(true); |
|
491 | + |
|
492 | + $this->terminate = true; |
|
493 | + } |
|
494 | + elseif ($cmds[0] == "clear") { |
|
495 | + $this->topCollector->ClearLatest(true); |
|
496 | + $this->topCollector->CollectData(true); |
|
497 | + $this->topCollector->ReInitIPC(); |
|
498 | + } |
|
499 | + elseif ($cmds[0] == "filter" || $cmds[0] == "f") { |
|
500 | + if (!isset($cmds[1]) || $cmds[1] == "") { |
|
501 | + $this->filter = false; |
|
502 | + $this->status = "No filter"; |
|
503 | + $this->statusexpire = $this->currenttime + 5; |
|
504 | + } |
|
505 | + else { |
|
506 | + $this->filter = $cmds[1]; |
|
507 | + $this->status = false; |
|
508 | + } |
|
509 | + } |
|
510 | + elseif ($cmds[0] == "option" || $cmds[0] == "o") { |
|
511 | + if (!isset($cmds[1]) || $cmds[1] == "") { |
|
512 | + $this->status = "Option value needs to be specified. See 'help' or 'h' for instructions"; |
|
513 | + $this->statusexpire = $this->currenttime + 5; |
|
514 | + } |
|
515 | + elseif ($cmds[1] == "p" || $cmds[1] == "push" || $cmds[1] == "ping") { |
|
516 | + $this->showPush = !$this->showPush; |
|
517 | + } |
|
518 | + elseif ($cmds[1] == "a" || $cmds[1] == "active") { |
|
519 | + $this->showOption = self::SHOW_ACTIVE_ONLY; |
|
520 | + } |
|
521 | + elseif ($cmds[1] == "u" || $cmds[1] == "unknown") { |
|
522 | + $this->showOption = self::SHOW_UNKNOWN_ONLY; |
|
523 | + } |
|
524 | + elseif ($cmds[1] == "d" || $cmds[1] == "default") { |
|
525 | + $this->showOption = self::SHOW_DEFAULT; |
|
526 | + $this->showTermSec = self::SHOW_TERM_DEFAULT_TIME; |
|
527 | + $this->showPush = true; |
|
528 | + } |
|
529 | + elseif (is_numeric($cmds[1])) { |
|
530 | + $this->showTermSec = $cmds[1]; |
|
531 | + } |
|
532 | + else { |
|
533 | + $this->status = sprintf("Option '%s' unknown", $cmds[1]); |
|
534 | + $this->statusexpire = $this->currenttime + 5; |
|
535 | + } |
|
536 | + } |
|
537 | + elseif ($cmds[0] == "reset" || $cmds[0] == "r") { |
|
538 | + $this->filter = false; |
|
539 | + $this->wide = false; |
|
540 | + $this->helpexpire = 0; |
|
541 | + $this->status = "reset"; |
|
542 | + $this->statusexpire = $this->currenttime + 2; |
|
543 | + } |
|
544 | + // enable/disable wide view |
|
545 | + elseif ($cmds[0] == "wide" || $cmds[0] == "w") { |
|
546 | + $this->wide = !$this->wide; |
|
547 | + $this->status = ($this->wide) ? "w i d e view" : "normal view"; |
|
548 | + $this->statusexpire = $this->currenttime + 2; |
|
549 | + } |
|
550 | + elseif ($cmds[0] == "help" || $cmds[0] == "h") { |
|
551 | + $this->helpexpire = $this->currenttime + 20; |
|
552 | + } |
|
553 | + // grep the log file |
|
554 | + elseif (($cmds[0] == "log" || $cmds[0] == "l") && isset($cmds[1])) { |
|
555 | + if (!file_exists(LOGFILE)) { |
|
556 | + $this->status = "Logfile can not be found: " . LOGFILE; |
|
557 | + } |
|
558 | + else { |
|
559 | + system('bash -c "fgrep -a ' . escapeshellarg($cmds[1]) . ' ' . LOGFILE . ' | less +G" > `tty`'); |
|
560 | + $this->status = "Returning from log, updating data"; |
|
561 | + } |
|
562 | + $this->statusexpire = time() + 5; // it might be much "later" now |
|
563 | + } |
|
564 | + // tail the log file |
|
565 | + elseif (($cmds[0] == "tail" || $cmds[0] == "t")) { |
|
566 | + if (!file_exists(LOGFILE)) { |
|
567 | + $this->status = "Logfile can not be found: " . LOGFILE; |
|
568 | + } |
|
569 | + else { |
|
570 | + $this->doingTail = true; |
|
571 | + $this->scrClear(); |
|
572 | + $this->scrPrintAt(1, 0, $this->scrAsBold("Press CTRL+C to return to grommunio-sync-top\n\n")); |
|
573 | + $secondary = ""; |
|
574 | + if (isset($cmds[1])) { |
|
575 | + $secondary = " -n 200 | grep " . escapeshellarg($cmds[1]); |
|
576 | + } |
|
577 | + system('bash -c "tail -f ' . LOGFILE . $secondary . '" > `tty`'); |
|
578 | + $this->doingTail = false; |
|
579 | + $this->status = "Returning from tail, updating data"; |
|
580 | + } |
|
581 | + $this->statusexpire = time() + 5; // it might be much "later" now |
|
582 | + } |
|
583 | + // tail the error log file |
|
584 | + elseif (($cmds[0] == "error" || $cmds[0] == "e")) { |
|
585 | + if (!file_exists(LOGERRORFILE)) { |
|
586 | + $this->status = "Error logfile can not be found: " . LOGERRORFILE; |
|
587 | + } |
|
588 | + else { |
|
589 | + $this->doingTail = true; |
|
590 | + $this->scrClear(); |
|
591 | + $this->scrPrintAt(1, 0, $this->scrAsBold("Press CTRL+C to return to grommunio-sync-top\n\n")); |
|
592 | + $secondary = ""; |
|
593 | + if (isset($cmds[1])) { |
|
594 | + $secondary = " -n 200 | grep " . escapeshellarg($cmds[1]); |
|
595 | + } |
|
596 | + system('bash -c "tail -f ' . LOGERRORFILE . $secondary . '" > `tty`'); |
|
597 | + $this->doingTail = false; |
|
598 | + $this->status = "Returning from tail, updating data"; |
|
599 | + } |
|
600 | + $this->statusexpire = time() + 5; // it might be much "later" now |
|
601 | + } |
|
602 | + elseif ($cmds[0] != "") { |
|
603 | + $this->status = sprintf("Command '%s' unknown", $cmds[0]); |
|
604 | + $this->statusexpire = $this->currenttime + 8; |
|
605 | + } |
|
606 | + $this->action = ""; |
|
607 | + } |
|
608 | + } |
|
609 | + } |
|
610 | + |
|
611 | + /** |
|
612 | + * Signal handler function. |
|
613 | + * |
|
614 | + * @param int $signo signal number |
|
615 | + * |
|
616 | + * @return |
|
617 | + */ |
|
618 | + public function SignalHandler($signo) { |
|
619 | + // don't terminate if the signal was sent by terminating tail |
|
620 | + if (!$this->doingTail) { |
|
621 | + $this->topCollector->CollectData(true); |
|
622 | + $this->topCollector->ClearLatest(true); |
|
623 | + $this->terminate = true; |
|
624 | + } |
|
625 | + } |
|
626 | + |
|
627 | + /** |
|
628 | + * Returns usage instructions. |
|
629 | + * |
|
630 | + * @return string |
|
631 | + */ |
|
632 | + public function UsageInstructions() { |
|
633 | + $help = "Usage:\n\tgrommunio-sync-top.php\n\n" . |
|
634 | + " grommunio-sync-top is a live top-like overview of what grommunio-sync is doing. It does not have specific command line options.\n\n" . |
|
635 | + " When grommunio-sync-top is running you can specify certain actions and options which can be executed (listed below).\n" . |
|
636 | + " This help information can also be shown inside grommunio-sync-top by hitting 'help' or 'h'.\n\n"; |
|
637 | + $scrhelp = $this->scrHelp(); |
|
638 | + unset($scrhelp[0]); |
|
639 | + |
|
640 | + $help .= implode("\n", $scrhelp); |
|
641 | + $help .= "\n\n"; |
|
642 | + |
|
643 | + return $help; |
|
644 | + } |
|
645 | + |
|
646 | + /** |
|
647 | + * Prints a 'help' text at the end of the page. |
|
648 | + * |
|
649 | + * @return array with help lines |
|
650 | + */ |
|
651 | + private function scrHelp() { |
|
652 | + $h = []; |
|
653 | + $secs = $this->helpexpire - $this->currenttime; |
|
654 | + $h[] = "Actions supported by grommunio-sync-top (help page still displayed for " . $secs . "secs)"; |
|
655 | + $h[] = " " . $this->scrAsBold("Action") . "\t\t" . $this->scrAsBold("Comment"); |
|
656 | + $h[] = " " . $this->scrAsBold("h") . " or " . $this->scrAsBold("help") . "\t\tDisplays this information."; |
|
657 | + $h[] = " " . $this->scrAsBold("q") . ", " . $this->scrAsBold("quit") . " or " . $this->scrAsBold(":q") . "\t\tExits grommunio-sync-top."; |
|
658 | + $h[] = " " . $this->scrAsBold("w") . " or " . $this->scrAsBold("wide") . "\t\tTries not to truncate data. Automatically done if more than 180 columns available."; |
|
659 | + $h[] = " " . $this->scrAsBold("f:VAL") . " or " . $this->scrAsBold("filter:VAL") . "\tOnly display connections which contain VAL. This value is case-insensitive."; |
|
660 | + $h[] = " " . $this->scrAsBold("f:") . " or " . $this->scrAsBold("filter:") . "\t\tWithout a search word: resets the filter."; |
|
661 | + $h[] = " " . $this->scrAsBold("l:STR") . " or " . $this->scrAsBold("log:STR") . "\tIssues 'less +G' on the logfile, after grepping on the optional STR."; |
|
662 | + $h[] = " " . $this->scrAsBold("t:STR") . " or " . $this->scrAsBold("tail:STR") . "\tIssues 'tail -f' on the logfile, grepping for optional STR."; |
|
663 | + $h[] = " " . $this->scrAsBold("e:STR") . " or " . $this->scrAsBold("error:STR") . "\tIssues 'tail -f' on the error logfile, grepping for optional STR."; |
|
664 | + $h[] = " " . $this->scrAsBold("r") . " or " . $this->scrAsBold("reset") . "\t\tResets 'wide' or 'filter'."; |
|
665 | + $h[] = " " . $this->scrAsBold("o:") . " or " . $this->scrAsBold("option:") . "\t\tSets display options. Valid options specified below"; |
|
666 | + $h[] = " " . $this->scrAsBold(" p") . " or " . $this->scrAsBold("push") . "\t\tLists/not lists active and open push connections."; |
|
667 | + $h[] = " " . $this->scrAsBold(" a") . " or " . $this->scrAsBold("action") . "\t\tLists only active connections."; |
|
668 | + $h[] = " " . $this->scrAsBold(" u") . " or " . $this->scrAsBold("unknown") . "\tLists only unknown connections."; |
|
669 | + $h[] = " " . $this->scrAsBold(" 10") . " or " . $this->scrAsBold("20") . "\t\tLists terminated connections for 10 or 20 seconds. Any other number can be used."; |
|
670 | + $h[] = " " . $this->scrAsBold(" d") . " or " . $this->scrAsBold("default") . "\tUses default options"; |
|
671 | + |
|
672 | + return $h; |
|
673 | + } |
|
674 | + |
|
675 | + /** |
|
676 | + * Encapsulates string with different color escape characters. |
|
677 | + * |
|
678 | + * @param string $text |
|
679 | + * |
|
680 | + * @return string same text as bold |
|
681 | + */ |
|
682 | + private function scrAsBold($text) { |
|
683 | + return "\033[01m" . $text . "\033[0m"; |
|
684 | + } |
|
685 | + |
|
686 | + /** |
|
687 | + * Prints one line of precessed data. |
|
688 | + * |
|
689 | + * @param array $l line information |
|
690 | + * |
|
691 | + * @return string |
|
692 | + */ |
|
693 | + private function getLine($l) { |
|
694 | + if ($this->wide === true) { |
|
695 | + return sprintf("%s%s%s%s%s%s%s%s", $this->ptStr($l['pid'], 6), $this->ptStr($l['ip'], 16), $this->ptStr($l['user'], 24), $this->ptStr($l['command'], 16), $this->ptStr($this->sec2min($l['time']), 8), $this->ptStr($l['devagent'], 28), $this->ptStr($l['devid'], 33, true), $l['addinfo']); |
|
696 | + } |
|
697 | + |
|
698 | + return sprintf("%s%s%s%s%s%s%s%s", $this->ptStr($l['pid'], 6), $this->ptStr($l['ip'], 16), $this->ptStr($l['user'], 8), $this->ptStr($l['command'], 8), $this->ptStr($this->sec2min($l['time']), 6), $this->ptStr($l['devagent'], 20), $this->ptStr($l['devid'], 12, true), $l['addinfo']); |
|
699 | + } |
|
700 | + |
|
701 | + /** |
|
702 | + * Pads and trims string. |
|
703 | + * |
|
704 | + * @param string $str to be trimmed/padded |
|
705 | + * @param int $size characters to be considered |
|
706 | + * @param bool $cutmiddle (optional) indicates where to long information should |
|
707 | + * be trimmed of, false means at the end |
|
708 | + * |
|
709 | + * @return string |
|
710 | + */ |
|
711 | + private function ptStr($str, $size, $cutmiddle = false) { |
|
712 | + if (strlen($str) < $size) { |
|
713 | + return str_pad($str, $size); |
|
714 | + } |
|
715 | + if ($cutmiddle == true) { |
|
716 | + $cut = ($size - 2) / 2; |
|
717 | + |
|
718 | + return $this->ptStr(substr($str, 0, $cut) . ".." . substr($str, (-1) * ($cut - 1)), $size); |
|
719 | + } |
|
720 | + |
|
721 | + return substr($str, 0, $size - 3) . ".. "; |
|
722 | + } |
|
723 | + |
|
724 | + /** |
|
725 | + * Tries to discover the size of the current terminal. |
|
726 | + * |
|
727 | + * @return array 'width' and 'height' as keys |
|
728 | + */ |
|
729 | + private function scrGetSize() { |
|
730 | + $tty = strtolower(exec('stty -a | fgrep columns')); |
|
731 | + if (preg_match_all("/rows.([0-9]+);.columns.([0-9]+);/", $tty, $output) || |
|
732 | + preg_match_all("/([0-9]+).rows;.([0-9]+).columns;/", $tty, $output)) { |
|
733 | + return ['width' => $output[2][0], 'height' => $output[1][0]]; |
|
734 | + } |
|
735 | + |
|
736 | + return ['width' => 80, 'height' => 24]; |
|
737 | + } |
|
738 | + |
|
739 | + /** |
|
740 | + * Returns the version of the current grommunio-sync installation. |
|
741 | + * |
|
742 | + * @return string |
|
743 | + */ |
|
744 | + private function getVersion() { |
|
745 | + return GROMMUNIOSYNC_VERSION; |
|
746 | + } |
|
747 | + |
|
748 | + /** |
|
749 | + * Converts seconds in MM:SS. |
|
750 | + * |
|
751 | + * @param int $s seconds |
|
752 | + * |
|
753 | + * @return string |
|
754 | + */ |
|
755 | + private function sec2min($s) { |
|
756 | + if (!is_int($s)) { |
|
757 | + return $s; |
|
758 | + } |
|
759 | + |
|
760 | + return sprintf("%02.2d:%02.2d", floor($s / 60), $s % 60); |
|
761 | + } |
|
762 | + |
|
763 | + /** |
|
764 | + * Resets the default colors of the terminal. |
|
765 | + * |
|
766 | + * @return |
|
767 | + */ |
|
768 | + private function scrDefaultColors() { |
|
769 | + echo "\033[0m"; |
|
770 | + } |
|
771 | + |
|
772 | + /** |
|
773 | + * Clears screen of the terminal. |
|
774 | + * |
|
775 | + * @param array $data |
|
776 | + * |
|
777 | + * @return |
|
778 | + */ |
|
779 | + public function scrClear() { |
|
780 | + echo "\033[2J"; |
|
781 | + } |
|
782 | + |
|
783 | + /** |
|
784 | + * Prints a text at a specific screen/terminal coordinates. |
|
785 | + * |
|
786 | + * @param int $row row number |
|
787 | + * @param int $col column number |
|
788 | + * @param string $text to be printed |
|
789 | + * |
|
790 | + * @return |
|
791 | + */ |
|
792 | + private function scrPrintAt($row, $col, $text = "") { |
|
793 | + echo "\033[" . $row . ";" . $col . "H" . $text; |
|
794 | + } |
|
795 | 795 | } |
@@ -20,11 +20,11 @@ discard block |
||
20 | 20 | * MAIN |
21 | 21 | */ |
22 | 22 | declare(ticks=1); |
23 | - define('BASE_PATH_CLI', dirname(__FILE__) . "/"); |
|
24 | - set_include_path(get_include_path() . PATH_SEPARATOR . BASE_PATH_CLI); |
|
23 | + define('BASE_PATH_CLI', dirname(__FILE__)."/"); |
|
24 | + set_include_path(get_include_path().PATH_SEPARATOR.BASE_PATH_CLI); |
|
25 | 25 | |
26 | 26 | if (!defined('GSYNC_CONFIG')) { |
27 | - define('GSYNC_CONFIG', BASE_PATH_CLI . 'config.php'); |
|
27 | + define('GSYNC_CONFIG', BASE_PATH_CLI.'config.php'); |
|
28 | 28 | } |
29 | 29 | |
30 | 30 | include_once GSYNC_CONFIG; |
@@ -59,7 +59,7 @@ discard block |
||
59 | 59 | } |
60 | 60 | } |
61 | 61 | catch (GSyncException $zpe) { |
62 | - fwrite(STDERR, get_class($zpe) . ": " . $zpe->getMessage() . "\n"); |
|
62 | + fwrite(STDERR, get_class($zpe).": ".$zpe->getMessage()."\n"); |
|
63 | 63 | |
64 | 64 | exit(1); |
65 | 65 | } |
@@ -259,13 +259,13 @@ discard block |
||
259 | 259 | |
260 | 260 | $lastUpdate = $this->currenttime - $line["update"]; |
261 | 261 | if ($this->currenttime - $line["update"] < 2) { |
262 | - $this->linesActive[$line["update"] . $line["pid"]] = $line; |
|
262 | + $this->linesActive[$line["update"].$line["pid"]] = $line; |
|
263 | 263 | } |
264 | 264 | elseif (($line['push'] === true && $lastUpdate > ($this->pingInterval + 2)) || ($line['push'] !== true && $lastUpdate > 4)) { |
265 | - $this->linesUnknown[$line["update"] . $line["pid"]] = $line; |
|
265 | + $this->linesUnknown[$line["update"].$line["pid"]] = $line; |
|
266 | 266 | } |
267 | 267 | else { |
268 | - $this->linesOpen[$line["update"] . $line["pid"]] = $line; |
|
268 | + $this->linesOpen[$line["update"].$line["pid"]] = $line; |
|
269 | 269 | } |
270 | 270 | } |
271 | 271 | else { |
@@ -291,7 +291,7 @@ discard block |
||
291 | 291 | } |
292 | 292 | |
293 | 293 | $line['time'] = $line['ended'] - $line['start']; |
294 | - $this->linesTerm[$line['update'] . $line['pid']] = $line; |
|
294 | + $this->linesTerm[$line['update'].$line['pid']] = $line; |
|
295 | 295 | } |
296 | 296 | } |
297 | 297 | } |
@@ -312,7 +312,7 @@ discard block |
||
312 | 312 | private function scrOverview() { |
313 | 313 | $linesAvail = $this->scrSize['height'] - 8; |
314 | 314 | $lc = 1; |
315 | - $this->scrPrintAt($lc, 0, "\033[1mgrommunio-sync-top live statistics\033[0m\t\t\t\t\t" . @strftime("%d/%m/%Y %T") . "\n"); |
|
315 | + $this->scrPrintAt($lc, 0, "\033[1mgrommunio-sync-top live statistics\033[0m\t\t\t\t\t".@strftime("%d/%m/%Y %T")."\n"); |
|
316 | 316 | ++$lc; |
317 | 317 | |
318 | 318 | $this->scrPrintAt($lc, 0, sprintf("Open connections: %d\t\t\t\tUsers:\t %d\tgrommunio-sync: %s ", count($this->activeConn), count($this->activeUsers), $this->getVersion())); |
@@ -323,7 +323,7 @@ discard block |
||
323 | 323 | ++$lc; |
324 | 324 | ++$lc; |
325 | 325 | |
326 | - $this->scrPrintAt($lc, 0, "\033[4m" . $this->getLine(['pid' => 'PID', 'ip' => 'IP', 'user' => 'USER', 'command' => 'COMMAND', 'time' => 'TIME', 'devagent' => 'AGENT', 'devid' => 'DEVID', 'addinfo' => 'Additional Information']) . str_repeat(" ", 20) . "\033[0m"); |
|
326 | + $this->scrPrintAt($lc, 0, "\033[4m".$this->getLine(['pid' => 'PID', 'ip' => 'IP', 'user' => 'USER', 'command' => 'COMMAND', 'time' => 'TIME', 'devagent' => 'AGENT', 'devid' => 'DEVID', 'addinfo' => 'Additional Information']).str_repeat(" ", 20)."\033[0m"); |
|
327 | 327 | ++$lc; |
328 | 328 | |
329 | 329 | // print help text if requested |
@@ -371,7 +371,7 @@ discard block |
||
371 | 371 | break; |
372 | 372 | } |
373 | 373 | |
374 | - $this->scrPrintAt($lc, 0, "\033[01m" . $this->getLine($l) . "\033[0m"); |
|
374 | + $this->scrPrintAt($lc, 0, "\033[01m".$this->getLine($l)."\033[0m"); |
|
375 | 375 | ++$lc; |
376 | 376 | ++$linesprinted; |
377 | 377 | } |
@@ -397,7 +397,7 @@ discard block |
||
397 | 397 | if ($l['push'] == false && $time - $l["start"] > 30) { |
398 | 398 | $color = "1;31m"; |
399 | 399 | } |
400 | - $this->scrPrintAt($lc, 0, "\033[0" . $color . $this->getLine($l) . "\033[0m"); |
|
400 | + $this->scrPrintAt($lc, 0, "\033[0".$color.$this->getLine($l)."\033[0m"); |
|
401 | 401 | ++$lc; |
402 | 402 | ++$linesprinted; |
403 | 403 | } |
@@ -412,7 +412,7 @@ discard block |
||
412 | 412 | break; |
413 | 413 | } |
414 | 414 | |
415 | - $this->scrPrintAt($lc, 0, "\033[01;30m" . $this->getLine($l) . "\033[0m"); |
|
415 | + $this->scrPrintAt($lc, 0, "\033[01;30m".$this->getLine($l)."\033[0m"); |
|
416 | 416 | ++$lc; |
417 | 417 | ++$linesprinted; |
418 | 418 | } |
@@ -430,7 +430,7 @@ discard block |
||
430 | 430 | |
431 | 431 | // show request information and help command |
432 | 432 | if ($this->starttime + 6 > $this->currenttime) { |
433 | - $this->status = sprintf("Requesting information (takes up to %dsecs)", $this->pingInterval) . str_repeat(".", ($this->currenttime - $this->starttime)) . " type \033[01;31mh\033[00;31m or \033[01;31mhelp\033[00;31m for usage instructions"; |
|
433 | + $this->status = sprintf("Requesting information (takes up to %dsecs)", $this->pingInterval).str_repeat(".", ($this->currenttime - $this->starttime))." type \033[01;31mh\033[00;31m or \033[01;31mhelp\033[00;31m for usage instructions"; |
|
434 | 434 | $this->statusexpire = $this->currenttime + 1; |
435 | 435 | } |
436 | 436 | |
@@ -448,7 +448,7 @@ discard block |
||
448 | 448 | } |
449 | 449 | |
450 | 450 | if ($this->showTermSec != self::SHOW_TERM_DEFAULT_TIME) { |
451 | - $str .= "\033[01;32mTerminated: " . $this->showTermSec . "s\033[0m "; |
|
451 | + $str .= "\033[01;32mTerminated: ".$this->showTermSec."s\033[0m "; |
|
452 | 452 | } |
453 | 453 | |
454 | 454 | if ($this->filter !== false || ($this->status !== false && $this->statusexpire > $this->currenttime)) { |
@@ -463,7 +463,7 @@ discard block |
||
463 | 463 | } |
464 | 464 | $this->scrPrintAt(5, 0, $str); |
465 | 465 | |
466 | - $this->scrPrintAt(4, 0, "Action: \033[01m" . $this->action . "\033[0m"); |
|
466 | + $this->scrPrintAt(4, 0, "Action: \033[01m".$this->action."\033[0m"); |
|
467 | 467 | } |
468 | 468 | |
469 | 469 | /** |
@@ -553,10 +553,10 @@ discard block |
||
553 | 553 | // grep the log file |
554 | 554 | elseif (($cmds[0] == "log" || $cmds[0] == "l") && isset($cmds[1])) { |
555 | 555 | if (!file_exists(LOGFILE)) { |
556 | - $this->status = "Logfile can not be found: " . LOGFILE; |
|
556 | + $this->status = "Logfile can not be found: ".LOGFILE; |
|
557 | 557 | } |
558 | 558 | else { |
559 | - system('bash -c "fgrep -a ' . escapeshellarg($cmds[1]) . ' ' . LOGFILE . ' | less +G" > `tty`'); |
|
559 | + system('bash -c "fgrep -a '.escapeshellarg($cmds[1]).' '.LOGFILE.' | less +G" > `tty`'); |
|
560 | 560 | $this->status = "Returning from log, updating data"; |
561 | 561 | } |
562 | 562 | $this->statusexpire = time() + 5; // it might be much "later" now |
@@ -564,7 +564,7 @@ discard block |
||
564 | 564 | // tail the log file |
565 | 565 | elseif (($cmds[0] == "tail" || $cmds[0] == "t")) { |
566 | 566 | if (!file_exists(LOGFILE)) { |
567 | - $this->status = "Logfile can not be found: " . LOGFILE; |
|
567 | + $this->status = "Logfile can not be found: ".LOGFILE; |
|
568 | 568 | } |
569 | 569 | else { |
570 | 570 | $this->doingTail = true; |
@@ -572,9 +572,9 @@ discard block |
||
572 | 572 | $this->scrPrintAt(1, 0, $this->scrAsBold("Press CTRL+C to return to grommunio-sync-top\n\n")); |
573 | 573 | $secondary = ""; |
574 | 574 | if (isset($cmds[1])) { |
575 | - $secondary = " -n 200 | grep " . escapeshellarg($cmds[1]); |
|
575 | + $secondary = " -n 200 | grep ".escapeshellarg($cmds[1]); |
|
576 | 576 | } |
577 | - system('bash -c "tail -f ' . LOGFILE . $secondary . '" > `tty`'); |
|
577 | + system('bash -c "tail -f '.LOGFILE.$secondary.'" > `tty`'); |
|
578 | 578 | $this->doingTail = false; |
579 | 579 | $this->status = "Returning from tail, updating data"; |
580 | 580 | } |
@@ -583,7 +583,7 @@ discard block |
||
583 | 583 | // tail the error log file |
584 | 584 | elseif (($cmds[0] == "error" || $cmds[0] == "e")) { |
585 | 585 | if (!file_exists(LOGERRORFILE)) { |
586 | - $this->status = "Error logfile can not be found: " . LOGERRORFILE; |
|
586 | + $this->status = "Error logfile can not be found: ".LOGERRORFILE; |
|
587 | 587 | } |
588 | 588 | else { |
589 | 589 | $this->doingTail = true; |
@@ -591,9 +591,9 @@ discard block |
||
591 | 591 | $this->scrPrintAt(1, 0, $this->scrAsBold("Press CTRL+C to return to grommunio-sync-top\n\n")); |
592 | 592 | $secondary = ""; |
593 | 593 | if (isset($cmds[1])) { |
594 | - $secondary = " -n 200 | grep " . escapeshellarg($cmds[1]); |
|
594 | + $secondary = " -n 200 | grep ".escapeshellarg($cmds[1]); |
|
595 | 595 | } |
596 | - system('bash -c "tail -f ' . LOGERRORFILE . $secondary . '" > `tty`'); |
|
596 | + system('bash -c "tail -f '.LOGERRORFILE.$secondary.'" > `tty`'); |
|
597 | 597 | $this->doingTail = false; |
598 | 598 | $this->status = "Returning from tail, updating data"; |
599 | 599 | } |
@@ -630,9 +630,9 @@ discard block |
||
630 | 630 | * @return string |
631 | 631 | */ |
632 | 632 | public function UsageInstructions() { |
633 | - $help = "Usage:\n\tgrommunio-sync-top.php\n\n" . |
|
634 | - " grommunio-sync-top is a live top-like overview of what grommunio-sync is doing. It does not have specific command line options.\n\n" . |
|
635 | - " When grommunio-sync-top is running you can specify certain actions and options which can be executed (listed below).\n" . |
|
633 | + $help = "Usage:\n\tgrommunio-sync-top.php\n\n". |
|
634 | + " grommunio-sync-top is a live top-like overview of what grommunio-sync is doing. It does not have specific command line options.\n\n". |
|
635 | + " When grommunio-sync-top is running you can specify certain actions and options which can be executed (listed below).\n". |
|
636 | 636 | " This help information can also be shown inside grommunio-sync-top by hitting 'help' or 'h'.\n\n"; |
637 | 637 | $scrhelp = $this->scrHelp(); |
638 | 638 | unset($scrhelp[0]); |
@@ -651,23 +651,23 @@ discard block |
||
651 | 651 | private function scrHelp() { |
652 | 652 | $h = []; |
653 | 653 | $secs = $this->helpexpire - $this->currenttime; |
654 | - $h[] = "Actions supported by grommunio-sync-top (help page still displayed for " . $secs . "secs)"; |
|
655 | - $h[] = " " . $this->scrAsBold("Action") . "\t\t" . $this->scrAsBold("Comment"); |
|
656 | - $h[] = " " . $this->scrAsBold("h") . " or " . $this->scrAsBold("help") . "\t\tDisplays this information."; |
|
657 | - $h[] = " " . $this->scrAsBold("q") . ", " . $this->scrAsBold("quit") . " or " . $this->scrAsBold(":q") . "\t\tExits grommunio-sync-top."; |
|
658 | - $h[] = " " . $this->scrAsBold("w") . " or " . $this->scrAsBold("wide") . "\t\tTries not to truncate data. Automatically done if more than 180 columns available."; |
|
659 | - $h[] = " " . $this->scrAsBold("f:VAL") . " or " . $this->scrAsBold("filter:VAL") . "\tOnly display connections which contain VAL. This value is case-insensitive."; |
|
660 | - $h[] = " " . $this->scrAsBold("f:") . " or " . $this->scrAsBold("filter:") . "\t\tWithout a search word: resets the filter."; |
|
661 | - $h[] = " " . $this->scrAsBold("l:STR") . " or " . $this->scrAsBold("log:STR") . "\tIssues 'less +G' on the logfile, after grepping on the optional STR."; |
|
662 | - $h[] = " " . $this->scrAsBold("t:STR") . " or " . $this->scrAsBold("tail:STR") . "\tIssues 'tail -f' on the logfile, grepping for optional STR."; |
|
663 | - $h[] = " " . $this->scrAsBold("e:STR") . " or " . $this->scrAsBold("error:STR") . "\tIssues 'tail -f' on the error logfile, grepping for optional STR."; |
|
664 | - $h[] = " " . $this->scrAsBold("r") . " or " . $this->scrAsBold("reset") . "\t\tResets 'wide' or 'filter'."; |
|
665 | - $h[] = " " . $this->scrAsBold("o:") . " or " . $this->scrAsBold("option:") . "\t\tSets display options. Valid options specified below"; |
|
666 | - $h[] = " " . $this->scrAsBold(" p") . " or " . $this->scrAsBold("push") . "\t\tLists/not lists active and open push connections."; |
|
667 | - $h[] = " " . $this->scrAsBold(" a") . " or " . $this->scrAsBold("action") . "\t\tLists only active connections."; |
|
668 | - $h[] = " " . $this->scrAsBold(" u") . " or " . $this->scrAsBold("unknown") . "\tLists only unknown connections."; |
|
669 | - $h[] = " " . $this->scrAsBold(" 10") . " or " . $this->scrAsBold("20") . "\t\tLists terminated connections for 10 or 20 seconds. Any other number can be used."; |
|
670 | - $h[] = " " . $this->scrAsBold(" d") . " or " . $this->scrAsBold("default") . "\tUses default options"; |
|
654 | + $h[] = "Actions supported by grommunio-sync-top (help page still displayed for ".$secs."secs)"; |
|
655 | + $h[] = " ".$this->scrAsBold("Action")."\t\t".$this->scrAsBold("Comment"); |
|
656 | + $h[] = " ".$this->scrAsBold("h")." or ".$this->scrAsBold("help")."\t\tDisplays this information."; |
|
657 | + $h[] = " ".$this->scrAsBold("q").", ".$this->scrAsBold("quit")." or ".$this->scrAsBold(":q")."\t\tExits grommunio-sync-top."; |
|
658 | + $h[] = " ".$this->scrAsBold("w")." or ".$this->scrAsBold("wide")."\t\tTries not to truncate data. Automatically done if more than 180 columns available."; |
|
659 | + $h[] = " ".$this->scrAsBold("f:VAL")." or ".$this->scrAsBold("filter:VAL")."\tOnly display connections which contain VAL. This value is case-insensitive."; |
|
660 | + $h[] = " ".$this->scrAsBold("f:")." or ".$this->scrAsBold("filter:")."\t\tWithout a search word: resets the filter."; |
|
661 | + $h[] = " ".$this->scrAsBold("l:STR")." or ".$this->scrAsBold("log:STR")."\tIssues 'less +G' on the logfile, after grepping on the optional STR."; |
|
662 | + $h[] = " ".$this->scrAsBold("t:STR")." or ".$this->scrAsBold("tail:STR")."\tIssues 'tail -f' on the logfile, grepping for optional STR."; |
|
663 | + $h[] = " ".$this->scrAsBold("e:STR")." or ".$this->scrAsBold("error:STR")."\tIssues 'tail -f' on the error logfile, grepping for optional STR."; |
|
664 | + $h[] = " ".$this->scrAsBold("r")." or ".$this->scrAsBold("reset")."\t\tResets 'wide' or 'filter'."; |
|
665 | + $h[] = " ".$this->scrAsBold("o:")." or ".$this->scrAsBold("option:")."\t\tSets display options. Valid options specified below"; |
|
666 | + $h[] = " ".$this->scrAsBold(" p")." or ".$this->scrAsBold("push")."\t\tLists/not lists active and open push connections."; |
|
667 | + $h[] = " ".$this->scrAsBold(" a")." or ".$this->scrAsBold("action")."\t\tLists only active connections."; |
|
668 | + $h[] = " ".$this->scrAsBold(" u")." or ".$this->scrAsBold("unknown")."\tLists only unknown connections."; |
|
669 | + $h[] = " ".$this->scrAsBold(" 10")." or ".$this->scrAsBold("20")."\t\tLists terminated connections for 10 or 20 seconds. Any other number can be used."; |
|
670 | + $h[] = " ".$this->scrAsBold(" d")." or ".$this->scrAsBold("default")."\tUses default options"; |
|
671 | 671 | |
672 | 672 | return $h; |
673 | 673 | } |
@@ -680,7 +680,7 @@ discard block |
||
680 | 680 | * @return string same text as bold |
681 | 681 | */ |
682 | 682 | private function scrAsBold($text) { |
683 | - return "\033[01m" . $text . "\033[0m"; |
|
683 | + return "\033[01m".$text."\033[0m"; |
|
684 | 684 | } |
685 | 685 | |
686 | 686 | /** |
@@ -715,10 +715,10 @@ discard block |
||
715 | 715 | if ($cutmiddle == true) { |
716 | 716 | $cut = ($size - 2) / 2; |
717 | 717 | |
718 | - return $this->ptStr(substr($str, 0, $cut) . ".." . substr($str, (-1) * ($cut - 1)), $size); |
|
718 | + return $this->ptStr(substr($str, 0, $cut)."..".substr($str, (-1) * ($cut - 1)), $size); |
|
719 | 719 | } |
720 | 720 | |
721 | - return substr($str, 0, $size - 3) . ".. "; |
|
721 | + return substr($str, 0, $size - 3).".. "; |
|
722 | 722 | } |
723 | 723 | |
724 | 724 | /** |
@@ -790,6 +790,6 @@ discard block |
||
790 | 790 | * @return |
791 | 791 | */ |
792 | 792 | private function scrPrintAt($row, $col, $text = "") { |
793 | - echo "\033[" . $row . ";" . $col . "H" . $text; |
|
793 | + echo "\033[".$row.";".$col."H".$text; |
|
794 | 794 | } |
795 | 795 | } |
@@ -53,12 +53,10 @@ discard block |
||
53 | 53 | $zpt->run(); |
54 | 54 | $zpt->scrClear(); |
55 | 55 | system("stty sane"); |
56 | - } |
|
57 | - else { |
|
56 | + } else { |
|
58 | 57 | echo "grommunio-sync interprocess communication (IPC) is not available or TopCollector is disabled.\n"; |
59 | 58 | } |
60 | - } |
|
61 | - catch (GSyncException $zpe) { |
|
59 | + } catch (GSyncException $zpe) { |
|
62 | 60 | fwrite(STDERR, get_class($zpe) . ": " . $zpe->getMessage() . "\n"); |
63 | 61 | |
64 | 62 | exit(1); |
@@ -173,8 +171,7 @@ discard block |
||
173 | 171 | if ($this->scrSize['width'] != $s['width']) { |
174 | 172 | if ($s['width'] > 180) { |
175 | 173 | $this->wide = true; |
176 | - } |
|
177 | - else { |
|
174 | + } else { |
|
178 | 175 | $this->wide = false; |
179 | 176 | } |
180 | 177 | } |
@@ -260,15 +257,12 @@ discard block |
||
260 | 257 | $lastUpdate = $this->currenttime - $line["update"]; |
261 | 258 | if ($this->currenttime - $line["update"] < 2) { |
262 | 259 | $this->linesActive[$line["update"] . $line["pid"]] = $line; |
263 | - } |
|
264 | - elseif (($line['push'] === true && $lastUpdate > ($this->pingInterval + 2)) || ($line['push'] !== true && $lastUpdate > 4)) { |
|
260 | + } elseif (($line['push'] === true && $lastUpdate > ($this->pingInterval + 2)) || ($line['push'] !== true && $lastUpdate > 4)) { |
|
265 | 261 | $this->linesUnknown[$line["update"] . $line["pid"]] = $line; |
266 | - } |
|
267 | - else { |
|
262 | + } else { |
|
268 | 263 | $this->linesOpen[$line["update"] . $line["pid"]] = $line; |
269 | 264 | } |
270 | - } |
|
271 | - else { |
|
265 | + } else { |
|
272 | 266 | // do not show terminated + expired connections |
273 | 267 | if ($this->currenttime > $line['ended'] + $this->showTermSec) { |
274 | 268 | continue; |
@@ -490,51 +484,40 @@ discard block |
||
490 | 484 | $this->topCollector->ClearLatest(true); |
491 | 485 | |
492 | 486 | $this->terminate = true; |
493 | - } |
|
494 | - elseif ($cmds[0] == "clear") { |
|
487 | + } elseif ($cmds[0] == "clear") { |
|
495 | 488 | $this->topCollector->ClearLatest(true); |
496 | 489 | $this->topCollector->CollectData(true); |
497 | 490 | $this->topCollector->ReInitIPC(); |
498 | - } |
|
499 | - elseif ($cmds[0] == "filter" || $cmds[0] == "f") { |
|
491 | + } elseif ($cmds[0] == "filter" || $cmds[0] == "f") { |
|
500 | 492 | if (!isset($cmds[1]) || $cmds[1] == "") { |
501 | 493 | $this->filter = false; |
502 | 494 | $this->status = "No filter"; |
503 | 495 | $this->statusexpire = $this->currenttime + 5; |
504 | - } |
|
505 | - else { |
|
496 | + } else { |
|
506 | 497 | $this->filter = $cmds[1]; |
507 | 498 | $this->status = false; |
508 | 499 | } |
509 | - } |
|
510 | - elseif ($cmds[0] == "option" || $cmds[0] == "o") { |
|
500 | + } elseif ($cmds[0] == "option" || $cmds[0] == "o") { |
|
511 | 501 | if (!isset($cmds[1]) || $cmds[1] == "") { |
512 | 502 | $this->status = "Option value needs to be specified. See 'help' or 'h' for instructions"; |
513 | 503 | $this->statusexpire = $this->currenttime + 5; |
514 | - } |
|
515 | - elseif ($cmds[1] == "p" || $cmds[1] == "push" || $cmds[1] == "ping") { |
|
504 | + } elseif ($cmds[1] == "p" || $cmds[1] == "push" || $cmds[1] == "ping") { |
|
516 | 505 | $this->showPush = !$this->showPush; |
517 | - } |
|
518 | - elseif ($cmds[1] == "a" || $cmds[1] == "active") { |
|
506 | + } elseif ($cmds[1] == "a" || $cmds[1] == "active") { |
|
519 | 507 | $this->showOption = self::SHOW_ACTIVE_ONLY; |
520 | - } |
|
521 | - elseif ($cmds[1] == "u" || $cmds[1] == "unknown") { |
|
508 | + } elseif ($cmds[1] == "u" || $cmds[1] == "unknown") { |
|
522 | 509 | $this->showOption = self::SHOW_UNKNOWN_ONLY; |
523 | - } |
|
524 | - elseif ($cmds[1] == "d" || $cmds[1] == "default") { |
|
510 | + } elseif ($cmds[1] == "d" || $cmds[1] == "default") { |
|
525 | 511 | $this->showOption = self::SHOW_DEFAULT; |
526 | 512 | $this->showTermSec = self::SHOW_TERM_DEFAULT_TIME; |
527 | 513 | $this->showPush = true; |
528 | - } |
|
529 | - elseif (is_numeric($cmds[1])) { |
|
514 | + } elseif (is_numeric($cmds[1])) { |
|
530 | 515 | $this->showTermSec = $cmds[1]; |
531 | - } |
|
532 | - else { |
|
516 | + } else { |
|
533 | 517 | $this->status = sprintf("Option '%s' unknown", $cmds[1]); |
534 | 518 | $this->statusexpire = $this->currenttime + 5; |
535 | 519 | } |
536 | - } |
|
537 | - elseif ($cmds[0] == "reset" || $cmds[0] == "r") { |
|
520 | + } elseif ($cmds[0] == "reset" || $cmds[0] == "r") { |
|
538 | 521 | $this->filter = false; |
539 | 522 | $this->wide = false; |
540 | 523 | $this->helpexpire = 0; |
@@ -546,16 +529,14 @@ discard block |
||
546 | 529 | $this->wide = !$this->wide; |
547 | 530 | $this->status = ($this->wide) ? "w i d e view" : "normal view"; |
548 | 531 | $this->statusexpire = $this->currenttime + 2; |
549 | - } |
|
550 | - elseif ($cmds[0] == "help" || $cmds[0] == "h") { |
|
532 | + } elseif ($cmds[0] == "help" || $cmds[0] == "h") { |
|
551 | 533 | $this->helpexpire = $this->currenttime + 20; |
552 | 534 | } |
553 | 535 | // grep the log file |
554 | 536 | elseif (($cmds[0] == "log" || $cmds[0] == "l") && isset($cmds[1])) { |
555 | 537 | if (!file_exists(LOGFILE)) { |
556 | 538 | $this->status = "Logfile can not be found: " . LOGFILE; |
557 | - } |
|
558 | - else { |
|
539 | + } else { |
|
559 | 540 | system('bash -c "fgrep -a ' . escapeshellarg($cmds[1]) . ' ' . LOGFILE . ' | less +G" > `tty`'); |
560 | 541 | $this->status = "Returning from log, updating data"; |
561 | 542 | } |
@@ -565,8 +546,7 @@ discard block |
||
565 | 546 | elseif (($cmds[0] == "tail" || $cmds[0] == "t")) { |
566 | 547 | if (!file_exists(LOGFILE)) { |
567 | 548 | $this->status = "Logfile can not be found: " . LOGFILE; |
568 | - } |
|
569 | - else { |
|
549 | + } else { |
|
570 | 550 | $this->doingTail = true; |
571 | 551 | $this->scrClear(); |
572 | 552 | $this->scrPrintAt(1, 0, $this->scrAsBold("Press CTRL+C to return to grommunio-sync-top\n\n")); |
@@ -584,8 +564,7 @@ discard block |
||
584 | 564 | elseif (($cmds[0] == "error" || $cmds[0] == "e")) { |
585 | 565 | if (!file_exists(LOGERRORFILE)) { |
586 | 566 | $this->status = "Error logfile can not be found: " . LOGERRORFILE; |
587 | - } |
|
588 | - else { |
|
567 | + } else { |
|
589 | 568 | $this->doingTail = true; |
590 | 569 | $this->scrClear(); |
591 | 570 | $this->scrPrintAt(1, 0, $this->scrAsBold("Press CTRL+C to return to grommunio-sync-top\n\n")); |
@@ -598,8 +577,7 @@ discard block |
||
598 | 577 | $this->status = "Returning from tail, updating data"; |
599 | 578 | } |
600 | 579 | $this->statusexpire = time() + 5; // it might be much "later" now |
601 | - } |
|
602 | - elseif ($cmds[0] != "") { |
|
580 | + } elseif ($cmds[0] != "") { |
|
603 | 581 | $this->status = sprintf("Command '%s' unknown", $cmds[0]); |
604 | 582 | $this->statusexpire = $this->currenttime + 8; |
605 | 583 | } |
@@ -8,216 +8,216 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class Settings extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the Settings command. |
|
13 | - * |
|
14 | - * @param int $commandCode |
|
15 | - * |
|
16 | - * @return bool |
|
17 | - */ |
|
18 | - public function Handle($commandCode) { |
|
19 | - if (!self::$decoder->getElementStartTag(SYNC_SETTINGS_SETTINGS)) { |
|
20 | - return false; |
|
21 | - } |
|
22 | - |
|
23 | - // save the request parameters |
|
24 | - $request = []; |
|
25 | - |
|
26 | - // Loop through properties. Possible are: |
|
27 | - // - Out of office |
|
28 | - // - DevicePassword |
|
29 | - // - DeviceInformation |
|
30 | - // - UserInformation |
|
31 | - // Each of them should only be once per request. Each property must be processed in order. |
|
32 | - WBXMLDecoder::ResetInWhile("settingsMain"); |
|
33 | - while (WBXMLDecoder::InWhile("settingsMain")) { |
|
34 | - $propertyName = ""; |
|
35 | - if (self::$decoder->getElementStartTag(SYNC_SETTINGS_OOF)) { |
|
36 | - $propertyName = SYNC_SETTINGS_OOF; |
|
37 | - } |
|
38 | - if (self::$decoder->getElementStartTag(SYNC_SETTINGS_DEVICEPW)) { |
|
39 | - $propertyName = SYNC_SETTINGS_DEVICEPW; |
|
40 | - } |
|
41 | - if (self::$decoder->getElementStartTag(SYNC_SETTINGS_DEVICEINFORMATION)) { |
|
42 | - $propertyName = SYNC_SETTINGS_DEVICEINFORMATION; |
|
43 | - } |
|
44 | - if (self::$decoder->getElementStartTag(SYNC_SETTINGS_USERINFORMATION)) { |
|
45 | - $propertyName = SYNC_SETTINGS_USERINFORMATION; |
|
46 | - } |
|
47 | - if (self::$decoder->getElementStartTag(SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION)) { |
|
48 | - $propertyName = SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION; |
|
49 | - } |
|
50 | - // TODO - check if it is necessary |
|
51 | - // no property name available - break |
|
52 | - if (!$propertyName) { |
|
53 | - break; |
|
54 | - } |
|
55 | - |
|
56 | - // the property name is followed by either get or set |
|
57 | - if (self::$decoder->getElementStartTag(SYNC_SETTINGS_GET)) { |
|
58 | - // get is available for OOF (AS 12), user information (AS 12) and rights management (AS 14.1) |
|
59 | - switch ($propertyName) { |
|
60 | - case SYNC_SETTINGS_OOF: |
|
61 | - $oofGet = new SyncOOF(); |
|
62 | - $oofGet->Decode(self::$decoder); |
|
63 | - if (!self::$decoder->getElementEndTag()) { |
|
64 | - return false; |
|
65 | - } // SYNC_SETTINGS_GET |
|
66 | - break; |
|
67 | - |
|
68 | - case SYNC_SETTINGS_USERINFORMATION: |
|
69 | - $userInformation = new SyncUserInformation(); |
|
70 | - break; |
|
71 | - |
|
72 | - case SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION: |
|
73 | - $rmTemplates = new SyncRightsManagementTemplates(); |
|
74 | - break; |
|
75 | - |
|
76 | - default: |
|
77 | - // TODO: a special status code needed? |
|
78 | - SLog::Write(LOGLEVEL_WARN, sprintf("This property ('%s') is not allowed to use get in request", $propertyName)); |
|
79 | - } |
|
80 | - } |
|
81 | - elseif (self::$decoder->getElementStartTag(SYNC_SETTINGS_SET)) { |
|
82 | - // set is available for OOF, device password and device information |
|
83 | - switch ($propertyName) { |
|
84 | - case SYNC_SETTINGS_OOF: |
|
85 | - $oofSet = new SyncOOF(); |
|
86 | - $oofSet->Decode(self::$decoder); |
|
87 | - // TODO check - do it after while(1) finished? |
|
88 | - break; |
|
89 | - |
|
90 | - case SYNC_SETTINGS_DEVICEPW: |
|
91 | - // TODO device password |
|
92 | - $devicepassword = new SyncDevicePassword(); |
|
93 | - $devicepassword->Decode(self::$decoder); |
|
94 | - break; |
|
95 | - |
|
96 | - case SYNC_SETTINGS_DEVICEINFORMATION: |
|
97 | - $deviceinformation = new SyncDeviceInformation(); |
|
98 | - $deviceinformation->Decode(self::$decoder); |
|
99 | - $deviceinformation->Status = SYNC_SETTINGSSTATUS_SUCCESS; |
|
100 | - self::$deviceManager->SaveDeviceInformation($deviceinformation); |
|
101 | - break; |
|
102 | - |
|
103 | - default: |
|
104 | - // TODO: a special status code needed? |
|
105 | - SLog::Write(LOGLEVEL_WARN, sprintf("This property ('%s') is not allowed to use set in request", $propertyName)); |
|
106 | - } |
|
107 | - |
|
108 | - if (!self::$decoder->getElementEndTag()) { |
|
109 | - return false; |
|
110 | - } // SYNC_SETTINGS_SET |
|
111 | - } |
|
112 | - else { |
|
113 | - SLog::Write(LOGLEVEL_WARN, sprintf("Neither get nor set found for property '%s'", $propertyName)); |
|
114 | - |
|
115 | - return false; |
|
116 | - } |
|
117 | - |
|
118 | - if (!self::$decoder->getElementEndTag()) { |
|
119 | - return false; |
|
120 | - } // SYNC_SETTINGS_OOF or SYNC_SETTINGS_DEVICEPW or SYNC_SETTINGS_DEVICEINFORMATION or SYNC_SETTINGS_USERINFORMATION |
|
121 | - |
|
122 | - // break if it reached the endtag |
|
123 | - $e = self::$decoder->peek(); |
|
124 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
125 | - self::$decoder->getElementEndTag(); // SYNC_SETTINGS_SETTINGS |
|
126 | - |
|
127 | - break; |
|
128 | - } |
|
129 | - } |
|
130 | - |
|
131 | - $status = SYNC_SETTINGSSTATUS_SUCCESS; |
|
132 | - |
|
133 | - // TODO put it in try catch block |
|
134 | - // TODO implement Settings in the backend |
|
135 | - // TODO save device information in device manager |
|
136 | - // TODO status handling |
|
137 | - // $data = self::$backend->Settings($request); |
|
138 | - |
|
139 | - self::$encoder->startWBXML(); |
|
140 | - self::$encoder->startTag(SYNC_SETTINGS_SETTINGS); |
|
141 | - |
|
142 | - self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
143 | - self::$encoder->content($status); |
|
144 | - self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
145 | - |
|
146 | - // get oof settings |
|
147 | - if (isset($oofGet)) { |
|
148 | - $oofGet = self::$backend->Settings($oofGet); |
|
149 | - self::$encoder->startTag(SYNC_SETTINGS_OOF); |
|
150 | - self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
151 | - self::$encoder->content($oofGet->Status); |
|
152 | - self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
153 | - |
|
154 | - self::$encoder->startTag(SYNC_SETTINGS_GET); |
|
155 | - $oofGet->Encode(self::$encoder); |
|
156 | - self::$encoder->endTag(); // SYNC_SETTINGS_GET |
|
157 | - self::$encoder->endTag(); // SYNC_SETTINGS_OOF |
|
158 | - } |
|
159 | - |
|
160 | - // get user information |
|
161 | - // TODO none email address found |
|
162 | - if (isset($userInformation)) { |
|
163 | - self::$backend->Settings($userInformation); |
|
164 | - self::$encoder->startTag(SYNC_SETTINGS_USERINFORMATION); |
|
165 | - self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
166 | - self::$encoder->content($userInformation->Status); |
|
167 | - self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
168 | - |
|
169 | - self::$encoder->startTag(SYNC_SETTINGS_GET); |
|
170 | - $userInformation->Encode(self::$encoder); |
|
171 | - self::$encoder->endTag(); // SYNC_SETTINGS_GET |
|
172 | - self::$encoder->endTag(); // SYNC_SETTINGS_USERINFORMATION |
|
173 | - } |
|
174 | - |
|
175 | - // get rights management templates |
|
176 | - if (isset($rmTemplates)) { |
|
177 | - self::$backend->Settings($rmTemplates); |
|
178 | - self::$encoder->startTag(SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION); |
|
179 | - self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
180 | - self::$encoder->content($rmTemplates->Status); |
|
181 | - self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
182 | - |
|
183 | - self::$encoder->startTag(SYNC_SETTINGS_GET); |
|
184 | - $rmTemplates->Encode(self::$encoder); |
|
185 | - self::$encoder->endTag(); // SYNC_SETTINGS_GET |
|
186 | - self::$encoder->endTag(); // SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION |
|
187 | - } |
|
188 | - |
|
189 | - // set out of office |
|
190 | - if (isset($oofSet)) { |
|
191 | - $oofSet = self::$backend->Settings($oofSet); |
|
192 | - self::$encoder->startTag(SYNC_SETTINGS_OOF); |
|
193 | - self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
194 | - self::$encoder->content($oofSet->Status); |
|
195 | - self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
196 | - self::$encoder->endTag(); // SYNC_SETTINGS_OOF |
|
197 | - } |
|
198 | - |
|
199 | - // set device passwort |
|
200 | - if (isset($devicepassword)) { |
|
201 | - self::$encoder->startTag(SYNC_SETTINGS_DEVICEPW); |
|
202 | - self::$encoder->startTag(SYNC_SETTINGS_SET); |
|
203 | - self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
204 | - self::$encoder->content($devicepassword->Status); |
|
205 | - self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
206 | - self::$encoder->endTag(); // SYNC_SETTINGS_SET |
|
207 | - self::$encoder->endTag(); // SYNC_SETTINGS_DEVICEPW |
|
208 | - } |
|
209 | - |
|
210 | - // set device information |
|
211 | - if (isset($deviceinformation)) { |
|
212 | - self::$encoder->startTag(SYNC_SETTINGS_DEVICEINFORMATION); |
|
213 | - self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
214 | - self::$encoder->content($deviceinformation->Status); |
|
215 | - self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
216 | - self::$encoder->endTag(); // SYNC_SETTINGS_DEVICEINFORMATION |
|
217 | - } |
|
218 | - |
|
219 | - self::$encoder->endTag(); // SYNC_SETTINGS_SETTINGS |
|
220 | - |
|
221 | - return true; |
|
222 | - } |
|
11 | + /** |
|
12 | + * Handles the Settings command. |
|
13 | + * |
|
14 | + * @param int $commandCode |
|
15 | + * |
|
16 | + * @return bool |
|
17 | + */ |
|
18 | + public function Handle($commandCode) { |
|
19 | + if (!self::$decoder->getElementStartTag(SYNC_SETTINGS_SETTINGS)) { |
|
20 | + return false; |
|
21 | + } |
|
22 | + |
|
23 | + // save the request parameters |
|
24 | + $request = []; |
|
25 | + |
|
26 | + // Loop through properties. Possible are: |
|
27 | + // - Out of office |
|
28 | + // - DevicePassword |
|
29 | + // - DeviceInformation |
|
30 | + // - UserInformation |
|
31 | + // Each of them should only be once per request. Each property must be processed in order. |
|
32 | + WBXMLDecoder::ResetInWhile("settingsMain"); |
|
33 | + while (WBXMLDecoder::InWhile("settingsMain")) { |
|
34 | + $propertyName = ""; |
|
35 | + if (self::$decoder->getElementStartTag(SYNC_SETTINGS_OOF)) { |
|
36 | + $propertyName = SYNC_SETTINGS_OOF; |
|
37 | + } |
|
38 | + if (self::$decoder->getElementStartTag(SYNC_SETTINGS_DEVICEPW)) { |
|
39 | + $propertyName = SYNC_SETTINGS_DEVICEPW; |
|
40 | + } |
|
41 | + if (self::$decoder->getElementStartTag(SYNC_SETTINGS_DEVICEINFORMATION)) { |
|
42 | + $propertyName = SYNC_SETTINGS_DEVICEINFORMATION; |
|
43 | + } |
|
44 | + if (self::$decoder->getElementStartTag(SYNC_SETTINGS_USERINFORMATION)) { |
|
45 | + $propertyName = SYNC_SETTINGS_USERINFORMATION; |
|
46 | + } |
|
47 | + if (self::$decoder->getElementStartTag(SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION)) { |
|
48 | + $propertyName = SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION; |
|
49 | + } |
|
50 | + // TODO - check if it is necessary |
|
51 | + // no property name available - break |
|
52 | + if (!$propertyName) { |
|
53 | + break; |
|
54 | + } |
|
55 | + |
|
56 | + // the property name is followed by either get or set |
|
57 | + if (self::$decoder->getElementStartTag(SYNC_SETTINGS_GET)) { |
|
58 | + // get is available for OOF (AS 12), user information (AS 12) and rights management (AS 14.1) |
|
59 | + switch ($propertyName) { |
|
60 | + case SYNC_SETTINGS_OOF: |
|
61 | + $oofGet = new SyncOOF(); |
|
62 | + $oofGet->Decode(self::$decoder); |
|
63 | + if (!self::$decoder->getElementEndTag()) { |
|
64 | + return false; |
|
65 | + } // SYNC_SETTINGS_GET |
|
66 | + break; |
|
67 | + |
|
68 | + case SYNC_SETTINGS_USERINFORMATION: |
|
69 | + $userInformation = new SyncUserInformation(); |
|
70 | + break; |
|
71 | + |
|
72 | + case SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION: |
|
73 | + $rmTemplates = new SyncRightsManagementTemplates(); |
|
74 | + break; |
|
75 | + |
|
76 | + default: |
|
77 | + // TODO: a special status code needed? |
|
78 | + SLog::Write(LOGLEVEL_WARN, sprintf("This property ('%s') is not allowed to use get in request", $propertyName)); |
|
79 | + } |
|
80 | + } |
|
81 | + elseif (self::$decoder->getElementStartTag(SYNC_SETTINGS_SET)) { |
|
82 | + // set is available for OOF, device password and device information |
|
83 | + switch ($propertyName) { |
|
84 | + case SYNC_SETTINGS_OOF: |
|
85 | + $oofSet = new SyncOOF(); |
|
86 | + $oofSet->Decode(self::$decoder); |
|
87 | + // TODO check - do it after while(1) finished? |
|
88 | + break; |
|
89 | + |
|
90 | + case SYNC_SETTINGS_DEVICEPW: |
|
91 | + // TODO device password |
|
92 | + $devicepassword = new SyncDevicePassword(); |
|
93 | + $devicepassword->Decode(self::$decoder); |
|
94 | + break; |
|
95 | + |
|
96 | + case SYNC_SETTINGS_DEVICEINFORMATION: |
|
97 | + $deviceinformation = new SyncDeviceInformation(); |
|
98 | + $deviceinformation->Decode(self::$decoder); |
|
99 | + $deviceinformation->Status = SYNC_SETTINGSSTATUS_SUCCESS; |
|
100 | + self::$deviceManager->SaveDeviceInformation($deviceinformation); |
|
101 | + break; |
|
102 | + |
|
103 | + default: |
|
104 | + // TODO: a special status code needed? |
|
105 | + SLog::Write(LOGLEVEL_WARN, sprintf("This property ('%s') is not allowed to use set in request", $propertyName)); |
|
106 | + } |
|
107 | + |
|
108 | + if (!self::$decoder->getElementEndTag()) { |
|
109 | + return false; |
|
110 | + } // SYNC_SETTINGS_SET |
|
111 | + } |
|
112 | + else { |
|
113 | + SLog::Write(LOGLEVEL_WARN, sprintf("Neither get nor set found for property '%s'", $propertyName)); |
|
114 | + |
|
115 | + return false; |
|
116 | + } |
|
117 | + |
|
118 | + if (!self::$decoder->getElementEndTag()) { |
|
119 | + return false; |
|
120 | + } // SYNC_SETTINGS_OOF or SYNC_SETTINGS_DEVICEPW or SYNC_SETTINGS_DEVICEINFORMATION or SYNC_SETTINGS_USERINFORMATION |
|
121 | + |
|
122 | + // break if it reached the endtag |
|
123 | + $e = self::$decoder->peek(); |
|
124 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
125 | + self::$decoder->getElementEndTag(); // SYNC_SETTINGS_SETTINGS |
|
126 | + |
|
127 | + break; |
|
128 | + } |
|
129 | + } |
|
130 | + |
|
131 | + $status = SYNC_SETTINGSSTATUS_SUCCESS; |
|
132 | + |
|
133 | + // TODO put it in try catch block |
|
134 | + // TODO implement Settings in the backend |
|
135 | + // TODO save device information in device manager |
|
136 | + // TODO status handling |
|
137 | + // $data = self::$backend->Settings($request); |
|
138 | + |
|
139 | + self::$encoder->startWBXML(); |
|
140 | + self::$encoder->startTag(SYNC_SETTINGS_SETTINGS); |
|
141 | + |
|
142 | + self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
143 | + self::$encoder->content($status); |
|
144 | + self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
145 | + |
|
146 | + // get oof settings |
|
147 | + if (isset($oofGet)) { |
|
148 | + $oofGet = self::$backend->Settings($oofGet); |
|
149 | + self::$encoder->startTag(SYNC_SETTINGS_OOF); |
|
150 | + self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
151 | + self::$encoder->content($oofGet->Status); |
|
152 | + self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
153 | + |
|
154 | + self::$encoder->startTag(SYNC_SETTINGS_GET); |
|
155 | + $oofGet->Encode(self::$encoder); |
|
156 | + self::$encoder->endTag(); // SYNC_SETTINGS_GET |
|
157 | + self::$encoder->endTag(); // SYNC_SETTINGS_OOF |
|
158 | + } |
|
159 | + |
|
160 | + // get user information |
|
161 | + // TODO none email address found |
|
162 | + if (isset($userInformation)) { |
|
163 | + self::$backend->Settings($userInformation); |
|
164 | + self::$encoder->startTag(SYNC_SETTINGS_USERINFORMATION); |
|
165 | + self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
166 | + self::$encoder->content($userInformation->Status); |
|
167 | + self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
168 | + |
|
169 | + self::$encoder->startTag(SYNC_SETTINGS_GET); |
|
170 | + $userInformation->Encode(self::$encoder); |
|
171 | + self::$encoder->endTag(); // SYNC_SETTINGS_GET |
|
172 | + self::$encoder->endTag(); // SYNC_SETTINGS_USERINFORMATION |
|
173 | + } |
|
174 | + |
|
175 | + // get rights management templates |
|
176 | + if (isset($rmTemplates)) { |
|
177 | + self::$backend->Settings($rmTemplates); |
|
178 | + self::$encoder->startTag(SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION); |
|
179 | + self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
180 | + self::$encoder->content($rmTemplates->Status); |
|
181 | + self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
182 | + |
|
183 | + self::$encoder->startTag(SYNC_SETTINGS_GET); |
|
184 | + $rmTemplates->Encode(self::$encoder); |
|
185 | + self::$encoder->endTag(); // SYNC_SETTINGS_GET |
|
186 | + self::$encoder->endTag(); // SYNC_SETTINGS_RIGHTSMANAGEMENTINFORMATION |
|
187 | + } |
|
188 | + |
|
189 | + // set out of office |
|
190 | + if (isset($oofSet)) { |
|
191 | + $oofSet = self::$backend->Settings($oofSet); |
|
192 | + self::$encoder->startTag(SYNC_SETTINGS_OOF); |
|
193 | + self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
194 | + self::$encoder->content($oofSet->Status); |
|
195 | + self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
196 | + self::$encoder->endTag(); // SYNC_SETTINGS_OOF |
|
197 | + } |
|
198 | + |
|
199 | + // set device passwort |
|
200 | + if (isset($devicepassword)) { |
|
201 | + self::$encoder->startTag(SYNC_SETTINGS_DEVICEPW); |
|
202 | + self::$encoder->startTag(SYNC_SETTINGS_SET); |
|
203 | + self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
204 | + self::$encoder->content($devicepassword->Status); |
|
205 | + self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
206 | + self::$encoder->endTag(); // SYNC_SETTINGS_SET |
|
207 | + self::$encoder->endTag(); // SYNC_SETTINGS_DEVICEPW |
|
208 | + } |
|
209 | + |
|
210 | + // set device information |
|
211 | + if (isset($deviceinformation)) { |
|
212 | + self::$encoder->startTag(SYNC_SETTINGS_DEVICEINFORMATION); |
|
213 | + self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
214 | + self::$encoder->content($deviceinformation->Status); |
|
215 | + self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
216 | + self::$encoder->endTag(); // SYNC_SETTINGS_DEVICEINFORMATION |
|
217 | + } |
|
218 | + |
|
219 | + self::$encoder->endTag(); // SYNC_SETTINGS_SETTINGS |
|
220 | + |
|
221 | + return true; |
|
222 | + } |
|
223 | 223 | } |
@@ -77,8 +77,7 @@ discard block |
||
77 | 77 | // TODO: a special status code needed? |
78 | 78 | SLog::Write(LOGLEVEL_WARN, sprintf("This property ('%s') is not allowed to use get in request", $propertyName)); |
79 | 79 | } |
80 | - } |
|
81 | - elseif (self::$decoder->getElementStartTag(SYNC_SETTINGS_SET)) { |
|
80 | + } elseif (self::$decoder->getElementStartTag(SYNC_SETTINGS_SET)) { |
|
82 | 81 | // set is available for OOF, device password and device information |
83 | 82 | switch ($propertyName) { |
84 | 83 | case SYNC_SETTINGS_OOF: |
@@ -108,8 +107,7 @@ discard block |
||
108 | 107 | if (!self::$decoder->getElementEndTag()) { |
109 | 108 | return false; |
110 | 109 | } // SYNC_SETTINGS_SET |
111 | - } |
|
112 | - else { |
|
110 | + } else { |
|
113 | 111 | SLog::Write(LOGLEVEL_WARN, sprintf("Neither get nor set found for property '%s'", $propertyName)); |
114 | 112 | |
115 | 113 | return false; |
@@ -8,37 +8,37 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class GetHierarchy extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the GetHierarchy command |
|
13 | - * simply returns current hierarchy of all folders. |
|
14 | - * |
|
15 | - * @param int $commandCode |
|
16 | - * |
|
17 | - * @return bool |
|
18 | - */ |
|
19 | - public function Handle($commandCode) { |
|
20 | - try { |
|
21 | - $folders = self::$backend->GetHierarchy(); |
|
22 | - if (!$folders || empty($folders)) { |
|
23 | - throw new StatusException("GetHierarchy() did not return any data."); |
|
24 | - } |
|
11 | + /** |
|
12 | + * Handles the GetHierarchy command |
|
13 | + * simply returns current hierarchy of all folders. |
|
14 | + * |
|
15 | + * @param int $commandCode |
|
16 | + * |
|
17 | + * @return bool |
|
18 | + */ |
|
19 | + public function Handle($commandCode) { |
|
20 | + try { |
|
21 | + $folders = self::$backend->GetHierarchy(); |
|
22 | + if (!$folders || empty($folders)) { |
|
23 | + throw new StatusException("GetHierarchy() did not return any data."); |
|
24 | + } |
|
25 | 25 | |
26 | - // TODO execute $data->Check() to see if SyncObject is valid |
|
27 | - } |
|
28 | - catch (StatusException $ex) { |
|
29 | - return false; |
|
30 | - } |
|
26 | + // TODO execute $data->Check() to see if SyncObject is valid |
|
27 | + } |
|
28 | + catch (StatusException $ex) { |
|
29 | + return false; |
|
30 | + } |
|
31 | 31 | |
32 | - self::$encoder->StartWBXML(); |
|
33 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERS); |
|
34 | - foreach ($folders as $folder) { |
|
35 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDER); |
|
36 | - $folder->Encode(self::$encoder); |
|
37 | - self::$encoder->endTag(); |
|
38 | - } |
|
39 | - self::$encoder->endTag(); |
|
32 | + self::$encoder->StartWBXML(); |
|
33 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERS); |
|
34 | + foreach ($folders as $folder) { |
|
35 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDER); |
|
36 | + $folder->Encode(self::$encoder); |
|
37 | + self::$encoder->endTag(); |
|
38 | + } |
|
39 | + self::$encoder->endTag(); |
|
40 | 40 | |
41 | - // save hierarchy for upcoming syncing |
|
42 | - return self::$deviceManager->InitializeFolderCache($folders); |
|
43 | - } |
|
41 | + // save hierarchy for upcoming syncing |
|
42 | + return self::$deviceManager->InitializeFolderCache($folders); |
|
43 | + } |
|
44 | 44 | } |
@@ -24,8 +24,7 @@ |
||
24 | 24 | } |
25 | 25 | |
26 | 26 | // TODO execute $data->Check() to see if SyncObject is valid |
27 | - } |
|
28 | - catch (StatusException $ex) { |
|
27 | + } catch (StatusException $ex) { |
|
29 | 28 | return false; |
30 | 29 | } |
31 | 30 |
@@ -8,257 +8,257 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class FolderSync extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the FolderSync command. |
|
13 | - * |
|
14 | - * @param int $commandCode |
|
15 | - * |
|
16 | - * @return bool |
|
17 | - */ |
|
18 | - public function Handle($commandCode) { |
|
19 | - // Parse input |
|
20 | - if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_FOLDERSYNC)) { |
|
21 | - return false; |
|
22 | - } |
|
23 | - |
|
24 | - if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SYNCKEY)) { |
|
25 | - return false; |
|
26 | - } |
|
27 | - |
|
28 | - $synckey = self::$decoder->getElementContent(); |
|
29 | - |
|
30 | - if (!self::$decoder->getElementEndTag()) { |
|
31 | - return false; |
|
32 | - } |
|
33 | - |
|
34 | - // every FolderSync with SyncKey 0 should return the supported AS version & command headers |
|
35 | - if ($synckey == "0") { |
|
36 | - self::$specialHeaders = []; |
|
37 | - self::$specialHeaders[] = GSync::GetSupportedProtocolVersions(); |
|
38 | - self::$specialHeaders[] = GSync::GetSupportedCommands(); |
|
39 | - } |
|
40 | - |
|
41 | - $status = SYNC_FSSTATUS_SUCCESS; |
|
42 | - $newsynckey = $synckey; |
|
43 | - |
|
44 | - try { |
|
45 | - $syncstate = self::$deviceManager->GetStateManager()->GetSyncState($synckey); |
|
46 | - |
|
47 | - // We will be saving the sync state under 'newsynckey' |
|
48 | - $newsynckey = self::$deviceManager->GetStateManager()->GetNewSyncKey($synckey); |
|
49 | - |
|
50 | - // there are no SyncParameters for the hierarchy, but we use it to save the latest synckeys |
|
51 | - $spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState(false); |
|
52 | - } |
|
53 | - catch (StateNotFoundException $snfex) { |
|
54 | - $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
55 | - } |
|
56 | - catch (StateInvalidException $sive) { |
|
57 | - $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
58 | - } |
|
59 | - |
|
60 | - // The ChangesWrapper caches all imports in-memory, so we can send a change count |
|
61 | - // before sending the actual data. |
|
62 | - // the HierarchyCache is notified and the changes from the PIM are transmitted to the actual backend |
|
63 | - $changesMem = self::$deviceManager->GetHierarchyChangesWrapper(); |
|
64 | - |
|
65 | - // the hierarchyCache should now fully be initialized - check for changes in the additional folders |
|
66 | - $changesMem->Config(GSync::GetAdditionalSyncFolders(false), ChangesMemoryWrapper::SYNCHRONIZING); |
|
67 | - |
|
68 | - // reset to default store in backend |
|
69 | - self::$backend->Setup(false); |
|
70 | - |
|
71 | - // process incoming changes |
|
72 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_CHANGES)) { |
|
73 | - // Ignore <Count> if present |
|
74 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_COUNT)) { |
|
75 | - self::$decoder->getElementContent(); |
|
76 | - if (!self::$decoder->getElementEndTag()) { |
|
77 | - return false; |
|
78 | - } |
|
79 | - } |
|
80 | - |
|
81 | - // Process the changes (either <Add>, <Modify>, or <Remove>) |
|
82 | - $element = self::$decoder->getElement(); |
|
83 | - |
|
84 | - if ($element[EN_TYPE] != EN_TYPE_STARTTAG) { |
|
85 | - return false; |
|
86 | - } |
|
87 | - |
|
88 | - $importer = false; |
|
89 | - WBXMLDecoder::ResetInWhile("folderSyncIncomingChange"); |
|
90 | - while (WBXMLDecoder::InWhile("folderSyncIncomingChange")) { |
|
91 | - $folder = new SyncFolder(); |
|
92 | - if (!$folder->Decode(self::$decoder)) { |
|
93 | - break; |
|
94 | - } |
|
95 | - |
|
96 | - // add the backendId to the SyncFolder object |
|
97 | - $folder->BackendId = self::$deviceManager->GetBackendIdForFolderId($folder->serverid); |
|
98 | - |
|
99 | - try { |
|
100 | - if ($status == SYNC_FSSTATUS_SUCCESS && !$importer) { |
|
101 | - // Configure the backends importer with last state |
|
102 | - $importer = self::$backend->GetImporter(); |
|
103 | - $importer->Config($syncstate); |
|
104 | - // the messages from the PIM will be forwarded to the backend |
|
105 | - $changesMem->forwardImporter($importer); |
|
106 | - } |
|
107 | - |
|
108 | - if ($status == SYNC_FSSTATUS_SUCCESS) { |
|
109 | - switch ($element[EN_TAG]) { |
|
110 | - case SYNC_ADD: |
|
111 | - case SYNC_MODIFY: |
|
112 | - $serverid = $changesMem->ImportFolderChange($folder); |
|
113 | - break; |
|
114 | - |
|
115 | - case SYNC_REMOVE: |
|
116 | - $serverid = $changesMem->ImportFolderDeletion($folder); |
|
117 | - break; |
|
118 | - } |
|
119 | - } |
|
120 | - else { |
|
121 | - SLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): ignoring incoming folderchange for folder '%s' as status indicates problem.", $folder->displayname)); |
|
122 | - self::$topCollector->AnnounceInformation("Incoming change ignored", true); |
|
123 | - } |
|
124 | - } |
|
125 | - catch (StatusException $stex) { |
|
126 | - $status = $stex->getCode(); |
|
127 | - } |
|
128 | - } |
|
129 | - |
|
130 | - if (!self::$decoder->getElementEndTag()) { |
|
131 | - return false; |
|
132 | - } |
|
133 | - } |
|
134 | - // no incoming changes |
|
135 | - else { |
|
136 | - // check for a potential process loop like described in Issue ZP-5 |
|
137 | - if ($synckey != "0" && self::$deviceManager->IsHierarchyFullResyncRequired()) { |
|
138 | - $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
139 | - self::$deviceManager->AnnounceProcessStatus(false, $status); |
|
140 | - } |
|
141 | - } |
|
142 | - |
|
143 | - if (!self::$decoder->getElementEndTag()) { |
|
144 | - return false; |
|
145 | - } |
|
146 | - |
|
147 | - // We have processed incoming foldersync requests, now send the PIM |
|
148 | - // our changes |
|
149 | - |
|
150 | - // Output our WBXML reply now |
|
151 | - self::$encoder->StartWBXML(); |
|
152 | - |
|
153 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERSYNC); |
|
154 | - |
|
155 | - if ($status == SYNC_FSSTATUS_SUCCESS) { |
|
156 | - try { |
|
157 | - // do nothing if this is an invalid device id (like the 'validate' Androids internal client sends) |
|
158 | - if (!Request::IsValidDeviceID()) { |
|
159 | - throw new StatusException(sprintf("Request::IsValidDeviceID() indicated that '%s' is not a valid device id", Request::GetDeviceID()), SYNC_FSSTATUS_SERVERERROR); |
|
160 | - } |
|
161 | - |
|
162 | - // Changes from backend are sent to the MemImporter and processed for the HierarchyCache. |
|
163 | - // The state which is saved is from the backend, as the MemImporter is only a proxy. |
|
164 | - $exporter = self::$backend->GetExporter(); |
|
165 | - |
|
166 | - $exporter->Config($syncstate); |
|
167 | - $exporter->InitializeExporter($changesMem); |
|
168 | - |
|
169 | - // Stream all changes to the ImportExportChangesMem |
|
170 | - $totalChanges = $exporter->GetChangeCount(); |
|
171 | - $exported = 0; |
|
172 | - $partial = false; |
|
173 | - while (is_array($exporter->Synchronize())) { |
|
174 | - ++$exported; |
|
175 | - |
|
176 | - if (time() % 4) { |
|
177 | - self::$topCollector->AnnounceInformation(sprintf("Exported %d from %d folders", $exported, $totalChanges)); |
|
178 | - } |
|
179 | - |
|
180 | - // if partial sync is allowed, stop if this takes too long |
|
181 | - if (USE_PARTIAL_FOLDERSYNC && Request::IsRequestTimeoutReached()) { |
|
182 | - SLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): Exporting folders is too slow. In %d seconds only %d from %d changes were processed.", (time() - $_SERVER["REQUEST_TIME"]), $exported, $totalChanges)); |
|
183 | - self::$topCollector->AnnounceInformation(sprintf("Partial export of %d out of %d folders", $exported, $totalChanges), true); |
|
184 | - self::$deviceManager->SetFolderSyncComplete(false); |
|
185 | - $partial = true; |
|
186 | - |
|
187 | - break; |
|
188 | - } |
|
189 | - } |
|
190 | - |
|
191 | - // update the foldersync complete flag |
|
192 | - if (USE_PARTIAL_FOLDERSYNC && $partial == false && self::$deviceManager->GetFolderSyncComplete() === false) { |
|
193 | - // say that we are done with partial syncing |
|
194 | - self::$deviceManager->SetFolderSyncComplete(true); |
|
195 | - // reset the loop data to prevent any loop detection to kick in now |
|
196 | - self::$deviceManager->ClearLoopDetectionData(Request::GetAuthUserString(), Request::GetDeviceID()); |
|
197 | - SLog::Write(LOGLEVEL_INFO, "Request->HandleFolderSync(): Chunked exporting of folders completed successfully"); |
|
198 | - } |
|
199 | - |
|
200 | - // get the new state from the backend |
|
201 | - $newsyncstate = (isset($exporter)) ? $exporter->GetState() : ""; |
|
202 | - } |
|
203 | - catch (StatusException $stex) { |
|
204 | - if ($stex->getCode() == SYNC_FSSTATUS_CODEUNKNOWN) { |
|
205 | - $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
206 | - } |
|
207 | - else { |
|
208 | - $status = $stex->getCode(); |
|
209 | - } |
|
210 | - } |
|
211 | - } |
|
212 | - |
|
213 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
|
214 | - self::$encoder->content($status); |
|
215 | - self::$encoder->endTag(); |
|
216 | - |
|
217 | - if ($status == SYNC_FSSTATUS_SUCCESS) { |
|
218 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY); |
|
219 | - $synckey = ($changesMem->IsStateChanged()) ? $newsynckey : $synckey; |
|
220 | - self::$encoder->content($synckey); |
|
221 | - self::$encoder->endTag(); |
|
222 | - |
|
223 | - // Stream folders directly to the PDA |
|
224 | - $streamimporter = new ImportChangesStream(self::$encoder, false); |
|
225 | - $changesMem->InitializeExporter($streamimporter); |
|
226 | - $changeCount = $changesMem->GetChangeCount(); |
|
227 | - |
|
228 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_CHANGES); |
|
229 | - |
|
230 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_COUNT); |
|
231 | - self::$encoder->content($changeCount); |
|
232 | - self::$encoder->endTag(); |
|
233 | - while ($changesMem->Synchronize()); |
|
234 | - |
|
235 | - self::$encoder->endTag(); |
|
236 | - self::$topCollector->AnnounceInformation(sprintf("Outgoing %d folders", $changeCount), true); |
|
237 | - |
|
238 | - if ($changeCount == 0) { |
|
239 | - self::$deviceManager->CheckFolderData(); |
|
240 | - } |
|
241 | - // everything fine, save the sync state for the next time |
|
242 | - if ($synckey == $newsynckey) { |
|
243 | - self::$deviceManager->GetStateManager()->SetSyncState($newsynckey, $newsyncstate); |
|
244 | - |
|
245 | - // update SPA & save it |
|
246 | - $spa->SetSyncKey($newsynckey); |
|
247 | - $spa->SetFolderId(false); |
|
248 | - |
|
249 | - // invalidate all pingable flags |
|
250 | - SyncCollections::InvalidatePingableFlags(); |
|
251 | - } |
|
252 | - // save the SyncParameters if it changed or the reference policy key is not set or different |
|
253 | - if ($spa->IsDataChanged() || !$spa->HasReferencePolicyKey() || GSync::GetProvisioningManager()->ProvisioningRequired($spa->GetReferencePolicyKey(), true, false)) { |
|
254 | - // saves the SPA (while updating the reference policy key) |
|
255 | - $spa->SetLastSynctime(time()); |
|
256 | - self::$deviceManager->GetStateManager()->SetSynchedFolderState($spa); |
|
257 | - } |
|
258 | - } |
|
259 | - |
|
260 | - self::$encoder->endTag(); |
|
261 | - |
|
262 | - return true; |
|
263 | - } |
|
11 | + /** |
|
12 | + * Handles the FolderSync command. |
|
13 | + * |
|
14 | + * @param int $commandCode |
|
15 | + * |
|
16 | + * @return bool |
|
17 | + */ |
|
18 | + public function Handle($commandCode) { |
|
19 | + // Parse input |
|
20 | + if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_FOLDERSYNC)) { |
|
21 | + return false; |
|
22 | + } |
|
23 | + |
|
24 | + if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SYNCKEY)) { |
|
25 | + return false; |
|
26 | + } |
|
27 | + |
|
28 | + $synckey = self::$decoder->getElementContent(); |
|
29 | + |
|
30 | + if (!self::$decoder->getElementEndTag()) { |
|
31 | + return false; |
|
32 | + } |
|
33 | + |
|
34 | + // every FolderSync with SyncKey 0 should return the supported AS version & command headers |
|
35 | + if ($synckey == "0") { |
|
36 | + self::$specialHeaders = []; |
|
37 | + self::$specialHeaders[] = GSync::GetSupportedProtocolVersions(); |
|
38 | + self::$specialHeaders[] = GSync::GetSupportedCommands(); |
|
39 | + } |
|
40 | + |
|
41 | + $status = SYNC_FSSTATUS_SUCCESS; |
|
42 | + $newsynckey = $synckey; |
|
43 | + |
|
44 | + try { |
|
45 | + $syncstate = self::$deviceManager->GetStateManager()->GetSyncState($synckey); |
|
46 | + |
|
47 | + // We will be saving the sync state under 'newsynckey' |
|
48 | + $newsynckey = self::$deviceManager->GetStateManager()->GetNewSyncKey($synckey); |
|
49 | + |
|
50 | + // there are no SyncParameters for the hierarchy, but we use it to save the latest synckeys |
|
51 | + $spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState(false); |
|
52 | + } |
|
53 | + catch (StateNotFoundException $snfex) { |
|
54 | + $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
55 | + } |
|
56 | + catch (StateInvalidException $sive) { |
|
57 | + $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
58 | + } |
|
59 | + |
|
60 | + // The ChangesWrapper caches all imports in-memory, so we can send a change count |
|
61 | + // before sending the actual data. |
|
62 | + // the HierarchyCache is notified and the changes from the PIM are transmitted to the actual backend |
|
63 | + $changesMem = self::$deviceManager->GetHierarchyChangesWrapper(); |
|
64 | + |
|
65 | + // the hierarchyCache should now fully be initialized - check for changes in the additional folders |
|
66 | + $changesMem->Config(GSync::GetAdditionalSyncFolders(false), ChangesMemoryWrapper::SYNCHRONIZING); |
|
67 | + |
|
68 | + // reset to default store in backend |
|
69 | + self::$backend->Setup(false); |
|
70 | + |
|
71 | + // process incoming changes |
|
72 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_CHANGES)) { |
|
73 | + // Ignore <Count> if present |
|
74 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_COUNT)) { |
|
75 | + self::$decoder->getElementContent(); |
|
76 | + if (!self::$decoder->getElementEndTag()) { |
|
77 | + return false; |
|
78 | + } |
|
79 | + } |
|
80 | + |
|
81 | + // Process the changes (either <Add>, <Modify>, or <Remove>) |
|
82 | + $element = self::$decoder->getElement(); |
|
83 | + |
|
84 | + if ($element[EN_TYPE] != EN_TYPE_STARTTAG) { |
|
85 | + return false; |
|
86 | + } |
|
87 | + |
|
88 | + $importer = false; |
|
89 | + WBXMLDecoder::ResetInWhile("folderSyncIncomingChange"); |
|
90 | + while (WBXMLDecoder::InWhile("folderSyncIncomingChange")) { |
|
91 | + $folder = new SyncFolder(); |
|
92 | + if (!$folder->Decode(self::$decoder)) { |
|
93 | + break; |
|
94 | + } |
|
95 | + |
|
96 | + // add the backendId to the SyncFolder object |
|
97 | + $folder->BackendId = self::$deviceManager->GetBackendIdForFolderId($folder->serverid); |
|
98 | + |
|
99 | + try { |
|
100 | + if ($status == SYNC_FSSTATUS_SUCCESS && !$importer) { |
|
101 | + // Configure the backends importer with last state |
|
102 | + $importer = self::$backend->GetImporter(); |
|
103 | + $importer->Config($syncstate); |
|
104 | + // the messages from the PIM will be forwarded to the backend |
|
105 | + $changesMem->forwardImporter($importer); |
|
106 | + } |
|
107 | + |
|
108 | + if ($status == SYNC_FSSTATUS_SUCCESS) { |
|
109 | + switch ($element[EN_TAG]) { |
|
110 | + case SYNC_ADD: |
|
111 | + case SYNC_MODIFY: |
|
112 | + $serverid = $changesMem->ImportFolderChange($folder); |
|
113 | + break; |
|
114 | + |
|
115 | + case SYNC_REMOVE: |
|
116 | + $serverid = $changesMem->ImportFolderDeletion($folder); |
|
117 | + break; |
|
118 | + } |
|
119 | + } |
|
120 | + else { |
|
121 | + SLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): ignoring incoming folderchange for folder '%s' as status indicates problem.", $folder->displayname)); |
|
122 | + self::$topCollector->AnnounceInformation("Incoming change ignored", true); |
|
123 | + } |
|
124 | + } |
|
125 | + catch (StatusException $stex) { |
|
126 | + $status = $stex->getCode(); |
|
127 | + } |
|
128 | + } |
|
129 | + |
|
130 | + if (!self::$decoder->getElementEndTag()) { |
|
131 | + return false; |
|
132 | + } |
|
133 | + } |
|
134 | + // no incoming changes |
|
135 | + else { |
|
136 | + // check for a potential process loop like described in Issue ZP-5 |
|
137 | + if ($synckey != "0" && self::$deviceManager->IsHierarchyFullResyncRequired()) { |
|
138 | + $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
139 | + self::$deviceManager->AnnounceProcessStatus(false, $status); |
|
140 | + } |
|
141 | + } |
|
142 | + |
|
143 | + if (!self::$decoder->getElementEndTag()) { |
|
144 | + return false; |
|
145 | + } |
|
146 | + |
|
147 | + // We have processed incoming foldersync requests, now send the PIM |
|
148 | + // our changes |
|
149 | + |
|
150 | + // Output our WBXML reply now |
|
151 | + self::$encoder->StartWBXML(); |
|
152 | + |
|
153 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERSYNC); |
|
154 | + |
|
155 | + if ($status == SYNC_FSSTATUS_SUCCESS) { |
|
156 | + try { |
|
157 | + // do nothing if this is an invalid device id (like the 'validate' Androids internal client sends) |
|
158 | + if (!Request::IsValidDeviceID()) { |
|
159 | + throw new StatusException(sprintf("Request::IsValidDeviceID() indicated that '%s' is not a valid device id", Request::GetDeviceID()), SYNC_FSSTATUS_SERVERERROR); |
|
160 | + } |
|
161 | + |
|
162 | + // Changes from backend are sent to the MemImporter and processed for the HierarchyCache. |
|
163 | + // The state which is saved is from the backend, as the MemImporter is only a proxy. |
|
164 | + $exporter = self::$backend->GetExporter(); |
|
165 | + |
|
166 | + $exporter->Config($syncstate); |
|
167 | + $exporter->InitializeExporter($changesMem); |
|
168 | + |
|
169 | + // Stream all changes to the ImportExportChangesMem |
|
170 | + $totalChanges = $exporter->GetChangeCount(); |
|
171 | + $exported = 0; |
|
172 | + $partial = false; |
|
173 | + while (is_array($exporter->Synchronize())) { |
|
174 | + ++$exported; |
|
175 | + |
|
176 | + if (time() % 4) { |
|
177 | + self::$topCollector->AnnounceInformation(sprintf("Exported %d from %d folders", $exported, $totalChanges)); |
|
178 | + } |
|
179 | + |
|
180 | + // if partial sync is allowed, stop if this takes too long |
|
181 | + if (USE_PARTIAL_FOLDERSYNC && Request::IsRequestTimeoutReached()) { |
|
182 | + SLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): Exporting folders is too slow. In %d seconds only %d from %d changes were processed.", (time() - $_SERVER["REQUEST_TIME"]), $exported, $totalChanges)); |
|
183 | + self::$topCollector->AnnounceInformation(sprintf("Partial export of %d out of %d folders", $exported, $totalChanges), true); |
|
184 | + self::$deviceManager->SetFolderSyncComplete(false); |
|
185 | + $partial = true; |
|
186 | + |
|
187 | + break; |
|
188 | + } |
|
189 | + } |
|
190 | + |
|
191 | + // update the foldersync complete flag |
|
192 | + if (USE_PARTIAL_FOLDERSYNC && $partial == false && self::$deviceManager->GetFolderSyncComplete() === false) { |
|
193 | + // say that we are done with partial syncing |
|
194 | + self::$deviceManager->SetFolderSyncComplete(true); |
|
195 | + // reset the loop data to prevent any loop detection to kick in now |
|
196 | + self::$deviceManager->ClearLoopDetectionData(Request::GetAuthUserString(), Request::GetDeviceID()); |
|
197 | + SLog::Write(LOGLEVEL_INFO, "Request->HandleFolderSync(): Chunked exporting of folders completed successfully"); |
|
198 | + } |
|
199 | + |
|
200 | + // get the new state from the backend |
|
201 | + $newsyncstate = (isset($exporter)) ? $exporter->GetState() : ""; |
|
202 | + } |
|
203 | + catch (StatusException $stex) { |
|
204 | + if ($stex->getCode() == SYNC_FSSTATUS_CODEUNKNOWN) { |
|
205 | + $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
206 | + } |
|
207 | + else { |
|
208 | + $status = $stex->getCode(); |
|
209 | + } |
|
210 | + } |
|
211 | + } |
|
212 | + |
|
213 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
|
214 | + self::$encoder->content($status); |
|
215 | + self::$encoder->endTag(); |
|
216 | + |
|
217 | + if ($status == SYNC_FSSTATUS_SUCCESS) { |
|
218 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY); |
|
219 | + $synckey = ($changesMem->IsStateChanged()) ? $newsynckey : $synckey; |
|
220 | + self::$encoder->content($synckey); |
|
221 | + self::$encoder->endTag(); |
|
222 | + |
|
223 | + // Stream folders directly to the PDA |
|
224 | + $streamimporter = new ImportChangesStream(self::$encoder, false); |
|
225 | + $changesMem->InitializeExporter($streamimporter); |
|
226 | + $changeCount = $changesMem->GetChangeCount(); |
|
227 | + |
|
228 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_CHANGES); |
|
229 | + |
|
230 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_COUNT); |
|
231 | + self::$encoder->content($changeCount); |
|
232 | + self::$encoder->endTag(); |
|
233 | + while ($changesMem->Synchronize()); |
|
234 | + |
|
235 | + self::$encoder->endTag(); |
|
236 | + self::$topCollector->AnnounceInformation(sprintf("Outgoing %d folders", $changeCount), true); |
|
237 | + |
|
238 | + if ($changeCount == 0) { |
|
239 | + self::$deviceManager->CheckFolderData(); |
|
240 | + } |
|
241 | + // everything fine, save the sync state for the next time |
|
242 | + if ($synckey == $newsynckey) { |
|
243 | + self::$deviceManager->GetStateManager()->SetSyncState($newsynckey, $newsyncstate); |
|
244 | + |
|
245 | + // update SPA & save it |
|
246 | + $spa->SetSyncKey($newsynckey); |
|
247 | + $spa->SetFolderId(false); |
|
248 | + |
|
249 | + // invalidate all pingable flags |
|
250 | + SyncCollections::InvalidatePingableFlags(); |
|
251 | + } |
|
252 | + // save the SyncParameters if it changed or the reference policy key is not set or different |
|
253 | + if ($spa->IsDataChanged() || !$spa->HasReferencePolicyKey() || GSync::GetProvisioningManager()->ProvisioningRequired($spa->GetReferencePolicyKey(), true, false)) { |
|
254 | + // saves the SPA (while updating the reference policy key) |
|
255 | + $spa->SetLastSynctime(time()); |
|
256 | + self::$deviceManager->GetStateManager()->SetSynchedFolderState($spa); |
|
257 | + } |
|
258 | + } |
|
259 | + |
|
260 | + self::$encoder->endTag(); |
|
261 | + |
|
262 | + return true; |
|
263 | + } |
|
264 | 264 | } |
@@ -49,11 +49,9 @@ discard block |
||
49 | 49 | |
50 | 50 | // there are no SyncParameters for the hierarchy, but we use it to save the latest synckeys |
51 | 51 | $spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState(false); |
52 | - } |
|
53 | - catch (StateNotFoundException $snfex) { |
|
52 | + } catch (StateNotFoundException $snfex) { |
|
54 | 53 | $status = SYNC_FSSTATUS_SYNCKEYERROR; |
55 | - } |
|
56 | - catch (StateInvalidException $sive) { |
|
54 | + } catch (StateInvalidException $sive) { |
|
57 | 55 | $status = SYNC_FSSTATUS_SYNCKEYERROR; |
58 | 56 | } |
59 | 57 | |
@@ -116,13 +114,11 @@ discard block |
||
116 | 114 | $serverid = $changesMem->ImportFolderDeletion($folder); |
117 | 115 | break; |
118 | 116 | } |
119 | - } |
|
120 | - else { |
|
117 | + } else { |
|
121 | 118 | SLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): ignoring incoming folderchange for folder '%s' as status indicates problem.", $folder->displayname)); |
122 | 119 | self::$topCollector->AnnounceInformation("Incoming change ignored", true); |
123 | 120 | } |
124 | - } |
|
125 | - catch (StatusException $stex) { |
|
121 | + } catch (StatusException $stex) { |
|
126 | 122 | $status = $stex->getCode(); |
127 | 123 | } |
128 | 124 | } |
@@ -199,12 +195,10 @@ discard block |
||
199 | 195 | |
200 | 196 | // get the new state from the backend |
201 | 197 | $newsyncstate = (isset($exporter)) ? $exporter->GetState() : ""; |
202 | - } |
|
203 | - catch (StatusException $stex) { |
|
198 | + } catch (StatusException $stex) { |
|
204 | 199 | if ($stex->getCode() == SYNC_FSSTATUS_CODEUNKNOWN) { |
205 | 200 | $status = SYNC_FSSTATUS_SYNCKEYERROR; |
206 | - } |
|
207 | - else { |
|
201 | + } else { |
|
208 | 202 | $status = $stex->getCode(); |
209 | 203 | } |
210 | 204 | } |
@@ -8,238 +8,238 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class FolderChange extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles creates, updates or deletes of a folder |
|
13 | - * issued by the commands FolderCreate, FolderUpdate and FolderDelete. |
|
14 | - * |
|
15 | - * @param int $commandCode |
|
16 | - * |
|
17 | - * @return bool |
|
18 | - */ |
|
19 | - public function Handle($commandCode) { |
|
20 | - $el = self::$decoder->getElement(); |
|
21 | - |
|
22 | - if ($el[EN_TYPE] != EN_TYPE_STARTTAG) { |
|
23 | - return false; |
|
24 | - } |
|
25 | - |
|
26 | - $create = $update = $delete = false; |
|
27 | - if ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERCREATE) { |
|
28 | - $create = true; |
|
29 | - } |
|
30 | - elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERUPDATE) { |
|
31 | - $update = true; |
|
32 | - } |
|
33 | - elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERDELETE) { |
|
34 | - $delete = true; |
|
35 | - } |
|
36 | - |
|
37 | - if (!$create && !$update && !$delete) { |
|
38 | - return false; |
|
39 | - } |
|
40 | - |
|
41 | - // SyncKey |
|
42 | - if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SYNCKEY)) { |
|
43 | - return false; |
|
44 | - } |
|
45 | - $synckey = self::$decoder->getElementContent(); |
|
46 | - if (!self::$decoder->getElementEndTag()) { |
|
47 | - return false; |
|
48 | - } |
|
49 | - |
|
50 | - // ServerID |
|
51 | - $serverid = false; |
|
52 | - $backendid = false; |
|
53 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID)) { |
|
54 | - $serverid = self::$decoder->getElementContent(); |
|
55 | - $backendid = self::$deviceManager->GetBackendIdForFolderId($serverid); |
|
56 | - if (!self::$decoder->getElementEndTag()) { |
|
57 | - return false; |
|
58 | - } |
|
59 | - } |
|
60 | - |
|
61 | - // Parent |
|
62 | - $parentid = false; |
|
63 | - $parentBackendId = false; |
|
64 | - |
|
65 | - // when creating or updating more information is necessary |
|
66 | - if (!$delete) { |
|
67 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_PARENTID)) { |
|
68 | - $parentid = self::$decoder->getElementContent(); |
|
69 | - $parentBackendId = self::$deviceManager->GetBackendIdForFolderId($parentid); |
|
70 | - if (!self::$decoder->getElementEndTag()) { |
|
71 | - return false; |
|
72 | - } |
|
73 | - } |
|
74 | - |
|
75 | - // Displayname |
|
76 | - if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_DISPLAYNAME)) { |
|
77 | - return false; |
|
78 | - } |
|
79 | - $displayname = self::$decoder->getElementContent(); |
|
80 | - if (!self::$decoder->getElementEndTag()) { |
|
81 | - return false; |
|
82 | - } |
|
83 | - |
|
84 | - // Type |
|
85 | - $type = false; |
|
86 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_TYPE)) { |
|
87 | - $type = self::$decoder->getElementContent(); |
|
88 | - if (!self::$decoder->getElementEndTag()) { |
|
89 | - return false; |
|
90 | - } |
|
91 | - } |
|
92 | - } |
|
93 | - |
|
94 | - // endtag foldercreate, folderupdate, folderdelete |
|
95 | - if (!self::$decoder->getElementEndTag()) { |
|
96 | - return false; |
|
97 | - } |
|
98 | - |
|
99 | - $status = SYNC_FSSTATUS_SUCCESS; |
|
100 | - // Get state of hierarchy |
|
101 | - try { |
|
102 | - $syncstate = self::$deviceManager->GetStateManager()->GetSyncState($synckey); |
|
103 | - $newsynckey = self::$deviceManager->GetStateManager()->GetNewSyncKey($synckey); |
|
104 | - |
|
105 | - // there are no SyncParameters for the hierarchy, but we use it to save the latest synckeys |
|
106 | - $spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState(false); |
|
107 | - |
|
108 | - // Over the ChangesWrapper the HierarchyCache is notified about all changes |
|
109 | - $changesMem = self::$deviceManager->GetHierarchyChangesWrapper(); |
|
110 | - |
|
111 | - // the hierarchyCache should now fully be initialized - check for changes in the additional folders |
|
112 | - $changesMem->Config(GSync::GetAdditionalSyncFolders(false)); |
|
113 | - |
|
114 | - // reset to default store in backend |
|
115 | - self::$backend->Setup(false); |
|
116 | - |
|
117 | - // there are unprocessed changes in the hierarchy, trigger resync |
|
118 | - if ($changesMem->GetChangeCount() > 0) { |
|
119 | - throw new StatusException("HandleFolderChange() can not proceed as there are unprocessed hierarchy changes", SYNC_FSSTATUS_SERVERERROR); |
|
120 | - } |
|
121 | - |
|
122 | - // any additional folders can not be modified - with exception if they are of type SYNC_FOLDER_TYPE_UNKNOWN (ZP-907) |
|
123 | - if (self::$deviceManager->GetFolderTypeFromCacheById($serverid) != SYNC_FOLDER_TYPE_UNKNOWN && $serverid !== false && GSync::GetAdditionalSyncFolderStore($backendid)) { |
|
124 | - throw new StatusException("HandleFolderChange() can not change additional folders which are configured", SYNC_FSSTATUS_SYSTEMFOLDER); |
|
125 | - } |
|
126 | - |
|
127 | - // switch user store if this this happens inside an additional folder |
|
128 | - // if this is an additional folder the backend has to be setup correctly |
|
129 | - // backend should also not be switched when type is SYNC_FOLDER_TYPE_UNKNOWN (ZP-1220) |
|
130 | - if (self::$deviceManager->GetFolderTypeFromCacheById($serverid) != SYNC_FOLDER_TYPE_UNKNOWN && !self::$backend->Setup(GSync::GetAdditionalSyncFolderStore((($parentBackendId != false) ? $parentBackendId : $backendid)))) { |
|
131 | - throw new StatusException(sprintf("HandleFolderChange() could not Setup() the backend for folder id '%s'", (($parentBackendId != false) ? $parentBackendId : $backendid)), SYNC_FSSTATUS_SERVERERROR); |
|
132 | - } |
|
133 | - } |
|
134 | - catch (StateNotFoundException $snfex) { |
|
135 | - $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
136 | - } |
|
137 | - catch (StatusException $stex) { |
|
138 | - $status = $stex->getCode(); |
|
139 | - } |
|
140 | - |
|
141 | - // set $newsynckey in case of an error |
|
142 | - if (!isset($newsynckey)) { |
|
143 | - $newsynckey = $synckey; |
|
144 | - } |
|
145 | - |
|
146 | - if ($status == SYNC_FSSTATUS_SUCCESS) { |
|
147 | - try { |
|
148 | - // Configure importer with last state |
|
149 | - $importer = self::$backend->GetImporter(); |
|
150 | - $importer->Config($syncstate); |
|
151 | - |
|
152 | - // the messages from the PIM will be forwarded to the real importer |
|
153 | - $changesMem->SetDestinationImporter($importer); |
|
154 | - |
|
155 | - // Create SyncFolder object |
|
156 | - $folder = new SyncFolder(); |
|
157 | - $folder->serverid = $serverid; |
|
158 | - $folder->parentid = $parentBackendId; |
|
159 | - if (isset($displayname)) { |
|
160 | - $folder->displayname = $displayname; |
|
161 | - } |
|
162 | - if (isset($type)) { |
|
163 | - $folder->type = $type; |
|
164 | - } |
|
165 | - // add the backendId to the SyncFolder object |
|
166 | - $folder->BackendId = $backendid; |
|
167 | - |
|
168 | - // process incoming change |
|
169 | - if (!$delete) { |
|
170 | - // when creating, $folder->serverid is false, and the returned id is already mapped by the backend |
|
171 | - $folder = $changesMem->ImportFolderChange($folder); |
|
172 | - } |
|
173 | - else { |
|
174 | - // delete folder |
|
175 | - $changesMem->ImportFolderDeletion($folder); |
|
176 | - } |
|
177 | - } |
|
178 | - catch (StatusException $stex) { |
|
179 | - $status = $stex->getCode(); |
|
180 | - } |
|
181 | - } |
|
182 | - |
|
183 | - self::$encoder->startWBXML(); |
|
184 | - if ($create) { |
|
185 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERCREATE); |
|
186 | - |
|
187 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
|
188 | - self::$encoder->content($status); |
|
189 | - self::$encoder->endTag(); |
|
190 | - |
|
191 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY); |
|
192 | - self::$encoder->content($newsynckey); |
|
193 | - self::$encoder->endTag(); |
|
194 | - |
|
195 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID); |
|
196 | - self::$encoder->content($folder->serverid); |
|
197 | - self::$encoder->endTag(); |
|
198 | - |
|
199 | - self::$encoder->endTag(); |
|
200 | - } |
|
201 | - elseif ($update) { |
|
202 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERUPDATE); |
|
203 | - |
|
204 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
|
205 | - self::$encoder->content($status); |
|
206 | - self::$encoder->endTag(); |
|
207 | - |
|
208 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY); |
|
209 | - self::$encoder->content($newsynckey); |
|
210 | - self::$encoder->endTag(); |
|
211 | - |
|
212 | - self::$encoder->endTag(); |
|
213 | - } |
|
214 | - elseif ($delete) { |
|
215 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERDELETE); |
|
216 | - |
|
217 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
|
218 | - self::$encoder->content($status); |
|
219 | - self::$encoder->endTag(); |
|
220 | - |
|
221 | - self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY); |
|
222 | - self::$encoder->content($newsynckey); |
|
223 | - self::$encoder->endTag(); |
|
224 | - |
|
225 | - self::$encoder->endTag(); |
|
226 | - } |
|
227 | - |
|
228 | - self::$topCollector->AnnounceInformation(sprintf("Operation status %d", $status), true); |
|
229 | - |
|
230 | - // Save the sync state for the next time |
|
231 | - if (isset($importer)) { |
|
232 | - self::$deviceManager->GetStateManager()->SetSyncState($newsynckey, $importer->GetState()); |
|
233 | - |
|
234 | - // update SPA & save it |
|
235 | - $spa->SetSyncKey($newsynckey); |
|
236 | - $spa->SetFolderId(false); |
|
237 | - self::$deviceManager->GetStateManager()->SetSynchedFolderState($spa); |
|
238 | - |
|
239 | - // invalidate all pingable flags |
|
240 | - SyncCollections::InvalidatePingableFlags(); |
|
241 | - } |
|
242 | - |
|
243 | - return true; |
|
244 | - } |
|
11 | + /** |
|
12 | + * Handles creates, updates or deletes of a folder |
|
13 | + * issued by the commands FolderCreate, FolderUpdate and FolderDelete. |
|
14 | + * |
|
15 | + * @param int $commandCode |
|
16 | + * |
|
17 | + * @return bool |
|
18 | + */ |
|
19 | + public function Handle($commandCode) { |
|
20 | + $el = self::$decoder->getElement(); |
|
21 | + |
|
22 | + if ($el[EN_TYPE] != EN_TYPE_STARTTAG) { |
|
23 | + return false; |
|
24 | + } |
|
25 | + |
|
26 | + $create = $update = $delete = false; |
|
27 | + if ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERCREATE) { |
|
28 | + $create = true; |
|
29 | + } |
|
30 | + elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERUPDATE) { |
|
31 | + $update = true; |
|
32 | + } |
|
33 | + elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERDELETE) { |
|
34 | + $delete = true; |
|
35 | + } |
|
36 | + |
|
37 | + if (!$create && !$update && !$delete) { |
|
38 | + return false; |
|
39 | + } |
|
40 | + |
|
41 | + // SyncKey |
|
42 | + if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SYNCKEY)) { |
|
43 | + return false; |
|
44 | + } |
|
45 | + $synckey = self::$decoder->getElementContent(); |
|
46 | + if (!self::$decoder->getElementEndTag()) { |
|
47 | + return false; |
|
48 | + } |
|
49 | + |
|
50 | + // ServerID |
|
51 | + $serverid = false; |
|
52 | + $backendid = false; |
|
53 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID)) { |
|
54 | + $serverid = self::$decoder->getElementContent(); |
|
55 | + $backendid = self::$deviceManager->GetBackendIdForFolderId($serverid); |
|
56 | + if (!self::$decoder->getElementEndTag()) { |
|
57 | + return false; |
|
58 | + } |
|
59 | + } |
|
60 | + |
|
61 | + // Parent |
|
62 | + $parentid = false; |
|
63 | + $parentBackendId = false; |
|
64 | + |
|
65 | + // when creating or updating more information is necessary |
|
66 | + if (!$delete) { |
|
67 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_PARENTID)) { |
|
68 | + $parentid = self::$decoder->getElementContent(); |
|
69 | + $parentBackendId = self::$deviceManager->GetBackendIdForFolderId($parentid); |
|
70 | + if (!self::$decoder->getElementEndTag()) { |
|
71 | + return false; |
|
72 | + } |
|
73 | + } |
|
74 | + |
|
75 | + // Displayname |
|
76 | + if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_DISPLAYNAME)) { |
|
77 | + return false; |
|
78 | + } |
|
79 | + $displayname = self::$decoder->getElementContent(); |
|
80 | + if (!self::$decoder->getElementEndTag()) { |
|
81 | + return false; |
|
82 | + } |
|
83 | + |
|
84 | + // Type |
|
85 | + $type = false; |
|
86 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_TYPE)) { |
|
87 | + $type = self::$decoder->getElementContent(); |
|
88 | + if (!self::$decoder->getElementEndTag()) { |
|
89 | + return false; |
|
90 | + } |
|
91 | + } |
|
92 | + } |
|
93 | + |
|
94 | + // endtag foldercreate, folderupdate, folderdelete |
|
95 | + if (!self::$decoder->getElementEndTag()) { |
|
96 | + return false; |
|
97 | + } |
|
98 | + |
|
99 | + $status = SYNC_FSSTATUS_SUCCESS; |
|
100 | + // Get state of hierarchy |
|
101 | + try { |
|
102 | + $syncstate = self::$deviceManager->GetStateManager()->GetSyncState($synckey); |
|
103 | + $newsynckey = self::$deviceManager->GetStateManager()->GetNewSyncKey($synckey); |
|
104 | + |
|
105 | + // there are no SyncParameters for the hierarchy, but we use it to save the latest synckeys |
|
106 | + $spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState(false); |
|
107 | + |
|
108 | + // Over the ChangesWrapper the HierarchyCache is notified about all changes |
|
109 | + $changesMem = self::$deviceManager->GetHierarchyChangesWrapper(); |
|
110 | + |
|
111 | + // the hierarchyCache should now fully be initialized - check for changes in the additional folders |
|
112 | + $changesMem->Config(GSync::GetAdditionalSyncFolders(false)); |
|
113 | + |
|
114 | + // reset to default store in backend |
|
115 | + self::$backend->Setup(false); |
|
116 | + |
|
117 | + // there are unprocessed changes in the hierarchy, trigger resync |
|
118 | + if ($changesMem->GetChangeCount() > 0) { |
|
119 | + throw new StatusException("HandleFolderChange() can not proceed as there are unprocessed hierarchy changes", SYNC_FSSTATUS_SERVERERROR); |
|
120 | + } |
|
121 | + |
|
122 | + // any additional folders can not be modified - with exception if they are of type SYNC_FOLDER_TYPE_UNKNOWN (ZP-907) |
|
123 | + if (self::$deviceManager->GetFolderTypeFromCacheById($serverid) != SYNC_FOLDER_TYPE_UNKNOWN && $serverid !== false && GSync::GetAdditionalSyncFolderStore($backendid)) { |
|
124 | + throw new StatusException("HandleFolderChange() can not change additional folders which are configured", SYNC_FSSTATUS_SYSTEMFOLDER); |
|
125 | + } |
|
126 | + |
|
127 | + // switch user store if this this happens inside an additional folder |
|
128 | + // if this is an additional folder the backend has to be setup correctly |
|
129 | + // backend should also not be switched when type is SYNC_FOLDER_TYPE_UNKNOWN (ZP-1220) |
|
130 | + if (self::$deviceManager->GetFolderTypeFromCacheById($serverid) != SYNC_FOLDER_TYPE_UNKNOWN && !self::$backend->Setup(GSync::GetAdditionalSyncFolderStore((($parentBackendId != false) ? $parentBackendId : $backendid)))) { |
|
131 | + throw new StatusException(sprintf("HandleFolderChange() could not Setup() the backend for folder id '%s'", (($parentBackendId != false) ? $parentBackendId : $backendid)), SYNC_FSSTATUS_SERVERERROR); |
|
132 | + } |
|
133 | + } |
|
134 | + catch (StateNotFoundException $snfex) { |
|
135 | + $status = SYNC_FSSTATUS_SYNCKEYERROR; |
|
136 | + } |
|
137 | + catch (StatusException $stex) { |
|
138 | + $status = $stex->getCode(); |
|
139 | + } |
|
140 | + |
|
141 | + // set $newsynckey in case of an error |
|
142 | + if (!isset($newsynckey)) { |
|
143 | + $newsynckey = $synckey; |
|
144 | + } |
|
145 | + |
|
146 | + if ($status == SYNC_FSSTATUS_SUCCESS) { |
|
147 | + try { |
|
148 | + // Configure importer with last state |
|
149 | + $importer = self::$backend->GetImporter(); |
|
150 | + $importer->Config($syncstate); |
|
151 | + |
|
152 | + // the messages from the PIM will be forwarded to the real importer |
|
153 | + $changesMem->SetDestinationImporter($importer); |
|
154 | + |
|
155 | + // Create SyncFolder object |
|
156 | + $folder = new SyncFolder(); |
|
157 | + $folder->serverid = $serverid; |
|
158 | + $folder->parentid = $parentBackendId; |
|
159 | + if (isset($displayname)) { |
|
160 | + $folder->displayname = $displayname; |
|
161 | + } |
|
162 | + if (isset($type)) { |
|
163 | + $folder->type = $type; |
|
164 | + } |
|
165 | + // add the backendId to the SyncFolder object |
|
166 | + $folder->BackendId = $backendid; |
|
167 | + |
|
168 | + // process incoming change |
|
169 | + if (!$delete) { |
|
170 | + // when creating, $folder->serverid is false, and the returned id is already mapped by the backend |
|
171 | + $folder = $changesMem->ImportFolderChange($folder); |
|
172 | + } |
|
173 | + else { |
|
174 | + // delete folder |
|
175 | + $changesMem->ImportFolderDeletion($folder); |
|
176 | + } |
|
177 | + } |
|
178 | + catch (StatusException $stex) { |
|
179 | + $status = $stex->getCode(); |
|
180 | + } |
|
181 | + } |
|
182 | + |
|
183 | + self::$encoder->startWBXML(); |
|
184 | + if ($create) { |
|
185 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERCREATE); |
|
186 | + |
|
187 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
|
188 | + self::$encoder->content($status); |
|
189 | + self::$encoder->endTag(); |
|
190 | + |
|
191 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY); |
|
192 | + self::$encoder->content($newsynckey); |
|
193 | + self::$encoder->endTag(); |
|
194 | + |
|
195 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID); |
|
196 | + self::$encoder->content($folder->serverid); |
|
197 | + self::$encoder->endTag(); |
|
198 | + |
|
199 | + self::$encoder->endTag(); |
|
200 | + } |
|
201 | + elseif ($update) { |
|
202 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERUPDATE); |
|
203 | + |
|
204 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
|
205 | + self::$encoder->content($status); |
|
206 | + self::$encoder->endTag(); |
|
207 | + |
|
208 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY); |
|
209 | + self::$encoder->content($newsynckey); |
|
210 | + self::$encoder->endTag(); |
|
211 | + |
|
212 | + self::$encoder->endTag(); |
|
213 | + } |
|
214 | + elseif ($delete) { |
|
215 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERDELETE); |
|
216 | + |
|
217 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
|
218 | + self::$encoder->content($status); |
|
219 | + self::$encoder->endTag(); |
|
220 | + |
|
221 | + self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY); |
|
222 | + self::$encoder->content($newsynckey); |
|
223 | + self::$encoder->endTag(); |
|
224 | + |
|
225 | + self::$encoder->endTag(); |
|
226 | + } |
|
227 | + |
|
228 | + self::$topCollector->AnnounceInformation(sprintf("Operation status %d", $status), true); |
|
229 | + |
|
230 | + // Save the sync state for the next time |
|
231 | + if (isset($importer)) { |
|
232 | + self::$deviceManager->GetStateManager()->SetSyncState($newsynckey, $importer->GetState()); |
|
233 | + |
|
234 | + // update SPA & save it |
|
235 | + $spa->SetSyncKey($newsynckey); |
|
236 | + $spa->SetFolderId(false); |
|
237 | + self::$deviceManager->GetStateManager()->SetSynchedFolderState($spa); |
|
238 | + |
|
239 | + // invalidate all pingable flags |
|
240 | + SyncCollections::InvalidatePingableFlags(); |
|
241 | + } |
|
242 | + |
|
243 | + return true; |
|
244 | + } |
|
245 | 245 | } |
@@ -26,11 +26,9 @@ discard block |
||
26 | 26 | $create = $update = $delete = false; |
27 | 27 | if ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERCREATE) { |
28 | 28 | $create = true; |
29 | - } |
|
30 | - elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERUPDATE) { |
|
29 | + } elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERUPDATE) { |
|
31 | 30 | $update = true; |
32 | - } |
|
33 | - elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERDELETE) { |
|
31 | + } elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERDELETE) { |
|
34 | 32 | $delete = true; |
35 | 33 | } |
36 | 34 | |
@@ -130,11 +128,9 @@ discard block |
||
130 | 128 | if (self::$deviceManager->GetFolderTypeFromCacheById($serverid) != SYNC_FOLDER_TYPE_UNKNOWN && !self::$backend->Setup(GSync::GetAdditionalSyncFolderStore((($parentBackendId != false) ? $parentBackendId : $backendid)))) { |
131 | 129 | throw new StatusException(sprintf("HandleFolderChange() could not Setup() the backend for folder id '%s'", (($parentBackendId != false) ? $parentBackendId : $backendid)), SYNC_FSSTATUS_SERVERERROR); |
132 | 130 | } |
133 | - } |
|
134 | - catch (StateNotFoundException $snfex) { |
|
131 | + } catch (StateNotFoundException $snfex) { |
|
135 | 132 | $status = SYNC_FSSTATUS_SYNCKEYERROR; |
136 | - } |
|
137 | - catch (StatusException $stex) { |
|
133 | + } catch (StatusException $stex) { |
|
138 | 134 | $status = $stex->getCode(); |
139 | 135 | } |
140 | 136 | |
@@ -169,13 +165,11 @@ discard block |
||
169 | 165 | if (!$delete) { |
170 | 166 | // when creating, $folder->serverid is false, and the returned id is already mapped by the backend |
171 | 167 | $folder = $changesMem->ImportFolderChange($folder); |
172 | - } |
|
173 | - else { |
|
168 | + } else { |
|
174 | 169 | // delete folder |
175 | 170 | $changesMem->ImportFolderDeletion($folder); |
176 | 171 | } |
177 | - } |
|
178 | - catch (StatusException $stex) { |
|
172 | + } catch (StatusException $stex) { |
|
179 | 173 | $status = $stex->getCode(); |
180 | 174 | } |
181 | 175 | } |
@@ -197,8 +191,7 @@ discard block |
||
197 | 191 | self::$encoder->endTag(); |
198 | 192 | |
199 | 193 | self::$encoder->endTag(); |
200 | - } |
|
201 | - elseif ($update) { |
|
194 | + } elseif ($update) { |
|
202 | 195 | self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERUPDATE); |
203 | 196 | |
204 | 197 | self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
@@ -210,8 +203,7 @@ discard block |
||
210 | 203 | self::$encoder->endTag(); |
211 | 204 | |
212 | 205 | self::$encoder->endTag(); |
213 | - } |
|
214 | - elseif ($delete) { |
|
206 | + } elseif ($delete) { |
|
215 | 207 | self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERDELETE); |
216 | 208 | |
217 | 209 | self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS); |
@@ -8,127 +8,127 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class MoveItems extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the MoveItems command. |
|
13 | - * |
|
14 | - * @param int $commandCode |
|
15 | - * |
|
16 | - * @return bool |
|
17 | - */ |
|
18 | - public function Handle($commandCode) { |
|
19 | - if (!self::$decoder->getElementStartTag(SYNC_MOVE_MOVES)) { |
|
20 | - return false; |
|
21 | - } |
|
22 | - |
|
23 | - $moves = []; |
|
24 | - while (self::$decoder->getElementStartTag(SYNC_MOVE_MOVE)) { |
|
25 | - $move = []; |
|
26 | - if (self::$decoder->getElementStartTag(SYNC_MOVE_SRCMSGID)) { |
|
27 | - $move["srcmsgid"] = self::$decoder->getElementContent(); |
|
28 | - if (!self::$decoder->getElementEndTag()) { |
|
29 | - break; |
|
30 | - } |
|
31 | - } |
|
32 | - if (self::$decoder->getElementStartTag(SYNC_MOVE_SRCFLDID)) { |
|
33 | - $move["srcfldid"] = self::$decoder->getElementContent(); |
|
34 | - if (!self::$decoder->getElementEndTag()) { |
|
35 | - break; |
|
36 | - } |
|
37 | - } |
|
38 | - if (self::$decoder->getElementStartTag(SYNC_MOVE_DSTFLDID)) { |
|
39 | - $move["dstfldid"] = self::$decoder->getElementContent(); |
|
40 | - if (!self::$decoder->getElementEndTag()) { |
|
41 | - break; |
|
42 | - } |
|
43 | - } |
|
44 | - array_push($moves, $move); |
|
45 | - |
|
46 | - if (!self::$decoder->getElementEndTag()) { |
|
47 | - return false; |
|
48 | - } |
|
49 | - } |
|
50 | - |
|
51 | - if (!self::$decoder->getElementEndTag()) { |
|
52 | - return false; |
|
53 | - } |
|
54 | - |
|
55 | - self::$encoder->StartWBXML(); |
|
56 | - |
|
57 | - self::$encoder->startTag(SYNC_MOVE_MOVES); |
|
58 | - |
|
59 | - $operationResults = []; |
|
60 | - $operationCounter = 0; |
|
61 | - $operationTotal = count($moves); |
|
62 | - foreach ($moves as $move) { |
|
63 | - ++$operationCounter; |
|
64 | - self::$encoder->startTag(SYNC_MOVE_RESPONSE); |
|
65 | - self::$encoder->startTag(SYNC_MOVE_SRCMSGID); |
|
66 | - self::$encoder->content($move["srcmsgid"]); |
|
67 | - self::$encoder->endTag(); |
|
68 | - |
|
69 | - $status = SYNC_MOVEITEMSSTATUS_SUCCESS; |
|
70 | - $result = false; |
|
71 | - |
|
72 | - try { |
|
73 | - $sourceBackendFolderId = self::$deviceManager->GetBackendIdForFolderId($move["srcfldid"]); |
|
74 | - |
|
75 | - // if the source folder is an additional folder the backend has to be setup correctly |
|
76 | - if (!self::$backend->Setup(GSync::GetAdditionalSyncFolderStore($sourceBackendFolderId))) { |
|
77 | - throw new StatusException(sprintf("HandleMoveItems() could not Setup() the backend for folder id %s/%s", $move["srcfldid"], $sourceBackendFolderId), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); |
|
78 | - } |
|
79 | - |
|
80 | - $importer = self::$backend->GetImporter($sourceBackendFolderId); |
|
81 | - if ($importer === false) { |
|
82 | - throw new StatusException(sprintf("HandleMoveItems() could not get an importer for folder id %s/%s", $move["srcfldid"], $sourceBackendFolderId), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); |
|
83 | - } |
|
84 | - |
|
85 | - // get saved SyncParameters of the source folder |
|
86 | - $spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState($move["srcfldid"]); |
|
87 | - if (!$spa->HasSyncKey()) { |
|
88 | - throw new StatusException(sprintf("MoveItems(): Source folder id '%s' is not fully synchronized. Unable to perform operation.", $move["srcfldid"]), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); |
|
89 | - } |
|
90 | - |
|
91 | - $importer->ConfigContentParameters($spa->GetCPO()); |
|
92 | - |
|
93 | - $result = $importer->ImportMessageMove($move["srcmsgid"], self::$deviceManager->GetBackendIdForFolderId($move["dstfldid"])); |
|
94 | - // We discard the standard importer state for now. |
|
95 | - } |
|
96 | - catch (StatusException $stex) { |
|
97 | - if ($stex->getCode() == SYNC_STATUS_FOLDERHIERARCHYCHANGED) { // same as SYNC_FSSTATUS_CODEUNKNOWN |
|
98 | - $status = SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID; |
|
99 | - } |
|
100 | - else { |
|
101 | - $status = $stex->getCode(); |
|
102 | - } |
|
103 | - } |
|
104 | - |
|
105 | - if ($operationCounter % 10 == 0) { |
|
106 | - self::$topCollector->AnnounceInformation(sprintf("Moved %d objects out of %d", $operationCounter, $operationTotal)); |
|
107 | - } |
|
108 | - |
|
109 | - // save the operation result |
|
110 | - if (!isset($operationResults[$status])) { |
|
111 | - $operationResults[$status] = 0; |
|
112 | - } |
|
113 | - ++$operationResults[$status]; |
|
114 | - |
|
115 | - self::$encoder->startTag(SYNC_MOVE_STATUS); |
|
116 | - self::$encoder->content($status); |
|
117 | - self::$encoder->endTag(); |
|
118 | - |
|
119 | - self::$encoder->startTag(SYNC_MOVE_DSTMSGID); |
|
120 | - self::$encoder->content((($result !== false) ? $result : $move["srcmsgid"])); |
|
121 | - self::$encoder->endTag(); |
|
122 | - self::$encoder->endTag(); |
|
123 | - } |
|
124 | - |
|
125 | - self::$topCollector->AnnounceInformation(sprintf("Moved %d - Codes", $operationTotal), true); |
|
126 | - foreach ($operationResults as $status => $occurrences) { |
|
127 | - self::$topCollector->AnnounceInformation(sprintf("%dx%d", $occurrences, $status), true); |
|
128 | - } |
|
129 | - |
|
130 | - self::$encoder->endTag(); |
|
131 | - |
|
132 | - return true; |
|
133 | - } |
|
11 | + /** |
|
12 | + * Handles the MoveItems command. |
|
13 | + * |
|
14 | + * @param int $commandCode |
|
15 | + * |
|
16 | + * @return bool |
|
17 | + */ |
|
18 | + public function Handle($commandCode) { |
|
19 | + if (!self::$decoder->getElementStartTag(SYNC_MOVE_MOVES)) { |
|
20 | + return false; |
|
21 | + } |
|
22 | + |
|
23 | + $moves = []; |
|
24 | + while (self::$decoder->getElementStartTag(SYNC_MOVE_MOVE)) { |
|
25 | + $move = []; |
|
26 | + if (self::$decoder->getElementStartTag(SYNC_MOVE_SRCMSGID)) { |
|
27 | + $move["srcmsgid"] = self::$decoder->getElementContent(); |
|
28 | + if (!self::$decoder->getElementEndTag()) { |
|
29 | + break; |
|
30 | + } |
|
31 | + } |
|
32 | + if (self::$decoder->getElementStartTag(SYNC_MOVE_SRCFLDID)) { |
|
33 | + $move["srcfldid"] = self::$decoder->getElementContent(); |
|
34 | + if (!self::$decoder->getElementEndTag()) { |
|
35 | + break; |
|
36 | + } |
|
37 | + } |
|
38 | + if (self::$decoder->getElementStartTag(SYNC_MOVE_DSTFLDID)) { |
|
39 | + $move["dstfldid"] = self::$decoder->getElementContent(); |
|
40 | + if (!self::$decoder->getElementEndTag()) { |
|
41 | + break; |
|
42 | + } |
|
43 | + } |
|
44 | + array_push($moves, $move); |
|
45 | + |
|
46 | + if (!self::$decoder->getElementEndTag()) { |
|
47 | + return false; |
|
48 | + } |
|
49 | + } |
|
50 | + |
|
51 | + if (!self::$decoder->getElementEndTag()) { |
|
52 | + return false; |
|
53 | + } |
|
54 | + |
|
55 | + self::$encoder->StartWBXML(); |
|
56 | + |
|
57 | + self::$encoder->startTag(SYNC_MOVE_MOVES); |
|
58 | + |
|
59 | + $operationResults = []; |
|
60 | + $operationCounter = 0; |
|
61 | + $operationTotal = count($moves); |
|
62 | + foreach ($moves as $move) { |
|
63 | + ++$operationCounter; |
|
64 | + self::$encoder->startTag(SYNC_MOVE_RESPONSE); |
|
65 | + self::$encoder->startTag(SYNC_MOVE_SRCMSGID); |
|
66 | + self::$encoder->content($move["srcmsgid"]); |
|
67 | + self::$encoder->endTag(); |
|
68 | + |
|
69 | + $status = SYNC_MOVEITEMSSTATUS_SUCCESS; |
|
70 | + $result = false; |
|
71 | + |
|
72 | + try { |
|
73 | + $sourceBackendFolderId = self::$deviceManager->GetBackendIdForFolderId($move["srcfldid"]); |
|
74 | + |
|
75 | + // if the source folder is an additional folder the backend has to be setup correctly |
|
76 | + if (!self::$backend->Setup(GSync::GetAdditionalSyncFolderStore($sourceBackendFolderId))) { |
|
77 | + throw new StatusException(sprintf("HandleMoveItems() could not Setup() the backend for folder id %s/%s", $move["srcfldid"], $sourceBackendFolderId), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); |
|
78 | + } |
|
79 | + |
|
80 | + $importer = self::$backend->GetImporter($sourceBackendFolderId); |
|
81 | + if ($importer === false) { |
|
82 | + throw new StatusException(sprintf("HandleMoveItems() could not get an importer for folder id %s/%s", $move["srcfldid"], $sourceBackendFolderId), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); |
|
83 | + } |
|
84 | + |
|
85 | + // get saved SyncParameters of the source folder |
|
86 | + $spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState($move["srcfldid"]); |
|
87 | + if (!$spa->HasSyncKey()) { |
|
88 | + throw new StatusException(sprintf("MoveItems(): Source folder id '%s' is not fully synchronized. Unable to perform operation.", $move["srcfldid"]), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); |
|
89 | + } |
|
90 | + |
|
91 | + $importer->ConfigContentParameters($spa->GetCPO()); |
|
92 | + |
|
93 | + $result = $importer->ImportMessageMove($move["srcmsgid"], self::$deviceManager->GetBackendIdForFolderId($move["dstfldid"])); |
|
94 | + // We discard the standard importer state for now. |
|
95 | + } |
|
96 | + catch (StatusException $stex) { |
|
97 | + if ($stex->getCode() == SYNC_STATUS_FOLDERHIERARCHYCHANGED) { // same as SYNC_FSSTATUS_CODEUNKNOWN |
|
98 | + $status = SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID; |
|
99 | + } |
|
100 | + else { |
|
101 | + $status = $stex->getCode(); |
|
102 | + } |
|
103 | + } |
|
104 | + |
|
105 | + if ($operationCounter % 10 == 0) { |
|
106 | + self::$topCollector->AnnounceInformation(sprintf("Moved %d objects out of %d", $operationCounter, $operationTotal)); |
|
107 | + } |
|
108 | + |
|
109 | + // save the operation result |
|
110 | + if (!isset($operationResults[$status])) { |
|
111 | + $operationResults[$status] = 0; |
|
112 | + } |
|
113 | + ++$operationResults[$status]; |
|
114 | + |
|
115 | + self::$encoder->startTag(SYNC_MOVE_STATUS); |
|
116 | + self::$encoder->content($status); |
|
117 | + self::$encoder->endTag(); |
|
118 | + |
|
119 | + self::$encoder->startTag(SYNC_MOVE_DSTMSGID); |
|
120 | + self::$encoder->content((($result !== false) ? $result : $move["srcmsgid"])); |
|
121 | + self::$encoder->endTag(); |
|
122 | + self::$encoder->endTag(); |
|
123 | + } |
|
124 | + |
|
125 | + self::$topCollector->AnnounceInformation(sprintf("Moved %d - Codes", $operationTotal), true); |
|
126 | + foreach ($operationResults as $status => $occurrences) { |
|
127 | + self::$topCollector->AnnounceInformation(sprintf("%dx%d", $occurrences, $status), true); |
|
128 | + } |
|
129 | + |
|
130 | + self::$encoder->endTag(); |
|
131 | + |
|
132 | + return true; |
|
133 | + } |
|
134 | 134 | } |
@@ -92,12 +92,10 @@ |
||
92 | 92 | |
93 | 93 | $result = $importer->ImportMessageMove($move["srcmsgid"], self::$deviceManager->GetBackendIdForFolderId($move["dstfldid"])); |
94 | 94 | // We discard the standard importer state for now. |
95 | - } |
|
96 | - catch (StatusException $stex) { |
|
95 | + } catch (StatusException $stex) { |
|
97 | 96 | if ($stex->getCode() == SYNC_STATUS_FOLDERHIERARCHYCHANGED) { // same as SYNC_FSSTATUS_CODEUNKNOWN |
98 | 97 | $status = SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID; |
99 | - } |
|
100 | - else { |
|
98 | + } else { |
|
101 | 99 | $status = $stex->getCode(); |
102 | 100 | } |
103 | 101 | } |