grommunio /
grommunio-web
| 1 | <?php |
||
| 2 | /* |
||
| 3 | * In general |
||
| 4 | * |
||
| 5 | * This class never actually modifies a task item unless we receive a task request update. This means |
||
| 6 | * that setting all the properties to make the task item itself behave like a task request is up to the |
||
| 7 | * caller. |
||
| 8 | * |
||
| 9 | * The only exception to this is the generation of the TaskGlobalObjId, the unique identifier identifying |
||
| 10 | * this task request to both the organizer and the assignee. The globalobjectid is generated when the |
||
| 11 | * task request is sent via sendTaskRequest. |
||
| 12 | */ |
||
| 13 | |||
| 14 | /* The TaskMode value is only used for the IPM.TaskRequest items. |
||
| 15 | * It must 0 (tdmtNothing) on IPM.Task items. |
||
| 16 | * |
||
| 17 | * It is used to indicate the type of change that is being |
||
| 18 | * carried in the IPM.TaskRequest item (although this information seems |
||
| 19 | * redundant due to that information already being available in PR_MESSAGE_CLASS). |
||
| 20 | */ |
||
| 21 | define('tdmtNothing', 0); // Value in IPM.Task items |
||
| 22 | define('tdmtTaskReq', 1); // Assigner -> Assignee |
||
| 23 | define('tdmtTaskAcc', 2); // Assignee -> Assigner |
||
| 24 | define('tdmtTaskDec', 3); // Assignee -> Assigner |
||
| 25 | define('tdmtTaskUpd', 4); // Assignee -> Assigner |
||
| 26 | define('tdmtTaskSELF', 5); // Assigner -> Assigner (?) |
||
| 27 | |||
| 28 | /* The TaskHistory is used to show the last action on the task |
||
| 29 | * on both the assigner and the assignee's side. |
||
| 30 | * |
||
| 31 | * It is used in combination with 'task_assigned_time' and 'tasklastdelegate' |
||
| 32 | * or 'tasklastuser' to show the information at the top of the task request in |
||
| 33 | * the format 'Accepted by <user> on 01-01-2010 11:00'. |
||
| 34 | */ |
||
| 35 | define('thNone', 0); |
||
| 36 | define('thAccepted', 1); // Set by assignee |
||
| 37 | define('thDeclined', 2); // Set by assignee |
||
| 38 | define('thUpdated', 3); // Set by assignee |
||
| 39 | define('thDueDateChanged', 4); |
||
| 40 | define('thAssigned', 5); // Set by assigner |
||
| 41 | |||
| 42 | /* The TaskState value is used to differentiate the version of a task |
||
| 43 | * in the assigner's folder and the version in the |
||
| 44 | * assignee's folder. The buttons shown depend on this and |
||
| 45 | * the 'taskaccepted' boolean (for the assignee) |
||
| 46 | */ |
||
| 47 | define('tdsNOM', 0); // Got a response to a deleted task, and re-created the task for the assigner |
||
| 48 | define('tdsOWNNEW', 1); // Not assigned |
||
| 49 | define('tdsOWN', 2); // Assignee version |
||
| 50 | define('tdsACC', 3); // Assigner version |
||
| 51 | define('tdsDEC', 4); // Assigner version, but assignee declined |
||
| 52 | |||
| 53 | /* The TaskAcceptanceState is used for the assigner to indicate state */ |
||
| 54 | define('olTaskNotDelegated', 0); |
||
| 55 | define('olTaskDelegationUnknown', 1); // After sending req |
||
| 56 | define('olTaskDelegationAccepted', 2); // After receiving accept |
||
| 57 | define('olTaskDelegationDeclined', 3); // After receiving decline |
||
| 58 | |||
| 59 | /* The task ownership indicates the role of the current user relative to the task. */ |
||
| 60 | define('olNewTask', 0); |
||
| 61 | define('olDelegatedTask', 1); // Task has been assigned |
||
| 62 | define('olOwnTask', 2); // Task owned |
||
| 63 | |||
| 64 | /* taskmultrecips indicates whether the task request sent or received has multiple assignees or not. */ |
||
| 65 | define('tmrNone', 0); |
||
| 66 | define('tmrSent', 1); // Task has been sent to multiple assignee |
||
| 67 | define('tmrReceived', 2); // Task Request received has multiple assignee |
||
| 68 | |||
| 69 | //Task icon index. |
||
| 70 | define('ICON_TASK_ASSIGNEE', 0x00000502); |
||
| 71 | define('ICON_TASK_DECLINE', 0x00000506); |
||
| 72 | define('ICON_TASK_ASSIGNER', 0x00000503); |
||
| 73 | |||
| 74 | class TaskRequest { |
||
| 75 | |||
| 76 | // All recipient properties |
||
| 77 | var $recipProps = Array( |
||
| 78 | PR_ENTRYID, |
||
| 79 | PR_DISPLAY_NAME, |
||
| 80 | PR_EMAIL_ADDRESS, |
||
| 81 | PR_RECIPIENT_ENTRYID, |
||
| 82 | PR_RECIPIENT_TYPE, |
||
| 83 | PR_SEND_INTERNET_ENCODING, |
||
| 84 | PR_SEND_RICH_INFO, |
||
| 85 | PR_RECIPIENT_DISPLAY_NAME, |
||
| 86 | PR_ADDRTYPE, |
||
| 87 | PR_DISPLAY_TYPE, |
||
| 88 | PR_RECIPIENT_TRACKSTATUS, |
||
| 89 | PR_RECIPIENT_TRACKSTATUS_TIME, |
||
| 90 | PR_RECIPIENT_FLAGS, |
||
| 91 | PR_ROWID, |
||
| 92 | PR_SEARCH_KEY |
||
| 93 | ); |
||
| 94 | |||
| 95 | /* Constructor |
||
| 96 | * |
||
| 97 | * Constructs a TaskRequest object for the specified message. This can be either the task request |
||
| 98 | * message itself (in the inbox) or the task in the tasks folder, depending on the action to be performed. |
||
| 99 | * |
||
| 100 | * As a general rule, the object message passed is the object 'in view' when the user performs one of the |
||
| 101 | * actions in this class. |
||
| 102 | * |
||
| 103 | * @param $store store MAPI Store in which $message resides. This is also the store where the tasks folder is assumed to be in |
||
| 104 | * @param $message message MAPI Message to which the task request refers (can be an email or a task) |
||
| 105 | * @param $session session MAPI Session which is used to open tasks folders for delegated task requests or responses |
||
| 106 | */ |
||
| 107 | function __construct($store, $message, $session) { |
||
| 108 | $this->store = $store; |
||
| 109 | $this->message = $message; |
||
| 110 | $this->session = $session; |
||
| 111 | $this->taskCommentsInfo = false; |
||
| 112 | |||
| 113 | $properties["owner"] = "PT_STRING8:PSETID_Task:0x811f"; |
||
| 114 | $properties["updatecount"] = "PT_LONG:PSETID_Task:0x8112"; |
||
| 115 | $properties["taskstate"] = "PT_LONG:PSETID_Task:0x8113"; |
||
| 116 | $properties["taskmultrecips"] = "PT_LONG:PSETID_Task:0x8120"; |
||
| 117 | $properties["taskupdates"] = "PT_BOOLEAN:PSETID_Task:0x811b"; |
||
| 118 | $properties["tasksoc"] = "PT_BOOLEAN:PSETID_Task:0x8119"; |
||
| 119 | $properties["taskhistory"] = "PT_LONG:PSETID_Task:0x811a"; |
||
| 120 | $properties["taskmode"] = "PT_LONG:PSETID_Common:0x8518"; |
||
| 121 | $properties["task_goid"] = "PT_BINARY:PSETID_Common:0x8519"; |
||
| 122 | $properties["complete"] = "PT_BOOLEAN:PSETID_Common:0x811c"; |
||
| 123 | $properties["task_assigned_time"] = "PT_SYSTIME:PSETID_Task:0x8115"; |
||
| 124 | $properties["taskfcreator"] = "PT_BOOLEAN:PSETID_Task:0x0x811e"; |
||
| 125 | $properties["tasklastuser"] = "PT_STRING8:PSETID_Task:0x8122"; |
||
| 126 | $properties["tasklastdelegate"] = "PT_STRING8:PSETID_Task:0x8125"; |
||
| 127 | $properties["taskaccepted"] = "PT_BOOLEAN:PSETID_Task:0x8108"; |
||
| 128 | $properties["task_acceptance_state"] = "PT_LONG:PSETID_Task:0x812a"; |
||
| 129 | $properties["ownership"] = "PT_LONG:PSETID_Task:0x8129"; |
||
| 130 | |||
| 131 | $properties["complete"] = "PT_BOOLEAN:PSETID_Task:0x811c"; |
||
| 132 | $properties["datecompleted"] = "PT_SYSTIME:PSETID_Task:0x810f"; |
||
| 133 | $properties["recurring"] = "PT_BOOLEAN:PSETID_Task:0x8126"; |
||
| 134 | $properties["startdate"] = "PT_SYSTIME:PSETID_Task:0x8104"; |
||
| 135 | $properties["duedate"] = "PT_SYSTIME:PSETID_Task:0x8105"; |
||
| 136 | $properties["status"] = "PT_LONG:PSETID_Task:0x8101"; |
||
| 137 | $properties["percent_complete"] = "PT_DOUBLE:PSETID_Task:0x8102"; |
||
| 138 | $properties["totalwork"] = "PT_LONG:PSETID_Task:0x8111"; |
||
| 139 | $properties["actualwork"] = "PT_LONG:PSETID_Task:0x8110"; |
||
| 140 | $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords"; |
||
| 141 | $properties["companies"] = "PT_MV_STRING8:PSETID_Common:0x8539"; |
||
| 142 | $properties["mileage"] = "PT_STRING8:PSETID_Common:0x8534"; |
||
| 143 | $properties["billinginformation"] = "PT_STRING8:PSETID_Common:0x8535"; |
||
| 144 | |||
| 145 | $this->props = getPropIdsFromStrings($store, $properties); |
||
| 146 | } |
||
| 147 | |||
| 148 | // General functions |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Returns TRUE if the message pointed to is an incoming task request and should |
||
| 152 | * therefore be replied to with doAccept or doDecline(). |
||
| 153 | * @param String $messageClass message class to use for checking. |
||
| 154 | * @return Boolean Returns true if this is a task request else false. |
||
| 155 | */ |
||
| 156 | function isTaskRequest($messageClass = false) |
||
| 157 | { |
||
| 158 | if($messageClass === false) { |
||
| 159 | $props = mapi_getprops($this->message, Array(PR_MESSAGE_CLASS)); |
||
| 160 | $messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false; |
||
| 161 | } |
||
| 162 | |||
| 163 | if($messageClass !== false && $messageClass === "IPM.TaskRequest") { |
||
| 164 | return true; |
||
| 165 | } |
||
| 166 | |||
| 167 | return false; |
||
| 168 | } |
||
| 169 | |||
| 170 | /** |
||
| 171 | * Returns TRUE if the message pointed to is a returning task request response. |
||
| 172 | * @param String $messageClass message class to use for checking. |
||
| 173 | * @return Boolean Returns true if this is a task request else false. |
||
| 174 | */ |
||
| 175 | function isTaskRequestResponse($messageClass = false) |
||
| 176 | { |
||
| 177 | if($messageClass === false) { |
||
| 178 | $props = mapi_getprops($this->message, Array(PR_MESSAGE_CLASS)); |
||
| 179 | $messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false; |
||
| 180 | } |
||
| 181 | |||
| 182 | if($messageClass !== false && strpos($messageClass, "IPM.TaskRequest.") === 0) { |
||
| 183 | return true; |
||
| 184 | } |
||
| 185 | |||
| 186 | return false; |
||
| 187 | } |
||
| 188 | |||
| 189 | /** |
||
| 190 | * Returns TRUE if the message pointed to is an incoming task request/response. |
||
| 191 | * |
||
| 192 | * @param array $props The MAPI properties to check message is an incoming task request/response |
||
| 193 | * @return Boolean Returns true if this is an incoming task request/response. else false. |
||
| 194 | */ |
||
| 195 | function isReceivedItem($props) |
||
| 196 | { |
||
| 197 | return isset($props[PR_MESSAGE_TO_ME]) ? $props[PR_MESSAGE_TO_ME] : false; |
||
| 198 | } |
||
| 199 | |||
| 200 | /** |
||
| 201 | * Gets the task associated with an IPM.TaskRequest message |
||
| 202 | * |
||
| 203 | * If the task does not exist yet, it is created, using the attachment object in the |
||
| 204 | * task request item. |
||
| 205 | * |
||
| 206 | * @param boolean $create false to find the associated task in user's task folder. true to |
||
| 207 | * create task in user's task folder if task is not exist in task folder. |
||
| 208 | * |
||
| 209 | * @return MAPIMessage|false Return associated task of task request else false |
||
| 210 | */ |
||
| 211 | function getAssociatedTask($create) |
||
| 212 | { |
||
| 213 | $props = mapi_getprops($this->message, array(PR_MESSAGE_CLASS, $this->props['task_goid'])); |
||
| 214 | |||
| 215 | if($props[PR_MESSAGE_CLASS] == "IPM.Task") { |
||
| 216 | // Message itself is task, so return that |
||
| 217 | return $this->message; |
||
| 218 | } |
||
| 219 | |||
| 220 | $taskFolder = $this->getDefaultTasksFolder(); |
||
| 221 | $goid = $props[$this->props['task_goid']]; |
||
| 222 | |||
| 223 | // Find the task by looking for the task_goid |
||
| 224 | $restriction = array(RES_PROPERTY, array(RELOP => RELOP_EQ, |
||
| 225 | ULPROPTAG => $this->props['task_goid'], |
||
| 226 | VALUE => $goid) |
||
| 227 | ); |
||
| 228 | |||
| 229 | $contents = mapi_folder_getcontentstable($taskFolder); |
||
| 230 | |||
| 231 | $rows = mapi_table_queryallrows($contents, array(PR_ENTRYID), $restriction); |
||
| 232 | |||
| 233 | if(empty($rows)) { |
||
| 234 | // None found, create one if possible |
||
| 235 | if(!$create) { |
||
| 236 | return false; |
||
| 237 | } |
||
| 238 | |||
| 239 | $task = mapi_folder_createmessage($taskFolder); |
||
| 240 | |||
| 241 | $sub = $this->getEmbeddedTask($this->message); |
||
| 242 | mapi_copyto($sub, array(), array($this->props['categories']), $task); |
||
| 243 | |||
| 244 | $senderProps = array( |
||
| 245 | PR_SENT_REPRESENTING_NAME, |
||
| 246 | PR_SENT_REPRESENTING_EMAIL_ADDRESS, |
||
| 247 | PR_SENT_REPRESENTING_ENTRYID, |
||
| 248 | PR_SENT_REPRESENTING_ADDRTYPE, |
||
| 249 | PR_SENT_REPRESENTING_SEARCH_KEY, |
||
| 250 | PR_SENDER_NAME, |
||
| 251 | PR_SENDER_EMAIL_ADDRESS, |
||
| 252 | PR_SENDER_ENTRYID, |
||
| 253 | PR_SENDER_ADDRTYPE, |
||
| 254 | PR_SENDER_SEARCH_KEY); |
||
| 255 | |||
| 256 | // Copy sender information from the e-mail |
||
| 257 | $props = mapi_getprops($this->message, $senderProps); |
||
| 258 | $props[PR_MESSAGE_CLASS] = 'IPM.Task'; |
||
| 259 | mapi_setprops($task, $props); |
||
| 260 | } else { |
||
| 261 | // If there are multiple, just use the first |
||
| 262 | $entryid = $rows[0][PR_ENTRYID]; |
||
| 263 | |||
| 264 | $store = $this->getTaskFolderStore(); |
||
| 265 | $task = mapi_msgstore_openentry($store, $entryid); |
||
| 266 | } |
||
| 267 | |||
| 268 | return $task; |
||
| 269 | } |
||
| 270 | |||
| 271 | /** |
||
| 272 | * Function which checks that if we have received a task request/response |
||
| 273 | * for an already updated task in task folder. |
||
| 274 | * |
||
| 275 | * @return Boolean true if task request is updated later. |
||
| 276 | */ |
||
| 277 | function isTaskRequestUpdated() { |
||
| 278 | $props = mapi_getprops($this->message, array(PR_MESSAGE_CLASS, $this->props['task_goid'], $this->props['updatecount'])); |
||
| 279 | $result = false; |
||
| 280 | $associatedTask = $this->getAssociatedTask(false); |
||
| 281 | if ($this->isTaskRequest($props[PR_MESSAGE_CLASS])) { |
||
| 282 | if($associatedTask) { |
||
| 283 | return true; |
||
| 284 | } else { |
||
| 285 | $folder = $this->getDefaultTasksFolder(); |
||
| 286 | $goid = $props[$this->props['task_goid']]; |
||
| 287 | |||
| 288 | // Find the task by looking for the task_goid |
||
| 289 | $restriction = array(RES_PROPERTY, array(RELOP => RELOP_EQ, |
||
| 290 | ULPROPTAG => $this->props['task_goid'], |
||
| 291 | VALUE => $goid) |
||
| 292 | ); |
||
| 293 | |||
| 294 | $table = mapi_folder_getcontentstable($folder, MAPI_DEFERRED_ERRORS | SHOW_SOFT_DELETES); |
||
| 295 | $softDeletedItems = mapi_table_queryallrows($table, array(PR_ENTRYID), $restriction); |
||
| 296 | if (!empty($softDeletedItems)) { |
||
| 297 | return true; |
||
| 298 | } |
||
| 299 | } |
||
| 300 | } |
||
| 301 | |||
| 302 | if ($associatedTask !== false) { |
||
| 303 | $taskItemProps = mapi_getprops($associatedTask, array($this->props['updatecount'])); |
||
| 304 | /* |
||
| 305 | * if(message_counter < task_counter) task object is newer then task response (task is updated) |
||
| 306 | * if(message_counter >= task_counter) task is not updated, do normal processing |
||
| 307 | */ |
||
| 308 | if (isset($taskItemProps[$this->props['updatecount']]) && isset($props[$this->props['updatecount']])) { |
||
| 309 | if($props[$this->props['updatecount']] < $taskItemProps[$this->props['updatecount']]) { |
||
| 310 | $result = true; |
||
| 311 | } |
||
| 312 | } |
||
| 313 | } |
||
| 314 | return $result; |
||
| 315 | } |
||
| 316 | |||
| 317 | // Organizer functions (called by the organizer) |
||
| 318 | |||
| 319 | /** |
||
| 320 | * Processes a task request response, which can be any of the following: |
||
| 321 | * - Task accept (task history is marked as accepted) |
||
| 322 | * - Task decline (task history is marked as declined) |
||
| 323 | * - Task update (updates completion %, etc) |
||
| 324 | */ |
||
| 325 | function processTaskResponse() { |
||
| 326 | $messageProps = mapi_getprops($this->message, array(PR_PROCESSED, $this->props["taskupdates"], PR_MESSAGE_TO_ME)); |
||
| 327 | if (isset($messageProps[PR_PROCESSED]) && $messageProps[PR_PROCESSED]) { |
||
| 328 | return true; |
||
| 329 | } else { |
||
| 330 | mapi_setprops($this->message, Array(PR_PROCESSED => true)); |
||
| 331 | mapi_savechanges($this->message); |
||
| 332 | } |
||
| 333 | |||
| 334 | // Get the embedded task information. |
||
| 335 | $sub = $this->getEmbeddedTask($this->message); |
||
| 336 | // OL saves the task related properties in the embedded message |
||
| 337 | $subProps = mapi_getprops($sub, array($this->props["taskupdates"])); |
||
| 338 | |||
| 339 | // If task is updated in task folder then we don't need to process |
||
| 340 | // old response |
||
| 341 | if($this->isTaskRequestUpdated()) { |
||
| 342 | return true; |
||
| 343 | } |
||
| 344 | |||
| 345 | $isReceivedItem = $this->isReceivedItem($messageProps); |
||
| 346 | |||
| 347 | $isCreateAssociatedTask = false; |
||
| 348 | $isAllowUpdateAssociatedTask = $subProps[$this->props["taskupdates"]]; |
||
| 349 | $props = mapi_getprops($this->message, array(PR_MESSAGE_CLASS)); |
||
| 350 | // Set correct taskmode and taskhistory depending on response type |
||
| 351 | switch ($props[PR_MESSAGE_CLASS]) { |
||
| 352 | case 'IPM.TaskRequest.Accept': |
||
| 353 | $taskHistory = thAccepted; |
||
| 354 | $taskState = $isReceivedItem ? tdsACC : tdsOWN; |
||
| 355 | $taskOwner = $isReceivedItem ? olDelegatedTask : olOwnTask; |
||
| 356 | $taskAcceptanceState = $isReceivedItem ? olTaskDelegationAccepted : olTaskNotDelegated; |
||
| 357 | break; |
||
| 358 | case 'IPM.TaskRequest.Decline': |
||
| 359 | $isCreateAssociatedTask = $isReceivedItem; |
||
| 360 | $isAllowUpdateAssociatedTask = $isReceivedItem; |
||
| 361 | $taskHistory = thDeclined; |
||
| 362 | $taskState = $isReceivedItem ? tdsDEC : tdsACC; |
||
| 363 | $taskOwner = $isReceivedItem ? olOwnTask : olDelegatedTask; |
||
| 364 | $taskAcceptanceState = $isReceivedItem ? olTaskDelegationDeclined : olTaskDelegationUnknown; |
||
| 365 | break; |
||
| 366 | case 'IPM.TaskRequest.Update': |
||
| 367 | case 'IPM.TaskRequest.Complete': |
||
| 368 | $taskHistory = thUpdated; |
||
| 369 | $taskState = $isReceivedItem ? tdsACC : tdsOWN; |
||
| 370 | $taskAcceptanceState = olTaskNotDelegated; |
||
| 371 | $taskOwner = $isReceivedItem ? olDelegatedTask : olOwnTask; |
||
| 372 | break; |
||
| 373 | } |
||
| 374 | |||
| 375 | $props = array($this->props['taskhistory'] => $taskHistory, |
||
| 376 | $this->props['taskstate'] => $taskState, |
||
| 377 | $this->props['task_acceptance_state'] => $taskAcceptanceState, |
||
| 378 | $this->props['ownership'] => $taskOwner); |
||
| 379 | |||
| 380 | // Get the task for this response |
||
| 381 | $task = $this->getAssociatedTask($isCreateAssociatedTask); |
||
| 382 | if ($task && $isAllowUpdateAssociatedTask) { |
||
| 383 | // To avoid duplication of attachments in associated task. we simple remove the |
||
| 384 | // all attachments from associated task. |
||
| 385 | $taskAttachTable = mapi_message_getattachmenttable($task); |
||
| 386 | $taskAttachments = mapi_table_queryallrows($taskAttachTable, array(PR_ATTACH_NUM)); |
||
| 387 | foreach($taskAttachments as $taskAttach) { |
||
| 388 | mapi_message_deleteattach($task, $taskAttach[PR_ATTACH_NUM]); |
||
| 389 | } |
||
| 390 | |||
| 391 | $ignoreProps = array( |
||
| 392 | $this->props['taskstate'], |
||
| 393 | $this->props['taskhistory'], |
||
| 394 | $this->props['taskmode'], |
||
| 395 | $this->props['taskfcreator'] |
||
| 396 | ); |
||
| 397 | // Ignore PR_ICON_INDEX when task request response |
||
| 398 | // is not received item. |
||
| 399 | if ($isReceivedItem === false) { |
||
| 400 | $ignoreProps[] = PR_ICON_INDEX; |
||
| 401 | } |
||
| 402 | |||
| 403 | // We copy all properties except taskstate, taskhistory, taskmode and taskfcreator properties |
||
| 404 | // from $sub message to $task even also we copy all attachments from $sub to $task message. |
||
| 405 | mapi_copyto($sub, array(), $ignoreProps, $task); |
||
| 406 | $senderProps = mapi_getprops($this->message, array( |
||
| 407 | PR_SENDER_NAME, |
||
| 408 | PR_SENDER_EMAIL_ADDRESS, |
||
| 409 | PR_SENDER_ENTRYID, |
||
| 410 | PR_SENDER_ADDRTYPE, |
||
| 411 | PR_SENDER_SEARCH_KEY, |
||
| 412 | PR_MESSAGE_DELIVERY_TIME, |
||
| 413 | PR_SENT_REPRESENTING_NAME, |
||
| 414 | PR_SENT_REPRESENTING_EMAIL_ADDRESS, |
||
| 415 | PR_SENT_REPRESENTING_ADDRTYPE, |
||
| 416 | PR_SENT_REPRESENTING_ENTRYID, |
||
| 417 | PR_SENT_REPRESENTING_SEARCH_KEY)); |
||
| 418 | |||
| 419 | mapi_setprops($task, $senderProps); |
||
| 420 | |||
| 421 | // Update taskstate and task history (last action done by the assignee) |
||
| 422 | mapi_setprops($task,$props); |
||
| 423 | |||
| 424 | // Copy missing properties from embedded task |
||
| 425 | $subProperties = $this->getSubProperties(); |
||
| 426 | $subprops = mapi_getprops($sub, $subProperties); |
||
| 427 | mapi_setprops($task, $subprops); |
||
| 428 | |||
| 429 | mapi_savechanges($task); |
||
| 430 | } |
||
| 431 | |||
| 432 | mapi_setprops($this->message, $props); |
||
| 433 | mapi_savechanges($this->message); |
||
| 434 | |||
| 435 | if($isReceivedItem) { |
||
| 436 | $this->updateSentTaskRequest(); |
||
| 437 | } |
||
| 438 | return true; |
||
| 439 | } |
||
| 440 | |||
| 441 | /** |
||
| 442 | * Update the sent task request in sent items folder. |
||
| 443 | * @return bool |
||
| 444 | */ |
||
| 445 | function updateSentTaskRequest() { |
||
| 446 | $props = mapi_getprops($this->message, array( |
||
| 447 | $this->props['taskhistory'], |
||
| 448 | $this->props["taskstate"], |
||
| 449 | $this->props["ownership"], |
||
| 450 | $this->props['task_goid'], |
||
| 451 | $this->props['task_acceptance_state'], |
||
| 452 | $this->props["tasklastuser"], |
||
| 453 | $this->props["tasklastdelegate"])); |
||
| 454 | |||
| 455 | $store = $this->getDefaultStore(); |
||
| 456 | $storeProps = mapi_getprops($store, array(PR_IPM_SENTMAIL_ENTRYID)); |
||
| 457 | |||
| 458 | $sentFolder = mapi_msgstore_openentry($store, $storeProps[PR_IPM_SENTMAIL_ENTRYID]); |
||
| 459 | if(!$sentFolder) { |
||
| 460 | return false; |
||
| 461 | } |
||
| 462 | |||
| 463 | // Find the task by looking for the task_goid |
||
| 464 | $restriction = array(RES_PROPERTY, array(RELOP => RELOP_EQ, |
||
| 465 | ULPROPTAG => $this->props['task_goid'], |
||
| 466 | VALUE => $props[$this->props['task_goid']]) |
||
| 467 | ); |
||
| 468 | |||
| 469 | $contentsTable = mapi_folder_getcontentstable($sentFolder); |
||
| 470 | |||
| 471 | $rows = mapi_table_queryallrows($contentsTable, array(PR_ENTRYID), $restriction); |
||
| 472 | |||
| 473 | if(!empty($rows)) { |
||
| 474 | foreach ($rows as $row) { |
||
| 475 | $sentTaskRequest = mapi_msgstore_openentry($store, $row[PR_ENTRYID]); |
||
| 476 | mapi_setprops($sentTaskRequest, $props); |
||
| 477 | mapi_setprops($sentTaskRequest, array(PR_PROCESSED => true)); |
||
| 478 | mapi_savechanges($sentTaskRequest); |
||
| 479 | } |
||
| 480 | } |
||
| 481 | return true; |
||
| 482 | } |
||
| 483 | |||
| 484 | /* Create a new message in the current user's outbox and submit it |
||
| 485 | * |
||
| 486 | * Takes the task passed in the constructor as the task to be sent; recipient should |
||
| 487 | * be pre-existing. The task request will be sent to all recipients. |
||
| 488 | */ |
||
| 489 | function sendTaskRequest($prefix) { |
||
| 490 | // Generate a TaskGlobalObjectId |
||
| 491 | $taskid = $this->createTGOID(); |
||
| 492 | $messageprops = mapi_getprops($this->message, array(PR_SUBJECT)); |
||
| 493 | |||
| 494 | // Set properties on Task Request |
||
| 495 | mapi_setprops($this->message, array( |
||
| 496 | $this->props['task_goid'] => $taskid, /* our new task_goid */ |
||
| 497 | $this->props['taskstate'] => tdsACC, /* state for our outgoing request */ |
||
| 498 | $this->props['taskmode'] => tdmtNothing, /* we're not sending a change */ |
||
| 499 | $this->props['updatecount'] => 2, /* version 2 (no idea) */ |
||
| 500 | $this->props['task_acceptance_state'] => olTaskDelegationUnknown, /* no reply yet */ |
||
| 501 | $this->props['ownership'] => olDelegatedTask, /* Task has been assigned */ |
||
| 502 | $this->props['taskhistory'] => thAssigned, /* Task has been assigned */ |
||
| 503 | PR_CONVERSATION_TOPIC => $messageprops[PR_SUBJECT], |
||
| 504 | PR_ICON_INDEX => ICON_TASK_ASSIGNER |
||
| 505 | )); |
||
| 506 | $this->setLastUser(); |
||
| 507 | $this->setOwnerForAssignor(); |
||
| 508 | mapi_savechanges($this->message); |
||
| 509 | |||
| 510 | // Create outgoing task request message |
||
| 511 | $outgoing = $this->createOutgoingMessage(); |
||
| 512 | |||
| 513 | |||
| 514 | // No need to copy PR_ICON_INDEX and PR_SENT_* information in to outgoing message. |
||
| 515 | $ignoreProps = array(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); |
||
| 516 | mapi_copyto($this->message, array(), $ignoreProps, $outgoing); |
||
| 517 | |||
| 518 | // Make it a task request, and put it in sent items after it is sent |
||
| 519 | mapi_setprops($outgoing, array( |
||
| 520 | PR_MESSAGE_CLASS => "IPM.TaskRequest", /* class is task request */ |
||
| 521 | $this->props['taskstate'] => tdsOWN, /* for the recipient he is the task owner */ |
||
| 522 | $this->props['taskmode'] => tdmtTaskReq, /* for the recipient it's a request */ |
||
| 523 | $this->props['updatecount'] => 1, /* version 2 is in the attachment */ |
||
| 524 | PR_SUBJECT_PREFIX => $prefix, |
||
| 525 | PR_SUBJECT => $prefix . $messageprops[PR_SUBJECT] |
||
| 526 | )); |
||
| 527 | |||
| 528 | $attach = mapi_message_createattach($outgoing); |
||
| 529 | mapi_setprops($attach, array( |
||
| 530 | PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG, |
||
| 531 | PR_ATTACHMENT_HIDDEN => true, |
||
| 532 | PR_DISPLAY_NAME => $messageprops[PR_SUBJECT])); |
||
| 533 | |||
| 534 | $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_MODIFY | MAPI_CREATE); |
||
| 535 | |||
| 536 | mapi_copyto($this->message, array(), array(), $sub); |
||
| 537 | mapi_setprops($sub, array(PR_MESSAGE_CLASS => 'IPM.Task')); |
||
| 538 | |||
| 539 | mapi_savechanges($sub); |
||
| 540 | |||
| 541 | mapi_savechanges($attach); |
||
| 542 | |||
| 543 | mapi_savechanges($outgoing); |
||
| 544 | mapi_message_submitmessage($outgoing); |
||
| 545 | return true; |
||
| 546 | } |
||
| 547 | |||
| 548 | // Assignee functions (called by the assignee) |
||
| 549 | |||
| 550 | /* Update task version counter |
||
| 551 | * |
||
| 552 | * Must be called before each update to increase counter |
||
| 553 | */ |
||
| 554 | function updateTaskRequest() { |
||
| 555 | $messageprops = mapi_getprops($this->message, array($this->props['updatecount'])); |
||
| 556 | |||
| 557 | if(isset($messageprops)) { |
||
| 558 | $messageprops[$this->props['updatecount']]++; |
||
| 559 | } else { |
||
| 560 | $messageprops[$this->props['updatecount']] = 1; |
||
| 561 | } |
||
| 562 | |||
| 563 | mapi_setprops($this->message, $messageprops); |
||
| 564 | } |
||
| 565 | |||
| 566 | /* Process a task request |
||
| 567 | * |
||
| 568 | * Message passed should be an IPM.TaskRequest message. The task request is then processed to create |
||
| 569 | * the task in the tasks folder if needed. |
||
| 570 | */ |
||
| 571 | function processTaskRequest() { |
||
| 572 | if (!$this->isTaskRequest()) { |
||
| 573 | return false; |
||
| 574 | } |
||
| 575 | $messageProps = mapi_getprops($this->message, array(PR_PROCESSED, $this->props["taskupdates"], PR_MESSAGE_TO_ME)); |
||
| 576 | if (isset($messageProps[PR_PROCESSED]) && $messageProps[PR_PROCESSED]) { |
||
| 577 | return true; |
||
| 578 | } |
||
| 579 | |||
| 580 | // if task is updated in task folder then we don't need to process |
||
| 581 | // old request. |
||
| 582 | if($this->isTaskRequestUpdated()) { |
||
| 583 | return true; |
||
| 584 | } |
||
| 585 | |||
| 586 | $isReceivedItem = $this->isReceivedItem($messageProps); |
||
| 587 | |||
| 588 | $props = array(); |
||
| 589 | $props[PR_PROCESSED] = true; |
||
| 590 | $props[$this->props["taskstate"]] = $isReceivedItem ? tdsOWN : tdsACC; |
||
| 591 | $props[$this->props["ownership"]] = $isReceivedItem ? olOwnTask : olDelegatedTask; |
||
| 592 | |||
| 593 | mapi_setprops($this->message, $props); |
||
| 594 | mapi_savechanges($this->message); |
||
| 595 | |||
| 596 | // Don't create associated task in task folder if "taskupdates" is not true. |
||
| 597 | if (!$isReceivedItem && !$messageProps[$this->props["taskupdates"]]) { |
||
| 598 | return true; |
||
| 599 | } else { |
||
| 600 | // create an associated task in task folder while |
||
| 601 | // reading/loading task request on client side. |
||
| 602 | $task = $this->getAssociatedTask(true); |
||
| 603 | |||
| 604 | $taskProps = mapi_getprops($task, array($this->props['taskmultrecips'])); |
||
| 605 | $taskProps[$this->props["taskstate"]] = $isReceivedItem ? tdsOWN : tdsACC; |
||
| 606 | $taskProps[$this->props["taskhistory"]] = thAssigned; |
||
| 607 | $taskProps[$this->props["taskmode"]] = tdmtNothing; |
||
| 608 | $taskProps[$this->props["taskaccepted"]] = false; |
||
| 609 | $taskProps[$this->props["taskfcreator"]] = false; |
||
| 610 | $taskProps[$this->props["ownership"]] = $isReceivedItem ? olOwnTask : olDelegatedTask; |
||
| 611 | $taskProps[$this->props["task_acceptance_state"]] = olTaskNotDelegated; |
||
| 612 | $taskProps[PR_ICON_INDEX] = ICON_TASK_ASSIGNEE; |
||
| 613 | |||
| 614 | mapi_setprops($task, $taskProps); |
||
| 615 | $this->setAssignorInRecipients($task); |
||
| 616 | |||
| 617 | mapi_savechanges($task); |
||
| 618 | } |
||
| 619 | |||
| 620 | return true; |
||
| 621 | } |
||
| 622 | |||
| 623 | /** |
||
| 624 | * Accept a task request and send the response. |
||
| 625 | * |
||
| 626 | * Message passed should be an IPM.Task (eg the task from getAssociatedTask()) |
||
| 627 | * |
||
| 628 | * Copies the task to the user's task folder, sets it to accepted, and sends the acceptation |
||
| 629 | * message back to the organizer. The caller is responsible for removing the message. |
||
| 630 | * |
||
| 631 | * @return entryid EntryID of the accepted task |
||
| 632 | */ |
||
| 633 | function doAccept() { |
||
| 634 | $prefix = _("Task Accepted:") . " "; |
||
| 635 | $messageProps = mapi_getprops($this->message, array(PR_MESSAGE_CLASS, $this->props['taskstate'])); |
||
| 636 | |||
| 637 | if(!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
||
| 638 | // Can only accept assignee task |
||
| 639 | return false; |
||
| 640 | } |
||
| 641 | |||
| 642 | $this->setLastUser(); |
||
| 643 | $this->updateTaskRequest(); |
||
| 644 | |||
| 645 | $props = array( |
||
| 646 | $this->props['taskhistory'] => thAccepted, |
||
| 647 | $this->props['task_assigned_time'] => time(), |
||
| 648 | $this->props['taskaccepted'] => true, |
||
| 649 | $this->props['task_acceptance_state'] => olTaskNotDelegated); |
||
| 650 | |||
| 651 | // Message is TaskRequest then update the associated task as well. |
||
| 652 | if ($this->isTaskRequest($messageProps[PR_MESSAGE_CLASS])) { |
||
| 653 | $task = $this->getAssociatedTask(false); |
||
| 654 | if ($task) { |
||
| 655 | mapi_setprops($task, $props); |
||
| 656 | mapi_savechanges($task); |
||
| 657 | } |
||
| 658 | } |
||
| 659 | |||
| 660 | // Set as accepted |
||
| 661 | mapi_setprops($this->message, $props); |
||
| 662 | |||
| 663 | // As we copy the all properties from received message we need to remove following |
||
| 664 | // properties from accept response. |
||
| 665 | mapi_deleteprops($this->message, array(PR_MESSAGE_RECIP_ME, PR_MESSAGE_TO_ME, PR_MESSAGE_CC_ME, PR_PROCESSED)); |
||
| 666 | |||
| 667 | mapi_savechanges($this->message); |
||
| 668 | |||
| 669 | $this->sendResponse(tdmtTaskAcc, $prefix); |
||
| 670 | |||
| 671 | return $this->deleteReceivedTR(); |
||
| 672 | } |
||
| 673 | |||
| 674 | /* Decline a task request and send the response. |
||
| 675 | * |
||
| 676 | * Passed message must be a task request message, ie isTaskRequest() must return TRUE. |
||
| 677 | * |
||
| 678 | * Sends the decline message back to the organizer. The caller is responsible for removing the message. |
||
| 679 | * |
||
| 680 | * @return boolean TRUE on success, FALSE on failure |
||
| 681 | */ |
||
| 682 | function doDecline() { |
||
| 683 | $prefix = _("Task Declined:") . " "; |
||
| 684 | $messageProps = mapi_getprops($this->message, array($this->props['taskstate'])); |
||
| 685 | |||
| 686 | if(!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
||
| 687 | return false; // Can only decline assignee task |
||
| 688 | } |
||
| 689 | |||
| 690 | $this->setLastUser(); |
||
| 691 | $this->updateTaskRequest(); |
||
| 692 | |||
| 693 | // Set as declined |
||
| 694 | mapi_setprops($this->message, array( |
||
| 695 | $this->props['taskhistory'] => thDeclined, |
||
| 696 | $this->props['task_acceptance_state'] => olTaskDelegationDeclined |
||
| 697 | )); |
||
| 698 | mapi_deleteprops($this->message, array(PR_MESSAGE_RECIP_ME, PR_MESSAGE_TO_ME, PR_MESSAGE_CC_ME, PR_PROCESSED)); |
||
| 699 | mapi_savechanges($this->message); |
||
| 700 | |||
| 701 | $this->sendResponse(tdmtTaskDec, $prefix); |
||
| 702 | |||
| 703 | // Delete the associated task when task request is declined by the assignee. |
||
| 704 | $task = $this->getAssociatedTask(false); |
||
| 705 | if ($task) { |
||
| 706 | $taskFolder = $this->getDefaultTasksFolder(); |
||
| 707 | $props = mapi_getprops($task, array(PR_ENTRYID)); |
||
| 708 | mapi_folder_deletemessages($taskFolder, array($props[PR_ENTRYID])); |
||
| 709 | } |
||
| 710 | return $this->deleteReceivedTR(); |
||
| 711 | } |
||
| 712 | |||
| 713 | /** |
||
| 714 | * Send an update of the task if requested, and send the Status-On-Completion report if complete and requested |
||
| 715 | * |
||
| 716 | * If no updates were requested from the organizer, this function does nothing. |
||
| 717 | * |
||
| 718 | * @return boolean TRUE if the update succeeded, FALSE otherwise. |
||
| 719 | */ |
||
| 720 | function doUpdate() { |
||
| 721 | $messageProps = mapi_getprops($this->message, array($this->props['taskstate'], PR_SUBJECT)); |
||
| 722 | |||
| 723 | if(!isset($messageProps[$this->props['taskstate']]) || $messageProps[$this->props['taskstate']] != tdsOWN) { |
||
| 724 | return false; // Can only update assignee task |
||
| 725 | } |
||
| 726 | |||
| 727 | $this->setLastUser(); |
||
| 728 | $this->updateTaskRequest(); |
||
| 729 | |||
| 730 | // Set as updated |
||
| 731 | mapi_setprops($this->message, array($this->props['taskhistory'] => thUpdated)); |
||
| 732 | |||
| 733 | mapi_savechanges($this->message); |
||
| 734 | |||
| 735 | $props = mapi_getprops($this->message, array($this->props['taskupdates'], $this->props['tasksoc'], $this->props['recurring'], $this->props['complete'])); |
||
| 736 | if (!$props[$this->props['complete']] && $props[$this->props['taskupdates']] && !(isset($props[$this->props['recurring']]) && $props[$this->props['recurring']])) { |
||
| 737 | $this->sendResponse(tdmtTaskUpd, _("Task Updated:") . " "); |
||
| 738 | } else if($props[$this->props['complete']]) { |
||
| 739 | $this->sendResponse(tdmtTaskUpd, _("Task Completed:") . " "); |
||
| 740 | } |
||
| 741 | } |
||
| 742 | |||
| 743 | /** |
||
| 744 | * Get the store associated with the task |
||
| 745 | * |
||
| 746 | * Normally this will just open the store that the processed message is in. However, if the message is opened |
||
| 747 | * by a delegate, this function opens the store that the message was delegated from. |
||
| 748 | */ |
||
| 749 | function getTaskFolderStore() |
||
| 750 | { |
||
| 751 | $ownerentryid = false; |
||
| 752 | |||
| 753 | $rcvdprops = mapi_getprops($this->message, array(PR_RCVD_REPRESENTING_ENTRYID)); |
||
| 754 | if(isset($rcvdprops[PR_RCVD_REPRESENTING_ENTRYID])) { |
||
| 755 | $ownerentryid = $rcvdprops[PR_RCVD_REPRESENTING_ENTRYID]; |
||
| 756 | } |
||
| 757 | |||
| 758 | if(!$ownerentryid) { |
||
| 759 | $store = $this->store; |
||
| 760 | } else { |
||
| 761 | $ab = mapi_openaddressbook($this->session); |
||
| 762 | if(!$ab) return false; |
||
| 763 | |||
| 764 | $mailuser = mapi_ab_openentry($ab, $ownerentryid); |
||
| 765 | if(!$mailuser) return false; |
||
| 766 | |||
| 767 | $mailuserprops = mapi_getprops($mailuser, array(PR_EMAIL_ADDRESS)); |
||
| 768 | if(!isset($mailuserprops[PR_EMAIL_ADDRESS])) return false; |
||
| 769 | |||
| 770 | $storeid = mapi_msgstore_createentryid($this->store, $mailuserprops[PR_EMAIL_ADDRESS]); |
||
| 771 | |||
| 772 | $store = mapi_openmsgstore($this->session, $storeid); |
||
| 773 | |||
| 774 | } |
||
| 775 | return $store; |
||
| 776 | } |
||
| 777 | |||
| 778 | /** |
||
| 779 | * Open the default task folder for the current user, or the specified user if passed |
||
| 780 | */ |
||
| 781 | function getDefaultTasksFolder() |
||
| 782 | { |
||
| 783 | $store = $this->getTaskFolderStore(); |
||
| 784 | |||
| 785 | $inbox = mapi_msgstore_getreceivefolder($store); |
||
| 786 | $inboxprops = mapi_getprops($inbox, Array(PR_IPM_TASK_ENTRYID)); |
||
| 787 | if(!isset($inboxprops[PR_IPM_TASK_ENTRYID])) |
||
| 788 | return false; |
||
| 789 | |||
| 790 | return mapi_msgstore_openentry($store, $inboxprops[PR_IPM_TASK_ENTRYID]); |
||
| 791 | } |
||
| 792 | |||
| 793 | /** |
||
| 794 | * Function prepare the sent representing properties from given MAPI store. |
||
| 795 | * @param $store MAPI store object |
||
| 796 | * @return array|bool if store is not mail box owner entryid then |
||
| 797 | * return false else prepare the sent representing props and return it. |
||
| 798 | */ |
||
| 799 | function getSentReprProps($store) |
||
| 800 | { |
||
| 801 | $storeprops = mapi_getprops($store, array(PR_MAILBOX_OWNER_ENTRYID)); |
||
| 802 | if (!isset($storeprops[PR_MAILBOX_OWNER_ENTRYID])) { |
||
| 803 | return false; |
||
| 804 | } |
||
| 805 | |||
| 806 | $ab = mapi_openaddressbook($this->session); |
||
| 807 | $mailuser = mapi_ab_openentry($ab, $storeprops[PR_MAILBOX_OWNER_ENTRYID]); |
||
| 808 | $mailuserprops = mapi_getprops($mailuser, array(PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_DISPLAY_NAME, PR_SEARCH_KEY, PR_ENTRYID)); |
||
| 809 | |||
| 810 | $props = array(); |
||
| 811 | $props[PR_SENT_REPRESENTING_ADDRTYPE] = $mailuserprops[PR_ADDRTYPE]; |
||
| 812 | $props[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $mailuserprops[PR_EMAIL_ADDRESS]; |
||
| 813 | $props[PR_SENT_REPRESENTING_NAME] = $mailuserprops[PR_DISPLAY_NAME]; |
||
| 814 | $props[PR_SENT_REPRESENTING_SEARCH_KEY] = $mailuserprops[PR_SEARCH_KEY]; |
||
| 815 | $props[PR_SENT_REPRESENTING_ENTRYID] = $mailuserprops[PR_ENTRYID]; |
||
| 816 | |||
| 817 | return $props; |
||
| 818 | } |
||
| 819 | |||
| 820 | /** |
||
| 821 | * Creates an outgoing message based on the passed message - will set delegate information |
||
| 822 | * and sent mail folder |
||
| 823 | */ |
||
| 824 | function createOutgoingMessage() |
||
| 825 | { |
||
| 826 | // Open our default store for this user (that's the only store we can submit in) |
||
| 827 | $store = $this->getDefaultStore(); |
||
| 828 | $storeprops = mapi_getprops($store, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID)); |
||
| 829 | |||
| 830 | $outbox = mapi_msgstore_openentry($store, $storeprops[PR_IPM_OUTBOX_ENTRYID]); |
||
| 831 | if(!$outbox) return false; |
||
| 832 | |||
| 833 | $outgoing = mapi_folder_createmessage($outbox); |
||
| 834 | if(!$outgoing) return false; |
||
| 835 | |||
| 836 | // Set SENT_REPRESENTING in case we're sending as a delegate |
||
| 837 | $ownerstore = $this->getTaskFolderStore(); |
||
| 838 | $sentreprprops = $this->getSentReprProps($ownerstore); |
||
| 839 | mapi_setprops($outgoing, $sentreprprops); |
||
| 840 | |||
| 841 | mapi_setprops($outgoing, array(PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID])); |
||
| 842 | |||
| 843 | return $outgoing; |
||
| 844 | } |
||
| 845 | |||
| 846 | /** |
||
| 847 | * Send a response message (from assignee back to organizer). |
||
| 848 | * |
||
| 849 | * @param $type int Type of response (tdmtTaskAcc, tdmtTaskDec, tdmtTaskUpd); |
||
| 850 | * @return boolean TRUE on success |
||
| 851 | */ |
||
| 852 | function sendResponse($type, $prefix) |
||
| 853 | { |
||
| 854 | // Create a message in our outbox |
||
| 855 | $outgoing = $this->createOutgoingMessage(); |
||
| 856 | $messageprops = mapi_getprops($this->message, array(PR_CONVERSATION_TOPIC, PR_MESSAGE_CLASS, $this->props['complete'])); |
||
| 857 | |||
| 858 | $attach = mapi_message_createattach($outgoing); |
||
| 859 | mapi_setprops($attach, array(PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG, PR_DISPLAY_NAME => $messageprops[PR_CONVERSATION_TOPIC], PR_ATTACHMENT_HIDDEN => true)); |
||
| 860 | $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_CREATE | MAPI_MODIFY); |
||
| 861 | |||
| 862 | $message = !$this->isTaskRequest() ? $this->message : $this->getAssociatedTask(false); |
||
| 863 | |||
| 864 | $ignoreProps = array(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); |
||
| 865 | |||
| 866 | mapi_copyto($message, array(), $ignoreProps, $outgoing); |
||
| 867 | mapi_copyto($message, array(), array(), $sub); |
||
| 868 | |||
| 869 | if (!$this->setRecipientsForResponse($outgoing, $type)) { |
||
| 870 | return false; |
||
| 871 | } |
||
| 872 | |||
| 873 | $props = array(); |
||
| 874 | switch($type) { |
||
| 875 | case tdmtTaskAcc: |
||
| 876 | $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Accept"; |
||
| 877 | mapi_setprops($sub,array(PR_ICON_INDEX => ICON_TASK_ASSIGNER)); |
||
| 878 | break; |
||
| 879 | case tdmtTaskDec: |
||
| 880 | $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Decline"; |
||
| 881 | mapi_setprops($sub,array(PR_ICON_INDEX => ICON_TASK_DECLINE)); |
||
| 882 | break; |
||
| 883 | case tdmtTaskUpd: |
||
| 884 | mapi_setprops($sub,array(PR_ICON_INDEX => ICON_TASK_ASSIGNER)); |
||
| 885 | if($messageprops[$this->props['complete']]) { |
||
| 886 | $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Complete"; |
||
| 887 | } else { |
||
| 888 | $props[PR_MESSAGE_CLASS] = "IPM.TaskRequest.Update"; |
||
| 889 | } |
||
| 890 | |||
| 891 | break; |
||
| 892 | }; |
||
| 893 | |||
| 894 | mapi_savechanges($sub); |
||
| 895 | mapi_savechanges($attach); |
||
| 896 | |||
| 897 | $props[PR_SUBJECT] = $prefix . $messageprops[PR_CONVERSATION_TOPIC]; |
||
| 898 | $props[$this->props['taskmode']] = $type; |
||
| 899 | $props[$this->props['task_assigned_time']] = time(); |
||
| 900 | |||
| 901 | mapi_setprops($outgoing, $props); |
||
| 902 | |||
| 903 | // taskCommentsInfo contains some comments which added by assignee while |
||
| 904 | // edit response before sending task response. |
||
| 905 | if ($this->taskCommentsInfo) { |
||
| 906 | $comments = $this->getTaskCommentsInfo(); |
||
| 907 | $stream = mapi_openproperty($outgoing, PR_BODY, IID_IStream, 0, MAPI_CREATE | MAPI_MODIFY); |
||
| 908 | mapi_stream_setsize($stream, strlen($comments)); |
||
| 909 | mapi_stream_write($stream, $comments); |
||
| 910 | mapi_stream_commit($stream); |
||
| 911 | } |
||
| 912 | |||
| 913 | mapi_savechanges($outgoing); |
||
| 914 | mapi_message_submitmessage($outgoing); |
||
| 915 | return true; |
||
| 916 | } |
||
| 917 | |||
| 918 | function getDefaultStore() |
||
| 919 | { |
||
| 920 | $table = mapi_getmsgstorestable($this->session); |
||
| 921 | $rows = mapi_table_queryallrows($table, array(PR_DEFAULT_STORE, PR_ENTRYID)); |
||
| 922 | |||
| 923 | foreach($rows as $row) { |
||
| 924 | if($row[PR_DEFAULT_STORE]) |
||
| 925 | return mapi_openmsgstore($this->session, $row[PR_ENTRYID]); |
||
| 926 | } |
||
| 927 | |||
| 928 | return false; |
||
| 929 | } |
||
| 930 | |||
| 931 | /** |
||
| 932 | * Creates a new TaskGlobalObjId |
||
| 933 | * |
||
| 934 | * Just 16 bytes of random data |
||
| 935 | */ |
||
| 936 | function createTGOID() |
||
| 937 | { |
||
| 938 | $goid = ""; |
||
| 939 | for($i=0;$i<16;$i++) { |
||
| 940 | $goid .= chr(rand(0, 255)); |
||
| 941 | } |
||
| 942 | return $goid; |
||
| 943 | } |
||
| 944 | |||
| 945 | /** |
||
| 946 | * Function used to get the embedded task of task request. Which further used to |
||
| 947 | * Create/Update associated task of assigner/assignee. |
||
| 948 | * |
||
| 949 | * @param object $message which contains embedded task. |
||
| 950 | * @return object|false $task if found embedded task else false |
||
| 951 | */ |
||
| 952 | function getEmbeddedTask($message) { |
||
| 953 | $task = false; |
||
| 954 | $goid = mapi_getprops($this->message, array($this->props["task_goid"])); |
||
| 955 | $attachmentTable = mapi_message_getattachmenttable($this->message); |
||
| 956 | $restriction = array(RES_PROPERTY, |
||
| 957 | array(RELOP => RELOP_EQ, |
||
| 958 | ULPROPTAG => PR_ATTACH_METHOD, |
||
| 959 | VALUE => ATTACH_EMBEDDED_MSG) |
||
| 960 | ); |
||
| 961 | $rows = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM), $restriction); |
||
| 962 | |||
| 963 | if(empty($rows)) { |
||
| 964 | return $task; |
||
| 965 | } |
||
| 966 | |||
| 967 | foreach ($rows as $row) { |
||
| 968 | try { |
||
| 969 | $attach = mapi_message_openattach($this->message, $row[PR_ATTACH_NUM]); |
||
| 970 | $task = mapi_attach_openobj($attach); |
||
| 971 | } catch (MAPIException $e) { |
||
| 972 | continue; |
||
| 973 | } |
||
| 974 | |||
| 975 | $taskGoid = mapi_getprops($task, array($this->props["task_goid"])); |
||
| 976 | if($goid[$this->props["task_goid"]] === $taskGoid[$this->props["task_goid"]]) { |
||
| 977 | mapi_setprops($attach, array(PR_ATTACHMENT_HIDDEN => true)); |
||
| 978 | mapi_savechanges($attach); |
||
| 979 | mapi_savechanges($this->message); |
||
| 980 | break; |
||
| 981 | } |
||
| 982 | } |
||
| 983 | return $task; |
||
| 984 | } |
||
| 985 | |||
| 986 | /** |
||
| 987 | * Function was used to set the user name who has last used this task also it was |
||
| 988 | * update the tasklastdelegate and task_assigned_time. |
||
| 989 | */ |
||
| 990 | function setLastUser() |
||
| 991 | { |
||
| 992 | $delegatestore = $this->getDefaultStore(); |
||
| 993 | $taskstore = $this->getTaskFolderStore(); |
||
| 994 | |||
| 995 | $delegateprops = mapi_getprops($delegatestore, array(PR_MAILBOX_OWNER_NAME)); |
||
| 996 | $taskprops = mapi_getprops($taskstore, array(PR_MAILBOX_OWNER_NAME)); |
||
| 997 | |||
| 998 | // The owner of the task |
||
| 999 | $username = $delegateprops[PR_MAILBOX_OWNER_NAME]; |
||
| 1000 | // This is me (the one calling the script) |
||
| 1001 | $delegate = $taskprops[PR_MAILBOX_OWNER_NAME]; |
||
| 1002 | |||
| 1003 | if ($this->isTaskRequest()) { |
||
| 1004 | $task = $this->getAssociatedTask(false); |
||
| 1005 | mapi_setprops($task, array($this->props["tasklastuser"] => $username, $this->props["tasklastdelegate"] => $delegate, $this->props['task_assigned_time'] => time())); |
||
| 1006 | mapi_savechanges($task); |
||
| 1007 | } |
||
| 1008 | mapi_setprops($this->message, array($this->props["tasklastuser"] => $username, $this->props["tasklastdelegate"] => $delegate, $this->props['task_assigned_time'] => time())); |
||
| 1009 | } |
||
| 1010 | |||
| 1011 | /** |
||
| 1012 | * Assignee becomes the owner when a user/assignor assigns any task to someone. Also there can be more than one assignee. |
||
| 1013 | * This function sets assignee as owner in the assignor's copy of task. |
||
| 1014 | */ |
||
| 1015 | function setOwnerForAssignor() |
||
| 1016 | { |
||
| 1017 | $recipTable = mapi_message_getrecipienttable($this->message); |
||
| 1018 | $recips = mapi_table_queryallrows($recipTable, array(PR_DISPLAY_NAME)); |
||
| 1019 | |||
| 1020 | if (!empty($recips)) { |
||
| 1021 | $owner = array(); |
||
| 1022 | foreach ($recips as $value) { |
||
| 1023 | $owner[] = $value[PR_DISPLAY_NAME]; |
||
| 1024 | } |
||
| 1025 | |||
| 1026 | $props = array($this->props['owner'] => implode("; ", $owner)); |
||
| 1027 | mapi_setprops($this->message, $props); |
||
| 1028 | } |
||
| 1029 | } |
||
| 1030 | |||
| 1031 | /** |
||
| 1032 | * Sets assignor as recipients in assignee's copy of task. |
||
| 1033 | * |
||
| 1034 | * If assignor has requested task updates then the assignor is added as recipient type MAPI_CC. |
||
| 1035 | * |
||
| 1036 | * Also if assignor has request SOC then the assignor is also add as recipient type MAPI_BCC |
||
| 1037 | * |
||
| 1038 | * @param $task message MAPI message which assignee's copy of task |
||
| 1039 | */ |
||
| 1040 | function setAssignorInRecipients($task) |
||
| 1041 | { |
||
| 1042 | $recipTable = mapi_message_getrecipienttable($task); |
||
| 1043 | |||
| 1044 | // Delete all MAPI_TO recipients |
||
| 1045 | $recips = mapi_table_queryallrows($recipTable, array(PR_ROWID), array(RES_PROPERTY, |
||
| 1046 | array( RELOP => RELOP_EQ, |
||
| 1047 | ULPROPTAG => PR_RECIPIENT_TYPE, |
||
| 1048 | VALUE => MAPI_TO |
||
| 1049 | ))); |
||
| 1050 | foreach($recips as $recip) { |
||
| 1051 | mapi_message_modifyrecipients($task, MODRECIP_REMOVE, array($recip)); |
||
| 1052 | } |
||
| 1053 | |||
| 1054 | $recips = array(); |
||
| 1055 | $taskReqProps = mapi_getprops($this->message, array(PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_SEARCH_KEY)); |
||
| 1056 | $associatedTaskProps = mapi_getprops($task, array($this->props['taskupdates'], $this->props['tasksoc'], $this->props['taskmultrecips'])); |
||
| 1057 | |||
| 1058 | // Build assignor info |
||
| 1059 | $assignor = array( |
||
| 1060 | PR_ENTRYID => $taskReqProps[PR_SENT_REPRESENTING_ENTRYID], |
||
| 1061 | PR_DISPLAY_NAME => $taskReqProps[PR_SENT_REPRESENTING_NAME], |
||
| 1062 | PR_EMAIL_ADDRESS => $taskReqProps[PR_SENT_REPRESENTING_EMAIL_ADDRESS], |
||
| 1063 | PR_RECIPIENT_DISPLAY_NAME => $taskReqProps[PR_SENT_REPRESENTING_NAME], |
||
| 1064 | PR_ADDRTYPE => empty($taskReqProps[PR_SENT_REPRESENTING_ADDRTYPE]) ? 'SMTP' : $taskReqProps[PR_SENT_REPRESENTING_ADDRTYPE], |
||
| 1065 | PR_RECIPIENT_FLAGS => recipSendable, |
||
| 1066 | PR_SEARCH_KEY => $taskReqProps[PR_SENT_REPRESENTING_SEARCH_KEY] |
||
| 1067 | ); |
||
| 1068 | |||
| 1069 | // Assignor has requested task updates, so set him/her as MAPI_CC in recipienttable. |
||
| 1070 | if ((isset($associatedTaskProps[$this->props['taskupdates']]) && $associatedTaskProps[$this->props['taskupdates']]) |
||
| 1071 | && !(isset($associatedTaskProps[$this->props['taskmultrecips']]) && $associatedTaskProps[$this->props['taskmultrecips']] == tmrReceived)) { |
||
| 1072 | $assignor[PR_RECIPIENT_TYPE] = MAPI_CC; |
||
| 1073 | $recips[] = $assignor; |
||
| 1074 | } |
||
| 1075 | |||
| 1076 | // Assignor wants to receive an email report when task is mark as 'Complete', so in recipients as MAPI_BCC |
||
| 1077 | if ($associatedTaskProps[$this->props['tasksoc']]) { |
||
| 1078 | $assignor[PR_RECIPIENT_TYPE] = MAPI_BCC; |
||
| 1079 | $recips[] = $assignor; |
||
| 1080 | } |
||
| 1081 | |||
| 1082 | if (!empty($recips)) { |
||
| 1083 | mapi_message_modifyrecipients($task, MODRECIP_ADD, $recips); |
||
| 1084 | } |
||
| 1085 | } |
||
| 1086 | |||
| 1087 | /** |
||
| 1088 | * Deletes incoming task request from Inbox |
||
| 1089 | * |
||
| 1090 | * @returns array returns PR_ENTRYID, PR_STORE_ENTRYID and PR_PARENT_ENTRYID of the deleted task request |
||
| 1091 | */ |
||
| 1092 | function deleteReceivedTR() |
||
| 1093 | { |
||
| 1094 | $store = $this->getTaskFolderStore(); |
||
| 1095 | $storeType = mapi_getprops($store, array(PR_MDB_PROVIDER)); |
||
| 1096 | if ($storeType[PR_MDB_PROVIDER] === ZARAFA_STORE_PUBLIC_GUID) { |
||
| 1097 | $store = $this->getDefaultStore(); |
||
| 1098 | } |
||
| 1099 | $inbox = mapi_msgstore_getreceivefolder($store); |
||
| 1100 | |||
| 1101 | $storeProps = mapi_getprops($store, array(PR_IPM_WASTEBASKET_ENTRYID)); |
||
| 1102 | $props = mapi_getprops($this->message, array($this->props['task_goid'])); |
||
| 1103 | $goid = $props[$this->props['task_goid']]; |
||
| 1104 | |||
| 1105 | // Find the task by looking for the task_goid |
||
| 1106 | $restriction = array(RES_PROPERTY, |
||
| 1107 | array(RELOP => RELOP_EQ, |
||
| 1108 | ULPROPTAG => $this->props['task_goid'], |
||
| 1109 | VALUE => $goid) |
||
| 1110 | ); |
||
| 1111 | |||
| 1112 | $contents = mapi_folder_getcontentstable($inbox); |
||
| 1113 | |||
| 1114 | $rows = mapi_table_queryallrows($contents, array(PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID), $restriction); |
||
| 1115 | |||
| 1116 | if(!empty($rows)) { |
||
| 1117 | // If there are multiple, just use the first |
||
| 1118 | $entryid = $rows[0][PR_ENTRYID]; |
||
| 1119 | $wastebasket = mapi_msgstore_openentry($store, $storeProps[PR_IPM_WASTEBASKET_ENTRYID]); |
||
| 1120 | mapi_folder_copymessages($inbox, Array($entryid), $wastebasket, MESSAGE_MOVE); |
||
| 1121 | |||
| 1122 | return array(PR_ENTRYID => $entryid, PR_PARENT_ENTRYID => $rows[0][PR_PARENT_ENTRYID], PR_STORE_ENTRYID => $rows[0][PR_STORE_ENTRYID]); |
||
| 1123 | } |
||
| 1124 | |||
| 1125 | return false; |
||
| 1126 | } |
||
| 1127 | |||
| 1128 | /** |
||
| 1129 | * Sets recipients for the outgoing message according to type of the response. |
||
| 1130 | * |
||
| 1131 | * If it is a task update, then only recipient type MAPI_CC are taken from the task message. |
||
| 1132 | * |
||
| 1133 | * If it is accept/decline response, then PR_SENT_REPRESENTATION_XXXX are taken as recipient. |
||
| 1134 | * |
||
| 1135 | *@param $outgoing MAPI_message outgoing mapi message |
||
| 1136 | *@param $responseType String response type |
||
| 1137 | */ |
||
| 1138 | function setRecipientsForResponse($outgoing, $responseType) |
||
| 1139 | { |
||
| 1140 | // Clear recipients from outgoing msg |
||
| 1141 | $this->deleteAllRecipients($outgoing); |
||
| 1142 | |||
| 1143 | // If it is a task update then get MAPI_CC recipients which are assignors who has asked for task update. |
||
| 1144 | if ($responseType == tdmtTaskUpd) { |
||
| 1145 | $props = mapi_getprops($this->message, array($this->props['complete'])); |
||
| 1146 | $isComplete = $props[$this->props['complete']]; |
||
| 1147 | |||
| 1148 | $recipTable = mapi_message_getrecipienttable($this->message); |
||
| 1149 | $recips = mapi_table_queryallrows($recipTable, $this->recipProps, array(RES_PROPERTY, |
||
| 1150 | array( RELOP => RELOP_EQ, |
||
| 1151 | ULPROPTAG => PR_RECIPIENT_TYPE, |
||
| 1152 | VALUE => ($isComplete ? MAPI_BCC : MAPI_CC) |
||
| 1153 | ) |
||
| 1154 | )); |
||
| 1155 | |||
| 1156 | // No recipients found, return error |
||
| 1157 | if (empty($recips)) { |
||
| 1158 | return false; |
||
| 1159 | } |
||
| 1160 | |||
| 1161 | foreach($recips as $recip) { |
||
| 1162 | $recip[PR_RECIPIENT_TYPE] = MAPI_TO; // Change recipient type to MAPI_TO |
||
| 1163 | mapi_message_modifyrecipients($outgoing, MODRECIP_ADD, array($recip)); |
||
| 1164 | } |
||
| 1165 | return true; |
||
| 1166 | } |
||
| 1167 | |||
| 1168 | $orgprops = mapi_getprops($this->message, array(PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_ENTRYID, PR_SUBJECT)); |
||
| 1169 | $recip = array( |
||
| 1170 | PR_DISPLAY_NAME => $orgprops[PR_SENT_REPRESENTING_NAME], |
||
| 1171 | PR_EMAIL_ADDRESS => $orgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS], |
||
| 1172 | PR_ADDRTYPE => $orgprops[PR_SENT_REPRESENTING_ADDRTYPE], |
||
| 1173 | PR_ENTRYID => $orgprops[PR_SENT_REPRESENTING_ENTRYID], |
||
| 1174 | PR_RECIPIENT_TYPE => MAPI_TO); |
||
| 1175 | |||
| 1176 | mapi_message_modifyrecipients($outgoing, MODRECIP_ADD, array($recip)); |
||
| 1177 | |||
| 1178 | return true; |
||
| 1179 | } |
||
| 1180 | |||
| 1181 | /** |
||
| 1182 | * Deletes all recipients from given message object |
||
| 1183 | * |
||
| 1184 | * @param $message MAPI message from which recipients are to be removed. |
||
| 1185 | */ |
||
| 1186 | function deleteAllRecipients($message) |
||
| 1187 | { |
||
| 1188 | $recipTable = mapi_message_getrecipienttable($message); |
||
| 1189 | $recipRows = mapi_table_queryallrows($recipTable, array(PR_ROWID)); |
||
| 1190 | |||
| 1191 | foreach($recipRows as $recipient) { |
||
| 1192 | mapi_message_modifyrecipients($message, MODRECIP_REMOVE, array($recipient)); |
||
| 1193 | } |
||
| 1194 | } |
||
| 1195 | |||
| 1196 | /** |
||
| 1197 | * Function used to mark the record to complete and send complete update |
||
| 1198 | * notification to assigner. |
||
| 1199 | * |
||
| 1200 | * @return boolean TRUE if the update succeeded, FALSE otherwise. |
||
| 1201 | */ |
||
| 1202 | function sendCompleteUpdate() |
||
| 1203 | { |
||
| 1204 | $messageprops = mapi_getprops($this->message, array($this->props['taskstate'])); |
||
| 1205 | |||
| 1206 | if(!isset($messageprops[$this->props['taskstate']]) || $messageprops[$this->props['taskstate']] != tdsOWN) { |
||
| 1207 | return false; // Can only decline assignee task |
||
| 1208 | } |
||
| 1209 | |||
| 1210 | mapi_setprops($this->message, array($this->props['complete'] => true, |
||
| 1211 | $this->props['datecompleted'] => time(), |
||
| 1212 | $this->props['status'] => 2, |
||
| 1213 | $this->props['percent_complete'] => 1)); |
||
| 1214 | |||
| 1215 | $this->doUpdate(); |
||
| 1216 | } |
||
| 1217 | |||
| 1218 | /** |
||
| 1219 | * Function returns extra info about task request comments along with message body |
||
| 1220 | * which will be included in body while sending task request/response. |
||
| 1221 | * |
||
| 1222 | * @return string info about task request comments along with message body. |
||
| 1223 | */ |
||
| 1224 | function getTaskCommentsInfo() |
||
| 1225 | { |
||
| 1226 | return $this->taskCommentsInfo; |
||
| 1227 | } |
||
| 1228 | |||
| 1229 | /** |
||
| 1230 | * Function sets extra info about task request comments along with message body |
||
| 1231 | * which will be included in body while sending task request/response. |
||
| 1232 | * |
||
| 1233 | * @param string $taskCommentsInfo info about task request comments along with message body. |
||
| 1234 | */ |
||
| 1235 | function setTaskCommentsInfo($taskCommentsInfo) |
||
| 1236 | { |
||
| 1237 | $this->taskCommentsInfo = $taskCommentsInfo; |
||
| 1238 | } |
||
| 1239 | |||
| 1240 | function getSubProperties() { |
||
| 1241 | $subProperties = array(); |
||
| 1242 | $subProperties["subject"] = PR_SUBJECT; |
||
| 1243 | $subProperties["convtopic"] = PR_CONVERSATION_TOPIC; |
||
| 1244 | $subProperties["complete"] = "PT_BOOLEAN:PSETID_Task:0x811c"; |
||
| 1245 | $subProperties["datecompleted"] = "PT_SYSTIME:PSETID_Task:0x810f"; |
||
| 1246 | $subProperties["recurring"] = "PT_BOOLEAN:PSETID_Task:0x8126"; |
||
| 1247 | $subProperties["startdate"] = "PT_SYSTIME:PSETID_Task:0x8104"; |
||
| 1248 | $subProperties["duedate"] = "PT_SYSTIME:PSETID_Task:0x8105"; |
||
| 1249 | $subProperties["status"] = "PT_LONG:PSETID_Task:0x8101"; |
||
| 1250 | $subProperties["percent_complete"] = "PT_DOUBLE:PSETID_Task:0x8102"; |
||
| 1251 | $subProperties["totalwork"] = "PT_LONG:PSETID_Task:0x8111"; |
||
| 1252 | $subProperties["actualwork"] = "PT_LONG:PSETID_Task:0x8110"; |
||
| 1253 | $subProperties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords"; |
||
| 1254 | $subProperties["companies"] = "PT_MV_STRING8:PSETID_Common:0x8539"; |
||
| 1255 | $subProperties["mileage"] = "PT_STRING8:PSETID_Common:0x8534"; |
||
| 1256 | $subProperties["billinginformation"] = "PT_STRING8:PSETID_Common:0x8535"; |
||
| 1257 | |||
| 1258 | return getPropIdsFromStrings($this->store, $subProperties); |
||
| 1259 | } |
||
| 1260 | } |
||
| 1261 | ?> |
||
|
0 ignored issues
–
show
|
|||
| 1262 |
Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.
A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.