grommunio /
grommunio-web
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Hierarchy Module |
||
| 4 | * |
||
| 5 | * @todo |
||
| 6 | * - Check the code at deleteFolder and at copyFolder. Looks the same. |
||
| 7 | */ |
||
| 8 | class HierarchyModule extends Module |
||
| 9 | { |
||
| 10 | /** |
||
| 11 | * Constructor |
||
| 12 | * @param int $id unique id. |
||
| 13 | * @param string $folderentryid Entryid of the folder. Data will be selected from this folder. |
||
| 14 | * @param array $data list of all actions. |
||
| 15 | */ |
||
| 16 | function __construct($id, $data) |
||
| 17 | { |
||
| 18 | $this->properties = $GLOBALS["properties"]->getFolderProperties(); |
||
| 19 | $this->list_properties = $GLOBALS["properties"]->getFolderListProperties(); |
||
| 20 | |||
| 21 | parent::__construct($id, $data); |
||
| 22 | } |
||
| 23 | |||
| 24 | /** |
||
| 25 | * Creates the notifiers for this module, |
||
| 26 | * and register them to the Bus. |
||
| 27 | */ |
||
| 28 | function createNotifiers() |
||
| 29 | { |
||
| 30 | $entryid = $this->getEntryID(); |
||
| 31 | $GLOBALS["bus"]->registerNotifier('hierarchynotifier', $entryid, true); |
||
| 32 | $GLOBALS["bus"]->registerNotifier('hierarchynotifier', REQUEST_ENTRYID); |
||
| 33 | $GLOBALS["bus"]->registerNotifier('newmailnotifier', REQUEST_ENTRYID); |
||
| 34 | } |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Function which returns a list of entryids, which is used to register this module. It |
||
| 38 | * returns the ipm_subtree entryids of every message store. |
||
| 39 | * @return array list of entryids |
||
| 40 | */ |
||
| 41 | function getEntryID() |
||
| 42 | { |
||
| 43 | $entryids = array(); |
||
| 44 | $storelist = $GLOBALS["mapisession"]->getAllMessageStores(); |
||
| 45 | |||
| 46 | foreach ($storelist as $entryid => $store) { |
||
| 47 | $entryids[] = bin2hex($entryid); |
||
| 48 | } |
||
| 49 | |||
| 50 | return $entryids; |
||
| 51 | } |
||
| 52 | |||
| 53 | /** |
||
| 54 | * Executes all the actions in the $data variable. |
||
| 55 | * @return boolean true on success or false on fialure. |
||
| 56 | */ |
||
| 57 | function execute() |
||
| 58 | { |
||
| 59 | foreach($this->data as $actionType => $action) |
||
| 60 | { |
||
| 61 | if(isset($actionType)) { |
||
| 62 | try { |
||
| 63 | $store = $this->getActionStore($action); |
||
| 64 | $parententryid = $this->getActionParentEntryID($action); |
||
| 65 | $entryid = $this->getActionEntryID($action); |
||
| 66 | |||
| 67 | switch($actionType) |
||
| 68 | { |
||
| 69 | case "keepalive": |
||
| 70 | /** |
||
| 71 | * as we haven't done any processing here but still we need to send |
||
| 72 | * success message to client so client can know that there isn't any problem |
||
| 73 | * on server side (this will also make bus class happy as it will cry when |
||
| 74 | * there isn't any data to send to client). |
||
| 75 | */ |
||
| 76 | $this->sendFeedback(true); |
||
| 77 | break; |
||
| 78 | case "destroysession": |
||
| 79 | // This actiontype should never get this far, but should already have been |
||
| 80 | // intercepted by the Session class. |
||
| 81 | // Nevertheless implement processing here for unforeseen cases. |
||
| 82 | $this->sendFeedback(true); |
||
| 83 | break; |
||
| 84 | case "list": |
||
| 85 | $this->hierarchyList(); |
||
| 86 | break; |
||
| 87 | case "open": |
||
| 88 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
| 89 | $data = $this->getFolderProps($store, $folder); |
||
| 90 | |||
| 91 | // return response |
||
| 92 | $this->addActionData("item", $data); |
||
| 93 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 94 | break; |
||
| 95 | case "foldersize": |
||
| 96 | $folders = array(); |
||
| 97 | |||
| 98 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
| 99 | $data = $this->getFolderProps($store, $folder); |
||
| 100 | |||
| 101 | $info = $this->getFolderSize($store, $folder, '', $folders); |
||
| 102 | |||
| 103 | // It could be that the $props already contains the data, |
||
| 104 | // this happens when the folder is the IPM_SUBTREE and the |
||
| 105 | // folder size is read directly from the store. Adjust |
||
| 106 | // total_size accordingly. |
||
| 107 | if (isset($data["props"]["store_size"])) { |
||
| 108 | if (!isset($data["props"]["message_size"])) { |
||
| 109 | $data["props"]["message_size"] = $data["props"]["store_size"]; |
||
| 110 | } |
||
| 111 | $data["props"]["total_message_size"] = $data["props"]["store_size"] + $info["total_size"]; |
||
| 112 | } else { |
||
| 113 | $data["props"]["message_size"] = $info["size"]; |
||
| 114 | $data["props"]["total_message_size"] = $info["total_size"]; |
||
| 115 | } |
||
| 116 | $data["folders"] = array( |
||
| 117 | "item" => $folders |
||
| 118 | ); |
||
| 119 | |||
| 120 | // return response |
||
| 121 | $this->addActionData("item", $data); |
||
| 122 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 123 | break; |
||
| 124 | |||
| 125 | case "delete": |
||
| 126 | if ($store && $parententryid && $entryid) { |
||
| 127 | if (isset($action["message_action"]) && isset($action["message_action"]["action_type"]) |
||
| 128 | && $action["message_action"]["action_type"] === "removefavorites" ) { |
||
| 129 | |||
| 130 | if (isset($action["message_action"]["isSearchFolder"]) |
||
| 131 | && $action["message_action"]["isSearchFolder"]) { |
||
| 132 | $result = $this->deleteSearchFolder($store, $parententryid, $entryid, $action); |
||
| 133 | dump($result, '$result'); |
||
| 134 | if ($result) { |
||
| 135 | $this->sendFeedback(true); |
||
| 136 | } |
||
| 137 | } else { |
||
| 138 | $this->removeFromFavorite($entryid); |
||
| 139 | } |
||
| 140 | } else { |
||
| 141 | $this->deleteFolder($store, $parententryid, $entryid, $action); |
||
| 142 | } |
||
| 143 | } |
||
| 144 | break; |
||
| 145 | |||
| 146 | case "save": |
||
| 147 | if ($store && $parententryid) { |
||
| 148 | if ($entryid) { |
||
| 149 | // The "message_action" object has been set, check the action_type field for |
||
| 150 | // the exact action which must be taken. |
||
| 151 | // Supported actions: |
||
| 152 | // - copy: Copy the folder to the new destination folder |
||
| 153 | // - move: Move the folder to the new destination folder |
||
| 154 | // - emptyfolder: Delete all items within the folder |
||
| 155 | // - readflags: Mark all items within the folder as read |
||
| 156 | // - addtofavorites: Add the folder to "favorites" |
||
| 157 | if (!isset($action["message_action"]["isSearchFolder"])){ |
||
| 158 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
| 159 | $data = $this->getFolderProps($store, $folder); |
||
| 160 | } |
||
| 161 | if (isset($action["message_action"]) && isset($action["message_action"]["action_type"])) { |
||
| 162 | switch($action["message_action"]["action_type"]) |
||
| 163 | { |
||
| 164 | case "copy": |
||
| 165 | case "move": |
||
| 166 | $destentryid = false; |
||
| 167 | if(isset($action["message_action"]["destination_parent_entryid"])) |
||
| 168 | $destentryid = hex2bin($action["message_action"]["destination_parent_entryid"]); |
||
| 169 | |||
| 170 | $deststore = $store; |
||
| 171 | if(isset($action["message_action"]["destination_store_entryid"])) |
||
| 172 | $deststore = $GLOBALS['mapisession']->openMessageStore(hex2bin($action["message_action"]["destination_store_entryid"])); |
||
| 173 | |||
| 174 | if($destentryid && $deststore) |
||
| 175 | $this->copyFolder($store, $parententryid, $entryid, $destentryid, $deststore, ($action["message_action"]["action_type"] == "move")); |
||
| 176 | if ($data["props"]["container_class"] === "IPF.Contact") { |
||
| 177 | $GLOBALS["bus"]->notify(ADDRESSBOOK_ENTRYID, OBJECT_SAVE); |
||
| 178 | } |
||
| 179 | break; |
||
| 180 | |||
| 181 | case "emptyfolder": |
||
| 182 | $this->emptyFolder($store, $entryid); |
||
| 183 | break; |
||
| 184 | |||
| 185 | case "readflags": |
||
| 186 | $this->setReadFlags($store, $entryid); |
||
| 187 | break; |
||
| 188 | |||
| 189 | case "addtofavorites": |
||
| 190 | if (isset($action["message_action"]["isSearchFolder"]) && $action["message_action"]["isSearchFolder"]){ |
||
| 191 | $searchStoreEntryId = $action["message_action"]["search_store_entryid"]; |
||
| 192 | // Set display name to search folder. |
||
| 193 | $searchStore = $GLOBALS["mapisession"]->openMessageStore(hex2bin($searchStoreEntryId)); |
||
| 194 | $searchFolder = mapi_msgstore_openentry($searchStore, $entryid); |
||
| 195 | mapi_setprops($searchFolder, array( |
||
| 196 | PR_DISPLAY_NAME => $action["props"]["display_name"] |
||
| 197 | )); |
||
| 198 | mapi_savechanges($searchFolder); |
||
| 199 | $this->createLinkedSearchFolder($searchFolder); |
||
| 200 | } else { |
||
| 201 | $this->addToFavorite($store, $entryid); |
||
| 202 | } |
||
| 203 | break; |
||
| 204 | } |
||
| 205 | } else { |
||
| 206 | // save folder |
||
| 207 | $folder = mapi_msgstore_openentry($store, hex2bin($action["entryid"])); |
||
| 208 | $this->save($store, $folder, $action); |
||
| 209 | if ($data["props"]["container_class"] === "IPF.Contact") { |
||
| 210 | $GLOBALS["bus"]->notify(ADDRESSBOOK_ENTRYID, OBJECT_SAVE); |
||
| 211 | } |
||
| 212 | $this->sendFeedback(true, array()); |
||
| 213 | } |
||
| 214 | } else { |
||
| 215 | // no entryid, create new folder |
||
| 216 | if($store && $parententryid && isset($action["props"]["display_name"]) && isset($action["props"]["container_class"])) |
||
| 217 | if (isset($action["message_action"]) && isset($action["message_action"]["action_type"])) { |
||
| 218 | // We need to create new search folder under the favorites folder |
||
| 219 | // based on give search folder info. |
||
| 220 | if($action["message_action"]["action_type"] === "addtofavorites") { |
||
| 221 | $storeEntryId = $action["message_action"]["search_store_entryid"]; |
||
| 222 | $searchFolderEntryId = $action["message_action"]["search_folder_entryid"]; |
||
| 223 | |||
| 224 | // Get the search folder and search criteria using $storeEntryId and $searchFolderEntryId. |
||
| 225 | $Store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeEntryId)); |
||
| 226 | $searchFolder = mapi_msgstore_openentry($Store, hex2bin($searchFolderEntryId)); |
||
| 227 | $searchCriteria = mapi_folder_getsearchcriteria($searchFolder); |
||
| 228 | |||
| 229 | // Get FINDERS_ROOT folder from store. |
||
| 230 | $finderRootFolder = mapi_getprops($Store, array(PR_FINDER_ENTRYID)); |
||
| 231 | $searchFolderRoot = mapi_msgstore_openentry($Store, $finderRootFolder[PR_FINDER_ENTRYID]); |
||
| 232 | |||
| 233 | // Create new search folder in FINDERS_ROOT folder and set the search |
||
| 234 | // criteria in newly created search folder. |
||
| 235 | $newSearchFolder = mapi_folder_createfolder($searchFolderRoot, $action["props"]["display_name"], null, 0, FOLDER_SEARCH); |
||
| 236 | $subfolder_flag = 0; |
||
| 237 | if (isset($action["subfolders"]) && $action["subfolders"] == "true") { |
||
| 238 | $subfolder_flag = RECURSIVE_SEARCH; |
||
| 239 | } |
||
| 240 | mapi_folder_setsearchcriteria($newSearchFolder, $searchCriteria['restriction'], $searchCriteria['folderlist'], $subfolder_flag); |
||
| 241 | |||
| 242 | // Sleep for 1 seconds initially, since it usually takes ~ 1 seconds to fill the search folder. |
||
| 243 | sleep(1); |
||
| 244 | $this->createLinkedSearchFolder($newSearchFolder); |
||
| 245 | } |
||
| 246 | } else { |
||
| 247 | $this->addFolder($store, $parententryid, $action["props"]["display_name"], $action["props"]["container_class"]); |
||
| 248 | } |
||
| 249 | if($action["props"]["container_class"] === "IPF.Contact"){ |
||
| 250 | $GLOBALS["bus"]->notify(ADDRESSBOOK_ENTRYID,OBJECT_SAVE); |
||
| 251 | } |
||
| 252 | } |
||
| 253 | } |
||
| 254 | break; |
||
| 255 | |||
| 256 | case "closesharedfolder": |
||
| 257 | if (isset($action["folder_type"]) && $action["folder_type"] != "all") { |
||
| 258 | // We're closing a Shared folder, check if we still have other |
||
| 259 | // folders for the same user opened, if not we can safely close |
||
| 260 | // the usrstore. |
||
| 261 | $stores = $GLOBALS["settings"]->get("zarafa/v1/contexts/hierarchy/shared_stores/" . strtolower(bin2hex($action["user_name"]))); |
||
| 262 | if (!isset($stores) || empty($stores) || (count($stores) == 1 && isset($stores[$action["folder_type"]]))) { |
||
| 263 | $entryid = $GLOBALS["mapisession"]->removeUserStore($action["user_name"]); |
||
| 264 | } else { |
||
| 265 | $entryid = $GLOBALS["mapisession"]->getStoreEntryIdOfUser($action["user_name"]); |
||
| 266 | $this->removeFromFavorite(hex2bin($action["entryid"]), $store, PR_WLINK_ENTRYID, false); |
||
| 267 | } |
||
| 268 | } else { |
||
| 269 | // We're closing a Shared Store, simply remove it from the session. |
||
| 270 | $entryid = $GLOBALS["mapisession"]->removeUserStore($action["user_name"]); |
||
| 271 | |||
| 272 | if (isset($action["remove_favorites"]) && $action["remove_favorites"]) { |
||
| 273 | $this->removeFromFavorite(hex2bin($action["store_entryid"]), $store, PR_WLINK_STORE_ENTRYID, false); |
||
| 274 | } |
||
| 275 | } |
||
| 276 | |||
| 277 | $data = array(); |
||
| 278 | $data["store_entryid"] = bin2hex($entryid); |
||
| 279 | if(isset($action["folder_type"])) { |
||
| 280 | $data["folder_type"] =$action["folder_type"]; |
||
| 281 | } |
||
| 282 | |||
| 283 | $this->addActionData("delete", $data); |
||
| 284 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 285 | $GLOBALS["bus"]->notify(ADDRESSBOOK_ENTRYID,OBJECT_SAVE); |
||
| 286 | break; |
||
| 287 | |||
| 288 | case "opensharedfolder": |
||
| 289 | $username = strtolower($action["user_name"]); |
||
| 290 | $store = $GLOBALS["mapisession"]->addUserStore($username); |
||
| 291 | if (!$store) { |
||
| 292 | break; |
||
| 293 | } |
||
| 294 | |||
| 295 | $options = array( $username => array( $action["folder_type"] => $action )); |
||
| 296 | $data = $GLOBALS["operations"]->getHierarchyList($this->list_properties, HIERARCHY_GET_ONE, $store, $options, $username); |
||
| 297 | |||
| 298 | if (empty($data["item"][0]["folders"]["item"])) { |
||
| 299 | throw new MAPIException(null, MAPI_E_NO_ACCESS); |
||
| 300 | } |
||
| 301 | |||
| 302 | $folders = count($data["item"][0]["folders"]["item"]); |
||
| 303 | if ($folders === 0) { |
||
| 304 | throw new MAPIException(null, MAPI_E_NO_ACCESS); |
||
| 305 | } |
||
| 306 | |||
| 307 | $noPermissionFolders = array_filter($data['item'][0]['folders']['item'], function($item) { |
||
| 308 | return $item['props']['access'] === 0; |
||
| 309 | }); |
||
| 310 | if (count($noPermissionFolders) >= $folders) { |
||
| 311 | // Throw an exception that we couldn't open the shared store, |
||
| 312 | // lets have processException() fill in our error message. |
||
| 313 | throw new MAPIException(null, MAPI_E_NO_ACCESS); |
||
| 314 | } |
||
| 315 | |||
| 316 | $this->addActionData("list", $data); |
||
| 317 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 318 | $GLOBALS["bus"]->notify(ADDRESSBOOK_ENTRYID,OBJECT_SAVE); |
||
| 319 | break; |
||
| 320 | case "sharedstoreupdate": |
||
| 321 | $supported_types = ['inbox' => 1, 'all' => 1]; |
||
| 322 | $users = $GLOBALS["settings"]->get("zarafa/v1/contexts/hierarchy/shared_stores", []); |
||
| 323 | |||
| 324 | foreach($users as $username => $data) { |
||
| 325 | $key = array_keys($data)[0]; |
||
| 326 | $folder_type = $data[$key]['folder_type']; |
||
| 327 | |||
| 328 | if (!isset($supported_types[$folder_type])) { |
||
| 329 | continue; |
||
| 330 | } |
||
| 331 | |||
| 332 | $GLOBALS["bus"]->notify(REQUEST_ENTRYID, HIERARCHY_UPDATE, array(strtolower(hex2bin($username)), $folder_type)); |
||
| 333 | } |
||
| 334 | |||
| 335 | $this->sendFeedback(true); |
||
| 336 | break; |
||
| 337 | default: |
||
| 338 | $this->handleUnknownActionType($actionType); |
||
| 339 | } |
||
| 340 | } catch (MAPIException $e) { |
||
| 341 | $this->processException($e, $actionType, $store, $parententryid, $entryid, $action); |
||
| 342 | } |
||
| 343 | } |
||
| 344 | } |
||
| 345 | } |
||
| 346 | |||
| 347 | /** |
||
| 348 | * Function does customization of exception based on module data. |
||
| 349 | * like, here it will generate display message based on actionType |
||
| 350 | * for particular exception, and send feedback to the client. |
||
| 351 | * |
||
| 352 | * @param object $e Exception object |
||
| 353 | * @param string $actionType the action type, sent by the client |
||
| 354 | * @param MAPIobject $store Store object of the folder. |
||
| 355 | * @param string $parententryid parent entryid of the message. |
||
| 356 | * @param string $entryid entryid of the folder. |
||
| 357 | * @param array $action the action data, sent by the client |
||
| 358 | */ |
||
| 359 | function handleException(&$e, $actionType = null, $store = null, $parententryid = null, $entryid = null, $action = null) |
||
| 360 | { |
||
| 361 | if(is_null($e->displayMessage)) { |
||
| 362 | switch($actionType) { |
||
| 363 | case "list": |
||
| 364 | $e->setDisplayMessage(_("Could not load the hierarchy.")); |
||
| 365 | break; |
||
| 366 | |||
| 367 | case "open": |
||
| 368 | $e->setDisplayMessage(_("Could not load folder properties.")); |
||
| 369 | break; |
||
| 370 | |||
| 371 | case "delete": |
||
| 372 | if (isset($action["message_action"]) |
||
|
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
Loading history...
|
|||
| 373 | && isset($action["message_action"]["action_type"]) |
||
| 374 | && $action["message_action"]["action_type"] === "removefavorites") { |
||
| 375 | $e->setDisplayMessage(_("Could not remove folder from favorites.")); |
||
| 376 | } else { |
||
| 377 | if($e->getCode() == MAPI_E_NO_ACCESS) |
||
| 378 | $e->setDisplayMessage(_("You have insufficient privileges to delete folder.")); |
||
| 379 | else |
||
| 380 | $e->setDisplayMessage(_("Could not delete folder.")); |
||
| 381 | break; |
||
| 382 | } |
||
| 383 | case "save": |
||
| 384 | if($entryid) { |
||
| 385 | if (isset($action["message_action"]) && isset($action["message_action"]["action_type"])) { |
||
| 386 | switch($action["message_action"]["action_type"]) |
||
| 387 | { |
||
| 388 | case "copy": |
||
| 389 | if($e->getCode() == MAPI_E_NO_ACCESS) |
||
| 390 | $e->setDisplayMessage(_("You have insufficient privileges to copy folder.")); |
||
| 391 | else |
||
| 392 | $e->setDisplayMessage(_("Could not copy folder.")); |
||
| 393 | break; |
||
| 394 | |||
| 395 | case "move": |
||
| 396 | if($e->getCode() == MAPI_E_NO_ACCESS) |
||
| 397 | $e->setDisplayMessage(_("You have insufficient privileges to move this folder.")); |
||
| 398 | else |
||
| 399 | $e->setDisplayMessage(_("Could not move folder.")); |
||
| 400 | break; |
||
| 401 | |||
| 402 | case "emptyfolder": |
||
| 403 | if($e->getCode() == MAPI_E_NO_ACCESS) |
||
| 404 | $e->setDisplayMessage(_("You have insufficient privileges to delete items.")); |
||
| 405 | else |
||
| 406 | $e->setDisplayMessage(_("Could not empty folder.")); |
||
| 407 | break; |
||
| 408 | |||
| 409 | case "readflags": |
||
| 410 | $e->setDisplayMessage(_("Could not perform action correctly.")); |
||
| 411 | break; |
||
| 412 | |||
| 413 | case "addtofavorites": |
||
| 414 | if ($e->getCode() == MAPI_E_COLLISION) { |
||
| 415 | $e->setDisplayMessage(_("A favorite folder with this name already exists, please use another name.")); |
||
| 416 | } else { |
||
| 417 | $e->setDisplayMessage(_("Could not add folder to favorites.")); |
||
| 418 | } |
||
| 419 | break; |
||
| 420 | } |
||
| 421 | } else { |
||
| 422 | // Exception generated while setting folder permissions. |
||
| 423 | if (isset($action["permissions"])){ |
||
| 424 | if($e->getCode() == MAPI_E_NO_ACCESS) |
||
| 425 | $e->setDisplayMessage(_("You have insufficient privileges to set permissions for this folder.")); |
||
| 426 | else |
||
| 427 | $e->setDisplayMessage(_("Could not set folder permissions.")); |
||
| 428 | } else { |
||
| 429 | // Exception generated while renaming folder. |
||
| 430 | switch($e->getCode()){ |
||
| 431 | case MAPI_E_NO_ACCESS: |
||
| 432 | $e->setDisplayMessage(_("You have insufficient privileges to rename this folder.")); |
||
| 433 | break; |
||
| 434 | case MAPI_E_COLLISION: |
||
| 435 | $e->setDisplayMessage(_("A folder with this name already exists. Use another name.")); |
||
| 436 | break; |
||
| 437 | default: |
||
| 438 | $e->setDisplayMessage(_("Could not rename folder.")); |
||
| 439 | } |
||
| 440 | |||
| 441 | } |
||
| 442 | } |
||
| 443 | } else { |
||
| 444 | // Exception generated while creating new folder. |
||
| 445 | switch($e->getCode()){ |
||
| 446 | case MAPI_E_NO_ACCESS: |
||
| 447 | $e->setDisplayMessage(_("You have insufficient privileges to create this folder.")); |
||
| 448 | break; |
||
| 449 | case MAPI_E_COLLISION: |
||
| 450 | $e->setDisplayMessage(_("A folder with this name already exists. Use another name.")); |
||
| 451 | break; |
||
| 452 | default: |
||
| 453 | $e->setDisplayMessage(_("Could not create folder.")); |
||
| 454 | } |
||
| 455 | } |
||
| 456 | break; |
||
| 457 | |||
| 458 | case "closesharedfolder": |
||
| 459 | $e->setDisplayMessage(_("Could not close shared folder.")); |
||
| 460 | break; |
||
| 461 | |||
| 462 | case "opensharedfolder": |
||
| 463 | if($e->getCode() == MAPI_E_NOT_FOUND) { |
||
| 464 | $e->setDisplayMessage(_("User could not be resolved.")); |
||
| 465 | } else { |
||
| 466 | $folderType = $action["folder_type"]; |
||
| 467 | if ($folderType == "all") { |
||
| 468 | $folderType = 'entire inbox'; |
||
| 469 | } |
||
| 470 | $e->setDisplayMessage(sprintf(_('You have insufficient privileges to open this %1$s folder. The folder owner can set these using the \'permissions\'-tab of the folder properties (right click the %1$s folder > properties > permissions).'),$folderType)); |
||
| 471 | } |
||
| 472 | break; |
||
| 473 | } |
||
| 474 | } |
||
| 475 | |||
| 476 | parent::handleException($e, $actionType, $store, $parententryid, $entryid, $action); |
||
| 477 | } |
||
| 478 | |||
| 479 | /** |
||
| 480 | * Generates the hierarchy list. All folders and subfolders are added to response data. |
||
| 481 | */ |
||
| 482 | function hierarchyList() |
||
| 483 | { |
||
| 484 | $data = $GLOBALS["operations"]->getHierarchyList($this->list_properties); |
||
| 485 | |||
| 486 | $this->addActionData("list", $data); |
||
| 487 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 488 | } |
||
| 489 | |||
| 490 | /** |
||
| 491 | * Add folder's properties to response data. This function doesn't add persmission details yet. |
||
| 492 | *@param Resource $store mapi store of the folder |
||
| 493 | *@param String $entryid entryid of the folder |
||
| 494 | *@param String $actionType type of action |
||
| 495 | */ |
||
| 496 | function addFolderToResponseData($store, $entryid, $actionType) |
||
| 497 | { |
||
| 498 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
| 499 | $folderProps = mapi_getprops($folder, $this->list_properties); |
||
| 500 | |||
| 501 | $data = $GLOBALS["operations"]->setFolder($folderProps); |
||
| 502 | $this->addActionData($actionType, $data); |
||
| 503 | } |
||
| 504 | |||
| 505 | /** |
||
| 506 | * Adds a folder to the hierarchylist. |
||
| 507 | * @param object $store Message Store Object. |
||
| 508 | * @param string $parententryid entryid of the parent folder. |
||
| 509 | * @param string $name name of the new folder. |
||
| 510 | * @param string $type type of the folder (calendar, mail, ...). |
||
| 511 | * @return boolean true on success or false on failure. |
||
| 512 | */ |
||
| 513 | function addFolder($store, $parententryid, $name, $type) |
||
| 514 | { |
||
| 515 | $props = array(); |
||
| 516 | $result = $GLOBALS["operations"]->createFolder($store, $parententryid, $name, $type, $props); |
||
| 517 | |||
| 518 | if ($result && isset($props[PR_ENTRYID])) { |
||
| 519 | // Notify about this newly created folder |
||
| 520 | $this->addFolderToResponseData($store, $props[PR_ENTRYID], "update"); |
||
| 521 | |||
| 522 | // Add all response data to Bus |
||
| 523 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 524 | |||
| 525 | // Notify parent folder that a folder has been added |
||
| 526 | $props[PR_ENTRYID] = $parententryid; |
||
| 527 | $GLOBALS["bus"]->notify(bin2hex($parententryid), OBJECT_SAVE, $props); |
||
| 528 | } |
||
| 529 | |||
| 530 | return $result; |
||
| 531 | } |
||
| 532 | |||
| 533 | /** |
||
| 534 | * returns properties of a folder, used by the properties dialog |
||
| 535 | */ |
||
| 536 | function getFolderProps($store, $folder) |
||
| 537 | { |
||
| 538 | $data = $GLOBALS["operations"]->getProps($folder, $this->properties); |
||
| 539 | |||
| 540 | // adding container_class if missing |
||
| 541 | if (!isset($data["props"]["container_class"])){ |
||
| 542 | $data["props"]["container_class"] = "IPF.Note"; |
||
| 543 | } |
||
| 544 | |||
| 545 | // replace "IPM_SUBTREE" with the display name of the store, and use the store message size |
||
| 546 | $store_props = mapi_getprops($store, array(PR_IPM_SUBTREE_ENTRYID)); |
||
| 547 | if ($data["entryid"] == bin2hex($store_props[PR_IPM_SUBTREE_ENTRYID])) { |
||
| 548 | $store_props = mapi_getprops($store, array(PR_DISPLAY_NAME, PR_MESSAGE_SIZE_EXTENDED, |
||
| 549 | PR_CONTENT_COUNT, PR_QUOTA_WARNING_THRESHOLD, PR_QUOTA_SEND_THRESHOLD, PR_QUOTA_RECEIVE_THRESHOLD)); |
||
| 550 | $data["props"]["display_name"] = $store_props[PR_DISPLAY_NAME]; |
||
| 551 | $data["props"]["message_size"] = round($store_props[PR_MESSAGE_SIZE_EXTENDED]); |
||
| 552 | $data["props"]["content_count"] = $store_props[PR_CONTENT_COUNT]; |
||
| 553 | $data["props"]["store_size"] = round($store_props[PR_MESSAGE_SIZE_EXTENDED]); |
||
| 554 | |||
| 555 | if (isset($store_props[PR_QUOTA_WARNING_THRESHOLD])) |
||
| 556 | $data["props"]["quota_warning"] = round($store_props[PR_QUOTA_WARNING_THRESHOLD]); |
||
| 557 | if (isset($store_props[PR_QUOTA_SEND_THRESHOLD])) |
||
| 558 | $data["props"]["quota_soft"] = round($store_props[PR_QUOTA_SEND_THRESHOLD]); |
||
| 559 | if (isset($store_props[PR_QUOTA_RECEIVE_THRESHOLD])) |
||
| 560 | $data["props"]["quota_hard"] = round($store_props[PR_QUOTA_RECEIVE_THRESHOLD]); |
||
| 561 | } |
||
| 562 | |||
| 563 | // calculating missing message_size |
||
| 564 | if (!isset($data["props"]["message_size"])){ |
||
| 565 | $data["props"]["message_size"] = round($GLOBALS["operations"]->calcFolderMessageSize($folder, false)); |
||
| 566 | } |
||
| 567 | |||
| 568 | // retrieving folder permissions |
||
| 569 | $data["permissions"] = array( |
||
| 570 | "item" => $this->getFolderPermissions($folder) |
||
| 571 | ); |
||
| 572 | |||
| 573 | return $data; |
||
| 574 | } |
||
| 575 | |||
| 576 | /** |
||
| 577 | * Returns the size and total_size of the given folder. |
||
| 578 | * @param mapistore $store The store to which the folder belongs |
||
| 579 | * @param mapifolder $folder The folder for which the size must be calculated |
||
| 580 | * @param string $pathname The path of the current folder |
||
| 581 | * @param array &$subfolders The array in which all information for the subfolders are stored |
||
| 582 | * @param boolean $hidden True to prevent the subfolders to be stored into the $subfolders argument |
||
| 583 | * @return array The response data |
||
| 584 | */ |
||
| 585 | function getFolderSize($store, $folder, $pathname, &$subfolders, $hidden = false) |
||
| 586 | { |
||
| 587 | $columns = array(PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID, PR_OBJECT_TYPE, PR_DISPLAY_NAME, PR_ATTR_HIDDEN); |
||
| 588 | $size = $GLOBALS["operations"]->calcFolderMessageSize($folder, false); |
||
| 589 | $total_size = $size; |
||
| 590 | |||
| 591 | $table = mapi_folder_gethierarchytable($folder, MAPI_DEFERRED_ERRORS); |
||
| 592 | |||
| 593 | mapi_table_setcolumns($table, $columns); |
||
| 594 | $columns = null; |
||
| 595 | |||
| 596 | $rows = mapi_table_queryrows($table, $columns, 0, 0x7ffffff); |
||
| 597 | foreach ($rows as $row) { |
||
| 598 | $subfolder = mapi_msgstore_openentry($store, $row[PR_ENTRYID]); |
||
| 599 | $subpath = (!empty($pathname) ? ($pathname . '\\') : '') . $row[PR_DISPLAY_NAME]; |
||
| 600 | |||
| 601 | /** |
||
| 602 | * Don't add hidden folders, folders with PR_ATTR_HIDDEN property set |
||
| 603 | * should not be shown to the client |
||
| 604 | */ |
||
| 605 | $hide = $hidden === true || (isset($row[PR_ATTR_HIDDEN]) && $row[PR_ATTR_HIDDEN] === true); |
||
| 606 | $info = $this->getFolderSize($store, $subfolder, $subpath, $subfolders, $hide); |
||
| 607 | |||
| 608 | if ($hide !== true) { |
||
| 609 | array_push($subfolders, array( |
||
| 610 | "entryid" => bin2hex($row[PR_ENTRYID]), |
||
| 611 | "parent_entryid" => bin2hex($row[PR_PARENT_ENTRYID]), |
||
| 612 | "store_entryid" => bin2hex($row[PR_STORE_ENTRYID]), |
||
| 613 | "props" => array( |
||
| 614 | "folder_pathname" => $subpath, // This equals PR_FOLDER_PATHNAME, which is not supported by Gromox |
||
| 615 | "display_name" => $row[PR_DISPLAY_NAME], |
||
| 616 | "object_type" => $row[PR_OBJECT_TYPE], |
||
| 617 | "message_size" => $info["size"], |
||
| 618 | "total_message_size" => $info["total_size"] |
||
| 619 | ) |
||
| 620 | )); |
||
| 621 | } |
||
| 622 | |||
| 623 | $total_size += $info["total_size"]; |
||
| 624 | } |
||
| 625 | |||
| 626 | return array( "size" => $size, "total_size" => $total_size ); |
||
| 627 | } |
||
| 628 | |||
| 629 | /** |
||
| 630 | * Function which saves changed properties to a folder. |
||
| 631 | * @param object $store MAPI object of the store |
||
| 632 | * @param object $folder MAPI object of the folder |
||
| 633 | * @param array $props the properties to save |
||
| 634 | */ |
||
| 635 | function save($store, $folder, $action) |
||
| 636 | { |
||
| 637 | // Rename folder |
||
| 638 | if (isset($action["props"]["display_name"])) |
||
| 639 | $this->modifyFolder($store, hex2bin($action["entryid"]), $action["props"]["display_name"]); |
||
| 640 | |||
| 641 | if (isset($action["props"]["comment"])) |
||
| 642 | mapi_setprops($folder, array( PR_COMMENT=> $action["props"]["comment"])); |
||
| 643 | |||
| 644 | if (isset($action["permissions"])){ |
||
| 645 | $this->setFolderPermissions($folder, $action["permissions"]); |
||
| 646 | if(isset($action['props']['recursive'])) { |
||
| 647 | $hierarchyTable = mapi_folder_gethierarchytable($folder, CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS); |
||
| 648 | $subfolders = mapi_table_queryallrows($hierarchyTable, array(PR_ENTRYID)); |
||
| 649 | foreach($subfolders as $subfolder) { |
||
| 650 | $folderObject = mapi_msgstore_openentry($store, $subfolder[PR_ENTRYID]); |
||
| 651 | $this->setFolderPermissions($folderObject, $action["permissions"]); |
||
| 652 | mapi_savechanges($folderObject); |
||
| 653 | } |
||
| 654 | } |
||
| 655 | } |
||
| 656 | |||
| 657 | mapi_savechanges($folder); |
||
| 658 | } |
||
| 659 | |||
| 660 | |||
| 661 | function getFolderPermissions($folder) |
||
| 662 | { |
||
| 663 | // check if folder is rootFolder, then we need the permissions from the store |
||
| 664 | $folderProps = mapi_getprops($folder, array(PR_DISPLAY_NAME, PR_STORE_ENTRYID)); |
||
| 665 | |||
| 666 | $store = $GLOBALS["mapisession"]->openMessageStore($folderProps[PR_STORE_ENTRYID]); |
||
| 667 | if ($folderProps[PR_DISPLAY_NAME] == "IPM_SUBTREE"){ |
||
| 668 | $folder = $store; |
||
| 669 | } |
||
| 670 | |||
| 671 | $grants = mapi_zarafa_getpermissionrules($folder, ACCESS_TYPE_GRANT); |
||
| 672 | foreach($grants as $id=>$grant){ |
||
| 673 | // The mapi_zarafa_getpermissionrules returns the entryid in the userid key |
||
| 674 | $userinfo = $this->getUserInfo($grant["userid"]); |
||
| 675 | |||
| 676 | $rights = array(); |
||
| 677 | $rights["entryid"] = $userinfo["entryid"]; |
||
| 678 | $rights["props"] = array(); |
||
| 679 | $rights["props"]["type"] = ACCESS_TYPE_GRANT; |
||
| 680 | $rights["props"]["display_name"] = $userinfo["fullname"]; |
||
| 681 | $rights["props"]["object_type"] = $userinfo["type"]; |
||
| 682 | $rights["props"]["entryid"] = $userinfo["entryid"]; |
||
| 683 | $rights["props"]["rights"] = $grant["rights"]; |
||
| 684 | |||
| 685 | $grants[$id] = $rights; |
||
| 686 | } |
||
| 687 | |||
| 688 | return $grants; |
||
| 689 | } |
||
| 690 | |||
| 691 | function setFolderPermissions($folder, $permissions) |
||
| 692 | { |
||
| 693 | $folderProps = mapi_getprops($folder, array(PR_DISPLAY_NAME, PR_STORE_ENTRYID, PR_ENTRYID)); |
||
| 694 | $store = $GLOBALS["mapisession"]->openMessageStore($folderProps[PR_STORE_ENTRYID]); |
||
| 695 | $storeProps = mapi_getprops($store, array(PR_IPM_SUBTREE_ENTRYID)); |
||
| 696 | $currentPermissions = $this->getFolderPermissions($folder); |
||
| 697 | |||
| 698 | // check if the folder is the default calendar, if so we also need to set the same permissions on the freebusy folder |
||
| 699 | $root = mapi_msgstore_openentry($store, null); |
||
| 700 | if($root) { |
||
| 701 | $rootProps = mapi_getprops($root, array(PR_IPM_APPOINTMENT_ENTRYID)); |
||
| 702 | if ($folderProps[PR_ENTRYID] == $rootProps[PR_IPM_APPOINTMENT_ENTRYID]){ |
||
| 703 | $freebusy = freebusy::getLocalFreeBusyFolder($store); |
||
| 704 | } |
||
| 705 | } |
||
| 706 | |||
| 707 | // check if folder is rootFolder, then we need the permissions from the store |
||
| 708 | if ($folderProps[PR_ENTRYID] == $storeProps[PR_IPM_SUBTREE_ENTRYID]){ |
||
| 709 | $folder = $store; |
||
| 710 | } |
||
| 711 | |||
| 712 | |||
| 713 | // first, get the current permissions because we need to delete all current acl's |
||
| 714 | $curAcls = mapi_zarafa_getpermissionrules($folder, ACCESS_TYPE_GRANT); |
||
| 715 | |||
| 716 | // First check which permissions should be removed from the existing list |
||
| 717 | if (isset($permissions['remove']) && !empty($permissions['remove'])) { |
||
| 718 | foreach ($permissions['remove'] as $i => &$delAcl) { |
||
| 719 | $userid = hex2bin($delAcl['entryid']); |
||
| 720 | foreach($curAcls as $aclIndex => &$curAcl) { |
||
| 721 | if ($curAcl['userid'] === $userid) { |
||
| 722 | $curAcl['rights'] = ecRightsNone; |
||
| 723 | $curAcl['state'] = RIGHT_DELETED | RIGHT_AUTOUPDATE_DENIED; |
||
| 724 | } |
||
| 725 | } |
||
| 726 | unset($curAcl); |
||
| 727 | } |
||
| 728 | unset($delAcl); |
||
| 729 | } |
||
| 730 | |||
| 731 | // Then we check which permissions must be updated in the existing list |
||
| 732 | if (isset($permissions['modify']) && !empty($permissions['modify'])) { |
||
| 733 | foreach ($permissions['modify'] as $i => &$modAcl) { |
||
| 734 | $entryid = $modAcl['entryid']; |
||
| 735 | // No permission for this user |
||
| 736 | // This is necessary for recursive folder permissions. |
||
| 737 | // If a subfolder does not have any permissions for the user yet, |
||
| 738 | // they need to be added instead of modified. |
||
| 739 | if(!$this->idInCurrentPermissions($currentPermissions, $entryid)) { |
||
| 740 | if(!isset($permissions['add'])) { |
||
| 741 | $permissions['add'] = array(); |
||
| 742 | } |
||
| 743 | array_push($permissions['add'], $modAcl); |
||
| 744 | } else { |
||
| 745 | $userid = hex2bin($entryid); |
||
| 746 | foreach($curAcls as $aclIndex => &$curAcl) { |
||
| 747 | if ($curAcl['userid'] === $userid) { |
||
| 748 | $curAcl['rights'] = $modAcl['rights']; |
||
| 749 | $curAcl['state'] = RIGHT_MODIFY | RIGHT_AUTOUPDATE_DENIED; |
||
| 750 | } |
||
| 751 | } |
||
| 752 | } |
||
| 753 | unset($curAcl); |
||
| 754 | } |
||
| 755 | unset($modAcl); |
||
| 756 | } |
||
| 757 | |||
| 758 | // Finally we check which permissions must be added to the existing list |
||
| 759 | if (isset($permissions['add']) && !empty($permissions['add'])) { |
||
| 760 | foreach ($permissions['add'] as $i => &$addAcl) { |
||
| 761 | $curAcls[$addAcl['entryid']] = array( |
||
| 762 | 'type'=> ACCESS_TYPE_GRANT, |
||
| 763 | 'userid' => hex2bin($addAcl['entryid']), |
||
| 764 | 'rights' => $addAcl['rights'], |
||
| 765 | 'state' => RIGHT_NEW | RIGHT_AUTOUPDATE_DENIED |
||
| 766 | ); |
||
| 767 | } |
||
| 768 | unset($addAcl); |
||
| 769 | } |
||
| 770 | |||
| 771 | if (!empty($curAcls)) { |
||
| 772 | mapi_zarafa_setpermissionrules($folder, $curAcls); |
||
| 773 | |||
| 774 | // $freebusy is only set when the calendar folder permissions is updated |
||
| 775 | if (isset($freebusy)){ |
||
| 776 | // set permissions on free/busy message |
||
| 777 | foreach($curAcls as $key => &$acl) { |
||
| 778 | if ($acl['type'] == ACCESS_TYPE_GRANT && ($acl['rights'] & ecRightsEditOwned)) { |
||
| 779 | $acl['rights'] |= ecRightsEditAny; |
||
| 780 | } |
||
| 781 | } |
||
| 782 | unset($acl); |
||
| 783 | |||
| 784 | mapi_zarafa_setpermissionrules($freebusy, $curAcls); |
||
| 785 | } |
||
| 786 | } |
||
| 787 | } |
||
| 788 | |||
| 789 | function idInCurrentPermissions($currentPermissions, $entryid) { |
||
| 790 | foreach ($currentPermissions as $key => $array) { |
||
| 791 | if ($array['entryid'] === $entryid) { |
||
| 792 | return true; |
||
| 793 | } |
||
| 794 | } |
||
| 795 | return false; |
||
| 796 | } |
||
| 797 | |||
| 798 | function getUserInfo($entryid){ |
||
| 799 | |||
| 800 | // default return stuff |
||
| 801 | $result = array("fullname"=>_("Unknown user/group"), |
||
| 802 | "username"=>_("unknown"), |
||
| 803 | "entryid"=>null, |
||
| 804 | "type"=>MAPI_MAILUSER, |
||
| 805 | "id"=>$entryid |
||
| 806 | ); |
||
| 807 | |||
| 808 | // open the addressbook |
||
| 809 | $ab = $GLOBALS["mapisession"]->getAddressbook(); |
||
| 810 | |||
| 811 | $user = mapi_ab_openentry($ab, $entryid); |
||
| 812 | |||
| 813 | if ($user){ |
||
| 814 | $props = mapi_getprops($user, array(PR_ACCOUNT, PR_DISPLAY_NAME, PR_OBJECT_TYPE)); |
||
| 815 | $result["username"] = $props[PR_ACCOUNT]; |
||
| 816 | $result["fullname"] = $props[PR_DISPLAY_NAME]; |
||
| 817 | $result["entryid"] = bin2hex($entryid); |
||
| 818 | $result["type"] = $props[PR_OBJECT_TYPE]; |
||
| 819 | } |
||
| 820 | return $result; |
||
| 821 | } |
||
| 822 | |||
| 823 | /** |
||
| 824 | * Function is used to get the IPM_COMMON_VIEWS folder from defaults store. |
||
| 825 | * @return object MAPI folder object. |
||
| 826 | */ |
||
| 827 | function getCommonViewsFolder() |
||
| 828 | { |
||
| 829 | $defaultStore = $GLOBALS["mapisession"]->getDefaultMessageStore(); |
||
| 830 | $commonViewsFolderEntryid = mapi_getprops($defaultStore, array(PR_COMMON_VIEWS_ENTRYID)); |
||
| 831 | $commonViewsFolder = mapi_msgstore_openentry($defaultStore, $commonViewsFolderEntryid[PR_COMMON_VIEWS_ENTRYID]); |
||
| 832 | return $commonViewsFolder; |
||
| 833 | } |
||
| 834 | |||
| 835 | /** |
||
| 836 | * Remove favorites link message from associated contains table of IPM_COMMON_VIEWS. |
||
| 837 | * It will also remove favorites search folders of given store. |
||
| 838 | * |
||
| 839 | * @param String $entryid entryid of the folder. |
||
| 840 | * @param object $store MAPI object of the store |
||
| 841 | * @param String $prop property which is used to find record from associated contains table of |
||
| 842 | * IPM_COMMON_VIEWS folder. |
||
| 843 | * @param Boolean $doNotify true to notify the IPM_COMMO_VIEWS folder on client side. |
||
| 844 | */ |
||
| 845 | function removeFromFavorite($entryid, $store = false, $prop = PR_WLINK_ENTRYID, $doNotify = true) |
||
| 846 | { |
||
| 847 | $commonViewsFolder = $this->getCommonViewsFolder(); |
||
| 848 | $associatedTable = mapi_folder_getcontentstable($commonViewsFolder, MAPI_ASSOCIATED); |
||
| 849 | |||
| 850 | $restriction = Array(RES_OR, |
||
| 851 | Array( |
||
| 852 | array(RES_PROPERTY, |
||
| 853 | array( |
||
| 854 | RELOP => RELOP_EQ, |
||
| 855 | ULPROPTAG => PR_MESSAGE_CLASS, |
||
| 856 | VALUE => array(PR_MESSAGE_CLASS => "IPM.Microsoft.WunderBar.Link") |
||
| 857 | ) |
||
| 858 | ), |
||
| 859 | array(RES_PROPERTY, |
||
| 860 | array( |
||
| 861 | RELOP => RELOP_EQ, |
||
| 862 | ULPROPTAG => PR_MESSAGE_CLASS, |
||
| 863 | VALUE => array(PR_MESSAGE_CLASS => "IPM.Microsoft.WunderBar.SFInfo") |
||
| 864 | ) |
||
| 865 | ) |
||
| 866 | ) |
||
| 867 | ); |
||
| 868 | $finderHierarchyTables = array(); |
||
| 869 | if (!empty($store)) { |
||
| 870 | $props = mapi_getprops($store, array(PR_FINDER_ENTRYID)); |
||
| 871 | try { |
||
| 872 | $finderFolder = mapi_msgstore_openentry($store, $props[PR_FINDER_ENTRYID]); |
||
| 873 | $hierarchyTable = mapi_folder_gethierarchytable($finderFolder, MAPI_DEFERRED_ERRORS); |
||
| 874 | $finderHierarchyTables[$props[PR_FINDER_ENTRYID]] = $hierarchyTable; |
||
| 875 | } |
||
| 876 | catch(Exception $e) { |
||
| 877 | } |
||
| 878 | } |
||
| 879 | |||
| 880 | $messages = mapi_table_queryallrows($associatedTable, array(PR_ENTRYID, PR_MESSAGE_CLASS, PR_WB_SF_ID, PR_WLINK_ENTRYID, PR_WLINK_STORE_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID), $restriction); |
||
| 881 | |||
| 882 | if (!empty($messages)) { |
||
| 883 | foreach ($messages as $message) { |
||
| 884 | if ($message[PR_MESSAGE_CLASS] === "IPM.Microsoft.WunderBar.SFInfo" && !empty($finderHierarchyTables)) { |
||
| 885 | $props = $GLOBALS["operations"]->getFavoritesLinkedSearchFolderProps($message[PR_WB_SF_ID], $finderHierarchyTables); |
||
| 886 | if (!empty($props)) { |
||
| 887 | $this->deleteSearchFolder($store, $props[PR_PARENT_ENTRYID], $props[PR_ENTRYID], array()); |
||
| 888 | } |
||
| 889 | } else if ($message[PR_MESSAGE_CLASS] === "IPM.Microsoft.WunderBar.Link") { |
||
| 890 | if (isset($message[$prop]) && $GLOBALS['entryid']->compareEntryIds($message[$prop], $entryid)) { |
||
| 891 | mapi_folder_deletemessages($commonViewsFolder, array($message[PR_ENTRYID])); |
||
| 892 | if ($doNotify) { |
||
| 893 | $GLOBALS["bus"]->notify(bin2hex($message[PR_ENTRYID]), OBJECT_SAVE, $message); |
||
| 894 | } |
||
| 895 | } elseif (isset($message[PR_WLINK_STORE_ENTRYID])) { |
||
| 896 | $storeObj = $GLOBALS["mapisession"]->openMessageStore($message[PR_WLINK_STORE_ENTRYID]); |
||
| 897 | $storeProps = mapi_getprops($storeObj, array(PR_ENTRYID)); |
||
| 898 | if ($GLOBALS['entryid']->compareEntryIds($message[PR_WLINK_ENTRYID], $storeProps[PR_ENTRYID])) { |
||
| 899 | mapi_folder_deletemessages($commonViewsFolder, array($message[PR_ENTRYID])); |
||
| 900 | $this->sendFeedback(true); |
||
| 901 | } |
||
| 902 | } |
||
| 903 | } |
||
| 904 | } |
||
| 905 | } |
||
| 906 | } |
||
| 907 | |||
| 908 | /** |
||
| 909 | * Function which is used to remove the search link message(IPM.Microsoft.WunderBar.SFInfo) |
||
| 910 | * from associated contains table of IPM_COMMON_VIEWS folder. |
||
| 911 | * |
||
| 912 | * @param String $searchFolderId GUID that identifies the search folder |
||
| 913 | */ |
||
| 914 | function removeSearchLinkMessage($searchFolderId) |
||
| 915 | { |
||
| 916 | $commonViewsFolder = $this->getCommonViewsFolder(); |
||
| 917 | $associatedTable = mapi_folder_getcontentstable($commonViewsFolder, MAPI_ASSOCIATED); |
||
| 918 | |||
| 919 | $restriction = array(RES_AND, |
||
| 920 | array( |
||
| 921 | array(RES_PROPERTY, |
||
| 922 | array( |
||
| 923 | RELOP => RELOP_EQ, |
||
| 924 | ULPROPTAG => PR_MESSAGE_CLASS, |
||
| 925 | VALUE => array(PR_MESSAGE_CLASS => "IPM.Microsoft.WunderBar.SFInfo") |
||
| 926 | ) |
||
| 927 | ), |
||
| 928 | array(RES_PROPERTY, |
||
| 929 | array( |
||
| 930 | RELOP => RELOP_EQ, |
||
| 931 | ULPROPTAG => PR_WB_SF_ID, |
||
| 932 | VALUE => array(PR_WB_SF_ID => hex2bin($searchFolderId)) |
||
| 933 | ) |
||
| 934 | ) |
||
| 935 | ), |
||
| 936 | ); |
||
| 937 | |||
| 938 | $messages = mapi_table_queryallrows($associatedTable, array(PR_WB_SF_ID, PR_ENTRYID), $restriction); |
||
| 939 | |||
| 940 | if (!empty($messages)) { |
||
| 941 | foreach ($messages as $message) { |
||
| 942 | if (bin2hex($message[PR_WB_SF_ID]) === $searchFolderId) { |
||
| 943 | mapi_folder_deletemessages($commonViewsFolder, array($message[PR_ENTRYID])); |
||
| 944 | } |
||
| 945 | } |
||
| 946 | } |
||
| 947 | } |
||
| 948 | |||
| 949 | /** |
||
| 950 | * Function is used to create link message for the selected folder |
||
| 951 | * in associated contains of IPM_COMMON_VIEWS folder. |
||
| 952 | * |
||
| 953 | * @param String $store $store entryid of the store |
||
| 954 | * @param String $entryid $entryid entryid of the MAPI folder. |
||
| 955 | */ |
||
| 956 | function addToFavorite($store, $entryid) |
||
| 957 | { |
||
| 958 | $commonViewsFolder = $this->getCommonViewsFolder(); |
||
| 959 | |||
| 960 | // In Favorites list all folders are must be sibling of other folders. |
||
| 961 | // whether it is sub folder of any other folders. |
||
| 962 | // So unset "subfolders" property as we don't required to show sub folders in favorites list. |
||
| 963 | unset($this->properties["subfolders"]); |
||
| 964 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
| 965 | $folderProps = mapi_getprops($folder, $this->properties); |
||
| 966 | $GLOBALS["operations"]->createFavoritesLink($commonViewsFolder, $folderProps); |
||
| 967 | |||
| 968 | $this->addActionData("update", $GLOBALS["operations"]->setFavoritesFolder($folderProps)); |
||
| 969 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 970 | } |
||
| 971 | |||
| 972 | /** |
||
| 973 | * Function which is used delete the search folder from respective store. |
||
| 974 | * |
||
| 975 | * @param Object $store $store $store MAPI store in which search folder is belongs. |
||
| 976 | * @param array $parententryid $parententryid parent folder to search folder it is FIND_ROOT folder which |
||
| 977 | * treated as search root folder. |
||
| 978 | * @param String $entryid $entryid search folder entryid which is going to remove. |
||
| 979 | * @param array $action the action data, sent by the client |
||
| 980 | */ |
||
| 981 | function deleteSearchFolder($store, $parententryid, $entryid, $action) |
||
| 982 | { |
||
| 983 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
| 984 | $props = mapi_getprops($folder, array(PR_EXTENDED_FOLDER_FLAGS)); |
||
| 985 | // for more information about PR_EXTENDED_FOLDER_FLAGS go through this link |
||
| 986 | // https://msdn.microsoft.com/en-us/library/ee203919(v=exchg.80).aspx |
||
| 987 | $flags = unpack("H2ExtendedFlags-Id/H2ExtendedFlags-Cb/H8ExtendedFlags-Data/H2SearchFolderTag-Id/H2SearchFolderTag-Cb/H8SearchFolderTag-Data/H2SearchFolderId-Id/H2SearchFolderId-Cb/H32SearchFolderId-Data", $props[PR_EXTENDED_FOLDER_FLAGS]); |
||
| 988 | $searchFolderId = $flags["SearchFolderId-Data"]; |
||
| 989 | $this->removeSearchLinkMessage($searchFolderId); |
||
| 990 | |||
| 991 | // Do not remove the search folder when the 'keepSearchFolder' flag is set. |
||
| 992 | // This flag indicates there is currently an open search tab which uses this search folder. |
||
| 993 | if (!isset($action["message_action"]["keepSearchFolder"])) { |
||
| 994 | $finderFolder = mapi_msgstore_openentry($store, $parententryid); |
||
| 995 | return mapi_folder_deletefolder($finderFolder, $entryid , DEL_FOLDERS | DEL_MESSAGES | DELETE_HARD_DELETE); |
||
| 996 | } else { |
||
| 997 | // Rename search folder to default search folder name otherwise, |
||
| 998 | // It will not be picked up by our search folder cleanup logic. |
||
| 999 | $storeProps = mapi_getprops($store, [PR_FINDER_ENTRYID]); |
||
| 1000 | $props = array(); |
||
| 1001 | $folder = mapi_msgstore_openentry($store, $storeProps[PR_FINDER_ENTRYID]); |
||
| 1002 | $folderName = $GLOBALS["operations"]->checkFolderNameConflict($store, $folder, "grommunio Web Search Folder"); |
||
| 1003 | return $GLOBALS["operations"]->renameFolder($store, $entryid, $folderName, $props); |
||
| 1004 | } |
||
| 1005 | } |
||
| 1006 | |||
| 1007 | /** |
||
| 1008 | * Function which is used create link message for the created search folder. |
||
| 1009 | * in associated contains table of IPM_COMMON_VIEWS folder. |
||
| 1010 | * |
||
| 1011 | * @param Object $folder MAPI search folder for which link message needs to |
||
| 1012 | * create in associated contains table of IPM_COMMON_VIEWS folder. |
||
| 1013 | */ |
||
| 1014 | function createLinkedSearchFolder($folder) |
||
| 1015 | { |
||
| 1016 | $searchFolderTag = openssl_random_pseudo_bytes(4); |
||
| 1017 | $searchFolderId = openssl_random_pseudo_bytes(16); |
||
| 1018 | |||
| 1019 | // PR_EXTENDED_FOLDER_FLAGS used to create permanent/persistent search folder in MAPI. |
||
| 1020 | // also it used to identify/get the linked search folder from FINDER_ROOT folder. |
||
| 1021 | // PR_EXTENDED_FOLDER_FLAGS contains at least the SearchFolderTag, SearchFolderID, |
||
| 1022 | // and ExtendedFlags subproperties. |
||
| 1023 | // For more information about PR_EXTENDED_FOLDER_FLAGS go through this link |
||
| 1024 | // https://msdn.microsoft.com/en-us/library/ee203919(v=exchg.80).aspx |
||
| 1025 | $extendedFolderFlags = "0104000000010304".bin2hex($searchFolderTag)."0210".bin2hex($searchFolderId); |
||
| 1026 | |||
| 1027 | mapi_setprops($folder, array( |
||
| 1028 | PR_EXTENDED_FOLDER_FLAGS => hex2bin($extendedFolderFlags) |
||
| 1029 | )); |
||
| 1030 | mapi_savechanges($folder); |
||
| 1031 | |||
| 1032 | $folderProps = mapi_getprops($folder, $this->properties); |
||
| 1033 | $commonViewsFolder = $this->getCommonViewsFolder(); |
||
| 1034 | $GLOBALS["operations"]->createFavoritesLink($commonViewsFolder, $folderProps, $searchFolderId); |
||
| 1035 | |||
| 1036 | $folderProps = mapi_getprops($folder, $this->properties); |
||
| 1037 | $this->addActionData("update", $GLOBALS["operations"]->setFavoritesFolder($folderProps)); |
||
| 1038 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 1039 | } |
||
| 1040 | |||
| 1041 | /** |
||
| 1042 | * Modifies a folder off the hierarchylist. |
||
| 1043 | * @param object $store Message Store Object. |
||
| 1044 | * @param string $entryid entryid of the folder. |
||
| 1045 | * @param string $name name of the folder. |
||
| 1046 | */ |
||
| 1047 | function modifyFolder($store, $entryid, $name) |
||
| 1048 | { |
||
| 1049 | $props = array(); |
||
| 1050 | $result = $GLOBALS["operations"]->renameFolder($store, $entryid, $name, $props); |
||
| 1051 | |||
| 1052 | if($result && isset($props[PR_ENTRYID])) { |
||
| 1053 | $GLOBALS["bus"]->notify(bin2hex($props[PR_ENTRYID]), OBJECT_SAVE, $props); |
||
| 1054 | } |
||
| 1055 | } |
||
| 1056 | |||
| 1057 | /** |
||
| 1058 | * Deletes a folder in the hierarchylist. |
||
| 1059 | * @param object $store Message Store Object. |
||
| 1060 | * @param string $parententryid entryid of the parent folder. |
||
| 1061 | * @param string $entryid entryid of the folder. |
||
| 1062 | * @param array $action the action data, sent by the client |
||
| 1063 | * @return boolean true on success or false on failure. |
||
| 1064 | */ |
||
| 1065 | function deleteFolder($store, $parententryid, $entryid, $action) |
||
| 1066 | { |
||
| 1067 | $props = array(); |
||
| 1068 | $result = $GLOBALS["operations"]->deleteFolder($store, $parententryid, $entryid, $props, isset($action['soft_delete']) ? $action['soft_delete'] : false); |
||
| 1069 | |||
| 1070 | // Indicate if the delete succeedded |
||
| 1071 | $this->sendFeedback($result); |
||
| 1072 | |||
| 1073 | if(isset($props[PR_ENTRYID])) { |
||
| 1074 | if($result) { |
||
| 1075 | $GLOBALS["bus"]->notify(bin2hex($parententryid), OBJECT_SAVE, $props); |
||
| 1076 | |||
| 1077 | $props = array(); |
||
| 1078 | $props[PR_PARENT_ENTRYID] = $parententryid; |
||
| 1079 | |||
| 1080 | $storeprops = mapi_getprops($store, array(PR_ENTRYID, PR_IPM_WASTEBASKET_ENTRYID)); |
||
| 1081 | $props[PR_STORE_ENTRYID] = $storeprops[PR_ENTRYID]; |
||
| 1082 | $GLOBALS["bus"]->notify(bin2hex($parententryid), OBJECT_SAVE, $props); |
||
| 1083 | |||
| 1084 | $props[PR_PARENT_ENTRYID] = $storeprops[PR_IPM_WASTEBASKET_ENTRYID]; |
||
| 1085 | $GLOBALS["bus"]->notify(bin2hex($parententryid), OBJECT_SAVE, $props); |
||
| 1086 | } |
||
| 1087 | } else { |
||
| 1088 | $props[PR_ENTRYID] = $entryid; |
||
| 1089 | $props[PR_PARENT_ENTRYID] = $parententryid; |
||
| 1090 | |||
| 1091 | if($result) { |
||
| 1092 | $this->removeFromFavorite($props[PR_ENTRYID]); |
||
| 1093 | |||
| 1094 | $storeprops = mapi_getprops($store, array(PR_ENTRYID, PR_IPM_FAVORITES_ENTRYID)); |
||
| 1095 | $props[PR_STORE_ENTRYID] = $storeprops[PR_ENTRYID]; |
||
| 1096 | |||
| 1097 | // Notify about that folder is deleted |
||
| 1098 | $GLOBALS["bus"]->notify(bin2hex($parententryid), OBJECT_DELETE, $props); |
||
| 1099 | |||
| 1100 | // Notify its parent about the delete |
||
| 1101 | $GLOBALS["bus"]->notify(bin2hex($parententryid), OBJECT_SAVE, $props); |
||
| 1102 | |||
| 1103 | // Notifying corresponding folder in 'Favorites' |
||
| 1104 | if (isset($storeprops[PR_IPM_FAVORITES_ENTRYID])){ |
||
| 1105 | $folderEntryID = "00000001". substr(bin2hex($entryid), 8); |
||
| 1106 | $props[PR_ENTRYID] = hex2bin($folderEntryID); |
||
| 1107 | $props[PR_PARENT_ENTRYID] = $storeprops[PR_IPM_FAVORITES_ENTRYID]; |
||
| 1108 | $GLOBALS["bus"]->notify(bin2hex($parententryid), OBJECT_DELETE, $props); |
||
| 1109 | } |
||
| 1110 | } |
||
| 1111 | } |
||
| 1112 | } |
||
| 1113 | |||
| 1114 | /** |
||
| 1115 | * Deletes all messages in a folder. |
||
| 1116 | * @param object $store Message Store Object. |
||
| 1117 | * @param string $entryid entryid of the folder. |
||
| 1118 | * @return boolean true on success or false on failure. |
||
| 1119 | */ |
||
| 1120 | function emptyFolder($store, $entryid) |
||
| 1121 | { |
||
| 1122 | $props = array(); |
||
| 1123 | |||
| 1124 | $result = false; |
||
| 1125 | |||
| 1126 | // False will only remove the message of |
||
| 1127 | // selected folder only and can't remove the |
||
| 1128 | // child folders. |
||
| 1129 | $emptySubFolders = false; |
||
| 1130 | $storeProps = mapi_getprops($store, array(PR_IPM_WASTEBASKET_ENTRYID)); |
||
| 1131 | // Check that selected folder is Waste basket or Junk folder then empty folder by removing |
||
| 1132 | // the child folders. |
||
| 1133 | if(isset($storeProps[PR_IPM_WASTEBASKET_ENTRYID]) && $storeProps[PR_IPM_WASTEBASKET_ENTRYID] === $entryid) { |
||
| 1134 | $emptySubFolders = true; |
||
| 1135 | } else { |
||
| 1136 | $root = mapi_msgstore_openentry($store, null); |
||
| 1137 | $rootProps = mapi_getprops($root, array(PR_ADDITIONAL_REN_ENTRYIDS)); |
||
| 1138 | // check if selected folder is junk folder then make junk folder empty with |
||
| 1139 | // it's child folder and it's contains. |
||
| 1140 | if(isset($rootProps[PR_ADDITIONAL_REN_ENTRYIDS]) && is_array($rootProps[PR_ADDITIONAL_REN_ENTRYIDS])) { |
||
| 1141 | // Checking if folder is junk folder or not. |
||
| 1142 | $emptySubFolders = $GLOBALS['entryid']->compareEntryIds($rootProps[PR_ADDITIONAL_REN_ENTRYIDS][4], $entryid); |
||
| 1143 | } |
||
| 1144 | |||
| 1145 | if($emptySubFolders === false) { |
||
| 1146 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
| 1147 | $folderProps = mapi_getprops($folder, array(PR_SUBFOLDERS)); |
||
| 1148 | $emptySubFolders = $folderProps[PR_SUBFOLDERS] === false; |
||
| 1149 | } |
||
| 1150 | } |
||
| 1151 | |||
| 1152 | $result = $GLOBALS["operations"]->emptyFolder($store, $entryid, $props, false, $emptySubFolders); |
||
| 1153 | |||
| 1154 | if($result && isset($props[PR_ENTRYID])) { |
||
| 1155 | $this->addFolderToResponseData($store, $entryid, "folders"); |
||
| 1156 | |||
| 1157 | // Add all response data to Bus |
||
| 1158 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 1159 | } |
||
| 1160 | } |
||
| 1161 | |||
| 1162 | /** |
||
| 1163 | * Copies of moves a folder in the hierarchylist. |
||
| 1164 | * @param object $store Message Store Object. |
||
| 1165 | * @param string $parententryid entryid of the parent folder. |
||
| 1166 | * @param string $sourcefolderentryid entryid of the folder to be copied of moved. |
||
| 1167 | * @param string $destfolderentryid entryid of the destination folder. |
||
| 1168 | * @param string $action move or copy the folder. |
||
| 1169 | * @return boolean true on success or false on failure. |
||
| 1170 | */ |
||
| 1171 | function copyFolder($store, $parententryid, $sourcefolderentryid, $destfolderentryid, $deststore, $moveFolder) |
||
| 1172 | { |
||
| 1173 | $props = array(); |
||
| 1174 | $result = $GLOBALS["operations"]->copyFolder($store, $parententryid, $sourcefolderentryid, $destfolderentryid, $deststore, $moveFolder, $props); |
||
| 1175 | |||
| 1176 | if($result) { |
||
| 1177 | if($moveFolder) { |
||
| 1178 | try { |
||
| 1179 | // If destination folder is wastebasket then remove source folder from favorites list if |
||
| 1180 | // it is present in it. |
||
| 1181 | $defaultStore = $GLOBALS["mapisession"]->getDefaultMessageStore(); |
||
| 1182 | $wastebasketFolderEntryid = mapi_getprops($defaultStore, array(PR_IPM_WASTEBASKET_ENTRYID)); |
||
| 1183 | if($GLOBALS["entryid"]->compareEntryIds($wastebasketFolderEntryid[PR_IPM_WASTEBASKET_ENTRYID], $destfolderentryid)) { |
||
| 1184 | $this->removeFromFavorite($sourcefolderentryid); |
||
| 1185 | } |
||
| 1186 | |||
| 1187 | /* |
||
| 1188 | * Normally it works well within same store, |
||
| 1189 | * but entryid gets changed when different stores so we can't use old entryid anymore. |
||
| 1190 | * When moving to different store send delete notification. |
||
| 1191 | */ |
||
| 1192 | $this->addFolderToResponseData($deststore, $sourcefolderentryid, "folders"); |
||
| 1193 | |||
| 1194 | // Add all response data to Bus |
||
| 1195 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 1196 | } catch (MAPIException $e) { |
||
| 1197 | if($e->getCode() == MAPI_E_INVALID_ENTRYID) { |
||
| 1198 | // Entryid of the folder might be change after move, so send delete notification for folder. |
||
| 1199 | $GLOBALS["bus"]->notify(bin2hex($props[PR_ENTRYID]), OBJECT_DELETE, $props); |
||
| 1200 | } |
||
| 1201 | } |
||
| 1202 | |||
| 1203 | // if move folder then refresh parent of source folder |
||
| 1204 | $sourcefolder = mapi_msgstore_openentry($store, $parententryid); |
||
| 1205 | $folderProps = mapi_getprops($sourcefolder, array(PR_ENTRYID, PR_STORE_ENTRYID)); |
||
| 1206 | $GLOBALS["bus"]->notify(bin2hex($folderProps[PR_ENTRYID]), OBJECT_SAVE, $folderProps); |
||
| 1207 | } else { |
||
| 1208 | $this->sendFeedback(true); |
||
| 1209 | } |
||
| 1210 | |||
| 1211 | // Update subfolders of copy/move folder |
||
| 1212 | $folder = mapi_msgstore_openentry($deststore, $destfolderentryid); |
||
| 1213 | $hierarchyTable = mapi_folder_gethierarchytable($folder, CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS); |
||
| 1214 | mapi_table_sort($hierarchyTable, array(PR_DISPLAY_NAME => TABLE_SORT_ASCEND), TBL_BATCH); |
||
| 1215 | |||
| 1216 | /** |
||
| 1217 | * remove hidden folders, folders with PR_ATTR_HIDDEN property set |
||
| 1218 | * should not be shown to the client |
||
| 1219 | */ |
||
| 1220 | $restriction = Array(RES_OR, |
||
| 1221 | Array( |
||
| 1222 | Array(RES_PROPERTY, |
||
| 1223 | Array( |
||
| 1224 | RELOP => RELOP_EQ, |
||
| 1225 | ULPROPTAG => PR_ATTR_HIDDEN, |
||
| 1226 | VALUE => Array( PR_ATTR_HIDDEN => false ) |
||
| 1227 | ) |
||
| 1228 | ), |
||
| 1229 | Array(RES_NOT, |
||
| 1230 | Array( |
||
| 1231 | Array(RES_EXIST, |
||
| 1232 | Array( |
||
| 1233 | ULPROPTAG => PR_ATTR_HIDDEN |
||
| 1234 | ) |
||
| 1235 | ) |
||
| 1236 | ) |
||
| 1237 | ) |
||
| 1238 | ) |
||
| 1239 | ); |
||
| 1240 | |||
| 1241 | $subfolders = mapi_table_queryallrows($hierarchyTable, array(PR_ENTRYID), $restriction); |
||
| 1242 | |||
| 1243 | if (is_array($subfolders)) { |
||
| 1244 | foreach($subfolders as $subfolder) { |
||
| 1245 | $folderObject = mapi_msgstore_openentry($deststore, $subfolder[PR_ENTRYID]); |
||
| 1246 | $folderProps = mapi_getprops($folderObject, array(PR_ENTRYID, PR_STORE_ENTRYID)); |
||
| 1247 | $GLOBALS["bus"]->notify(bin2hex($subfolder[PR_ENTRYID]), OBJECT_SAVE, $folderProps); |
||
| 1248 | } |
||
| 1249 | } |
||
| 1250 | |||
| 1251 | // Now update destination folder |
||
| 1252 | $folder = mapi_msgstore_openentry($deststore, $destfolderentryid); |
||
| 1253 | $folderProps = mapi_getprops($folder, array(PR_ENTRYID, PR_STORE_ENTRYID)); |
||
| 1254 | $GLOBALS["bus"]->notify(bin2hex($folderProps[PR_ENTRYID]), OBJECT_SAVE, $folderProps); |
||
| 1255 | } else { |
||
| 1256 | if ($moveFolder) { |
||
| 1257 | $this->sendFeedback(false, _('Could not move folder')); |
||
| 1258 | } else { |
||
| 1259 | $this->sendFeedback(false, _('Could not copy folder')); |
||
| 1260 | } |
||
| 1261 | } |
||
| 1262 | } |
||
| 1263 | |||
| 1264 | /** |
||
| 1265 | * Set all messages read. |
||
| 1266 | * @param object $store Message Store Object. |
||
| 1267 | * @param string $entryid entryid of the folder. |
||
| 1268 | * @return boolean true on success or false on failure. |
||
| 1269 | */ |
||
| 1270 | function setReadFlags($store, $entryid) |
||
| 1271 | { |
||
| 1272 | $props = array(); |
||
| 1273 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
| 1274 | |||
| 1275 | if (!$folder) { |
||
| 1276 | return; |
||
| 1277 | } |
||
| 1278 | |||
| 1279 | if (mapi_folder_setreadflags($folder, array(), SUPPRESS_RECEIPT)) { |
||
| 1280 | $props = mapi_getprops($folder, array(PR_ENTRYID, PR_STORE_ENTRYID)); |
||
| 1281 | |||
| 1282 | if (!isset($props[PR_ENTRYID])) { |
||
| 1283 | return; |
||
| 1284 | } |
||
| 1285 | |||
| 1286 | $this->addFolderToResponseData($store, $props[PR_ENTRYID], "folders"); |
||
| 1287 | |||
| 1288 | // Add all response data to Bus |
||
| 1289 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
| 1290 | } |
||
| 1291 | } |
||
| 1292 | } |
||
| 1293 | ?> |
||
|
0 ignored issues
–
show
It is not recommended to use PHP's closing tag
?> in files other than templates.
Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore. A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever. Loading history...
|
|||
| 1294 |