@@ -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 | } |