Back to index

d-push  2.0
asdevice.php
Go to the documentation of this file.
00001 <?php
00002 /***********************************************
00003 * File      :   asdevice.php
00004 * Project   :   Z-Push
00005 * Descr     :   The ASDevice holds basic data about a device,
00006 *               its users and the linked states
00007 *
00008 * Created   :   11.04.2011
00009 *
00010 * Copyright 2007 - 2011 Zarafa Deutschland GmbH
00011 *
00012 * This program is free software: you can redistribute it and/or modify
00013 * it under the terms of the GNU Affero General Public License, version 3,
00014 * as published by the Free Software Foundation with the following additional
00015 * term according to sec. 7:
00016 *
00017 * According to sec. 7 of the GNU Affero General Public License, version 3,
00018 * the terms of the AGPL are supplemented with the following terms:
00019 *
00020 * "Zarafa" is a registered trademark of Zarafa B.V.
00021 * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
00022 * The licensing of the Program under the AGPL does not imply a trademark license.
00023 * Therefore any rights, title and interest in our trademarks remain entirely with us.
00024 *
00025 * However, if you propagate an unmodified version of the Program you are
00026 * allowed to use the term "Z-Push" to indicate that you distribute the Program.
00027 * Furthermore you may use our trademarks where it is necessary to indicate
00028 * the intended purpose of a product or service provided you use it in accordance
00029 * with honest practices in industrial or commercial matters.
00030 * If you want to propagate modified versions of the Program under the name "Z-Push",
00031 * you may only do so if you have a written permission by Zarafa Deutschland GmbH
00032 * (to acquire a permission please contact Zarafa at trademark@zarafa.com).
00033 *
00034 * This program is distributed in the hope that it will be useful,
00035 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00036 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00037 * GNU Affero General Public License for more details.
00038 *
00039 * You should have received a copy of the GNU Affero General Public License
00040 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00041 *
00042 * Consult LICENSE file for details
00043 ************************************************/
00044 
00045 class ASDevice extends StateObject {
00046     const UNDEFINED = -1;
00047     // content data
00048     const FOLDERUUID = 1;
00049     const FOLDERTYPE = 2;
00050     const FOLDERSUPPORTEDFIELDS = 3;
00051 
00052     // expected values for not set member variables
00053     protected $unsetdata = array(
00054                                     'useragenthistory' => array(),
00055                                     'hierarchyuuid' => false,
00056                                     'contentdata' => array(),
00057                                     'wipestatus' => SYNC_PROVISION_RWSTATUS_NA,
00058                                     'wiperequestedby' => false,
00059                                     'wiperequestedon' => false,
00060                                     'wipeactionon' => false,
00061                                     'lastupdatetime' => 0,
00062                                     'conversationmode' => false,
00063                                     'policies' => array(),
00064                                     'policykey' => self::UNDEFINED,
00065                                     'forcesave' => false,
00066                                     'asversion' => false,
00067                                     'ignoredmessages' => array(),
00068                                     'announcedASversion' => false,
00069                                 );
00070 
00071     static private $loadedData;
00072     protected $newdevice;
00073     protected $hierarchyCache;
00074     protected $ignoredMessageIds;
00075 
00087     public function ASDevice($devid, $devicetype, $getuser, $useragent) {
00088         $this->deviceid = $devid;
00089         $this->devicetype = $devicetype;
00090         list ($this->deviceuser, $this->domain) =  Utils::SplitDomainUser($getuser);
00091         $this->useragent = $useragent;
00092         $this->firstsynctime = time();
00093         $this->newdevice = true;
00094         $this->ignoredMessageIds = array();
00095     }
00096 
00106     public function SetData($stateObject, $semanticUpdate = true) {
00107         if (!($stateObject instanceof StateObject) || !isset($stateObject->devices) || !is_array($stateObject->devices)) return;
00108 
00109         // is information about this device & user available?
00110         if (isset($stateObject->devices[$this->deviceuser]) && $stateObject->devices[$this->deviceuser] instanceof ASDevice) {
00111             // overwrite local data with data from the saved object
00112             $this->SetDataArray($stateObject->devices[$this->deviceuser]->GetDataArray());
00113             $this->newdevice = false;
00114             ZLog::Write(LOGLEVEL_DEBUG, sprintf("ASDevice data loaded for user: '%s'", $this->deviceuser));
00115         }
00116 
00117         // check if RWStatus from another user on same device may require action
00118         if ($semanticUpdate && count($stateObject->devices) > 1) {
00119             foreach ($stateObject->devices as $user=>$asuserdata) {
00120                 if ($user == $this->user) continue;
00121 
00122                 // another user has a required action on this device
00123                 if (isset($asuserdata->wipeStatus) && $asuserdata->wipeStatus > SYNC_PROVISION_RWSTATUS_OK) {
00124                     ZLog::Write(LOGLEVEL_INFO, sprintf("User '%s' has requested a remote wipe for this device on '%s'", $asuserdata->wipeRequestBy, strftime("%Y-%m-%d %H:%M", $asuserdata->wipeRequstOn)));
00125 
00126                     // reset status to PENDING if wipe was executed before
00127                     $this->wipeStatus =  ($asuserdata->wipeStatus & SYNC_PROVISION_RWSTATUS_WIPED)?SYNC_PROVISION_RWSTATUS_PENDING:$asuserdata->wipeStatus;
00128                     $this->wipeRequestBy =  $asuserdata->wipeRequestBy;
00129                     $this->wipeRequestOn =  $asuserdata->wipeRequestOn;
00130                     $this->wipeActionOn = $asuserdata->wipeActionOn;
00131                     break;
00132                 }
00133             }
00134         }
00135 
00136         self::$loadedData = $stateObject;
00137         $this->changed = false;
00138     }
00139 
00147     public function GetData() {
00148         if (! $this->changed)
00149             return false;
00150 
00151         // device was updated
00152         $this->lastupdatetime = time();
00153         unset($this->ignoredMessageIds);
00154 
00155         if (!isset(self::$loadedData) || !isset(self::$loadedData->devices) || !is_array(self::$loadedData->devices)) {
00156             self::$loadedData = new StateObject();
00157             $devices = array();
00158         }
00159         else
00160             $devices = self::$loadedData->devices;
00161 
00162         $devices[$this->deviceuser] = $this;
00163 
00164         // check if RWStatus has to be updated so it can be updated for other users on same device
00165         if (isset($this->wipeStatus) && $this->wipeStatus > SYNC_PROVISION_RWSTATUS_OK) {
00166             foreach ($devices as $user=>$asuserdata) {
00167                 if ($user == $this->deviceuser) continue;
00168                 if (isset($this->wipeStatus))       $asuserdata->wipeStatus     = $this->wipeStatus;
00169                 if (isset($this->wipeRequestBy))    $asuserdata->wipeRequestBy  = $this->wipeRequestBy;
00170                 if (isset($this->wipeRequestOn))    $asuserdata->wipeRequestOn  = $this->wipeRequestOn;
00171                 if (isset($this->wipeActionOn))     $asuserdata->wipeActionOn   = $this->wipeActionOn;
00172                 $devices[$user] = $asuserdata;
00173 
00174                 ZLog::Write(LOGLEVEL_DEBUG, sprintf("Updated remote wipe status for user '%s' on the same device", $user));
00175             }
00176         }
00177         self::$loadedData->devices = $devices;
00178         return self::$loadedData;
00179     }
00180 
00187     public function StripData() {
00188         unset($this->changed);
00189         unset($this->unsetdata);
00190         unset($this->hierarchyCache);
00191         unset($this->forceSave);
00192         unset($this->newdevice);
00193         unset($this->ignoredMessageIds);
00194 
00195         if (isset($this->ignoredmessages) && is_array($this->ignoredmessages)) {
00196             $imessages = $this->ignoredmessages;
00197             $unserializedMessage = array();
00198             foreach ($imessages as $im) {
00199                 $im->asobject = unserialize($im->asobject);
00200                 $im->asobject->StripData();
00201                 $unserializedMessage[] = $im;
00202             }
00203             $this->ignoredmessages = $unserializedMessage;
00204         }
00205 
00206         return true;
00207     }
00208 
00215     public function IsNewDevice() {
00216         return (isset($this->newdevice) && $this->newdevice === true);
00217     }
00218 
00219 
00230     public function GetDeviceUserAgent() {
00231         if (!isset($this->useragent) || !$this->useragent)
00232             return "unknown";
00233 
00234         return $this->useragent;
00235     }
00236 
00243     public function GetDeviceUserAgentHistory() {
00244         return $this->useragentHistory;
00245     }
00246 
00256     public function SetUserAgent($useragent) {
00257         if ($useragent == $this->useragent || $useragent === false || $useragent === Request::UNKNOWN)
00258             return true;
00259 
00260         // save the old user agent, if available
00261         if ($this->useragent != "") {
00262             // [] = changedate, previous user agent
00263             $a = $this->useragentHistory;
00264             $a[] = array(time(), $this->useragent);
00265             $this->useragentHistory = $a;
00266         }
00267         $this->useragent = $useragent;
00268         return true;
00269     }
00270 
00279     public function SetWipeStatus($status, $requestedBy = false) {
00280         // force saving the updated information if there was a transition between the wiping status
00281         if ($this->wipeStatus > SYNC_PROVISION_RWSTATUS_OK && $status > SYNC_PROVISION_RWSTATUS_OK)
00282             $this->forceSave = true;
00283 
00284         if ($requestedBy != false) {
00285             $this->wipeRequestedBy = $requestedBy;
00286             $this->wipeRequestedOn = time();
00287         }
00288         else {
00289             $this->wipeActionOn = time();
00290         }
00291 
00292         $this->wipeStatus = $status;
00293 
00294         if ($this->wipeStatus > SYNC_PROVISION_RWSTATUS_PENDING)
00295             ZLog::Write(LOGLEVEL_INFO, sprintf("ASDevice id '%s' was %s remote wiped on %s. Action requested by user '%s' on %s",
00296                                         $this->deviceid, ($this->wipeStatus == SYNC_PROVISION_RWSTATUS_REQUESTED ? "requested to be": "sucessfully"),
00297                                         strftime("%Y-%m-%d %H:%M", $this->wipeActionOn), $this->wipeRequestedBy, strftime("%Y-%m-%d %H:%M", $this->wipeRequestedOn)));
00298     }
00299 
00308     public function SetPolicyKey($policykey) {
00309         $this->policykey = $policykey;
00310         if ($this->GetWipeStatus() == SYNC_PROVISION_RWSTATUS_NA)
00311             $this->wipeStatus = SYNC_PROVISION_RWSTATUS_OK;
00312     }
00313 
00322     public function AddIgnoredMessage($ignoredMessage) {
00323         // we should have all previousily ignored messages in an id array
00324         if (count($this->ignoredMessages) != count($this->ignoredMessageIds)) {
00325             foreach($this->ignoredMessages as $oldMessage) {
00326                 if (!isset($this->ignoredMessageIds[$oldMessage->folderid]))
00327                     $this->ignoredMessageIds[$oldMessage->folderid] = array();
00328                 $this->ignoredMessageIds[$oldMessage->folderid][] = $oldMessage->id;
00329             }
00330         }
00331 
00332         // serialize the AS object - if available
00333         if (isset($ignoredMessage->asobject))
00334             $ignoredMessage->asobject = serialize($ignoredMessage->asobject);
00335 
00336         // try not to add the same message several times
00337         if (isset($ignoredMessage->folderid) && isset($ignoredMessage->id)) {
00338             if (!isset($this->ignoredMessageIds[$ignoredMessage->folderid]))
00339                 $this->ignoredMessageIds[$ignoredMessage->folderid] = array();
00340 
00341             if (in_array($ignoredMessage->id, $this->ignoredMessageIds[$ignoredMessage->folderid]))
00342                 $this->RemoveIgnoredMessage($ignoredMessage->folderid, $ignoredMessage->id);
00343 
00344             $this->ignoredMessageIds[$ignoredMessage->folderid][] = $ignoredMessage->id;
00345             $msges = $this->ignoredMessages;
00346             $msges[] = $ignoredMessage;
00347             $this->ignoredMessages = $msges;
00348 
00349             return true;
00350         }
00351         else {
00352             $msges = $this->ignoredMessages;
00353             $msges[] = $ignoredMessage;
00354             $this->ignoredMessages = $msges;
00355             ZLog::Write(LOGLEVEL_WARN, "ASDevice->AddIgnoredMessage(): added message has no folder/id");
00356             return true;
00357         }
00358     }
00359 
00369     public function RemoveIgnoredMessage($folderid, $id) {
00370         // we should have all previousily ignored messages in an id array
00371         if (count($this->ignoredMessages) != count($this->ignoredMessageIds)) {
00372             foreach($this->ignoredMessages as $oldMessage) {
00373                 if (!isset($this->ignoredMessageIds[$oldMessage->folderid]))
00374                     $this->ignoredMessageIds[$oldMessage->folderid] = array();
00375                 $this->ignoredMessageIds[$oldMessage->folderid][] = $oldMessage->id;
00376             }
00377         }
00378 
00379         $foundMessage = false;
00380         // there are ignored messages in that folder
00381         if (isset($this->ignoredMessageIds[$folderid])) {
00382             // resync of a folder.. we should remove all previousily ignored messages
00383             if ($id === false || in_array($id, $this->ignoredMessageIds[$folderid], true)) {
00384                 $ignored = $this->ignoredMessages;
00385                 $newMessages = array();
00386                 foreach ($ignored as $im) {
00387                     if ($im->folderid = $folderid) {
00388                         if ($id === false || $im->id === $id) {
00389                             $foundMessage = true;
00390                             if (count($this->ignoredMessageIds[$folderid]) == 1) {
00391                                 unset($this->ignoredMessageIds[$folderid]);
00392                             }
00393                             else {
00394                                 unset($this->ignoredMessageIds[$folderid][array_search($id, $this->ignoredMessageIds[$folderid])]);
00395                             }
00396                             continue;
00397                         }
00398                         else
00399                             $newMessages[] = $im;
00400                     }
00401                 }
00402                 $this->ignoredMessages = $newMessages;
00403             }
00404         }
00405 
00406         return $foundMessage;
00407     }
00408 
00418     public function HasIgnoredMessage($folderid, $id) {
00419         // we should have all previousily ignored messages in an id array
00420         if (count($this->ignoredMessages) != count($this->ignoredMessageIds)) {
00421             foreach($this->ignoredMessages as $oldMessage) {
00422                 if (!isset($this->ignoredMessageIds[$oldMessage->folderid]))
00423                     $this->ignoredMessageIds[$oldMessage->folderid] = array();
00424                 $this->ignoredMessageIds[$oldMessage->folderid][] = $oldMessage->id;
00425             }
00426         }
00427 
00428         $foundMessage = false;
00429         // there are ignored messages in that folder
00430         if (isset($this->ignoredMessageIds[$folderid])) {
00431             // resync of a folder.. we should remove all previousily ignored messages
00432             if ($id === false || in_array($id, $this->ignoredMessageIds[$folderid], true)) {
00433                 $foundMessage = true;
00434             }
00435         }
00436 
00437         return $foundMessage;
00438     }
00439 
00456     public function SetHierarchyCache($hierarchydata = false) {
00457         if ($hierarchydata !== false && $hierarchydata instanceof ChangesMemoryWrapper) {
00458             $this->hierarchyCache = $hierarchydata;
00459             $this->hierarchyCache->CopyOldState();
00460         }
00461         else
00462             $this->hierarchyCache = new ChangesMemoryWrapper();
00463 
00464         if (is_array($hierarchydata))
00465             return $this->hierarchyCache->ImportFolders($hierarchydata);
00466         return true;
00467     }
00468 
00475     public function GetHierarchyCacheData() {
00476         if (isset($this->hierarchyCache))
00477             return $this->hierarchyCache;
00478 
00479         ZLog::Write(LOGLEVEL_WARN, "ASDevice->GetHierarchyCacheData() has no data! HierarchyCache probably never initialized.");
00480         return false;
00481     }
00482 
00489     public function GetHierarchyCache() {
00490         if (!isset($this->hierarchyCache))
00491             $this->SetHierarchyCache();
00492 
00493         ZLog::Write(LOGLEVEL_DEBUG, "ASDevice->GetHierarchyCache(): ". $this->hierarchyCache->GetStat());
00494         return $this->hierarchyCache;
00495     }
00496 
00503     public function GetAllFolderIds() {
00504         if (isset($this->contentData) && is_array($this->contentData))
00505             return array_keys($this->contentData);
00506         return array();
00507     }
00508 
00517     public function GetFolderUUID($folderid = false) {
00518         if ($folderid === false)
00519             return (isset($this->hierarchyUuid) && $this->hierarchyUuid !== self::UNDEFINED) ? $this->hierarchyUuid : false;
00520         else if (isset($this->contentData) && isset($this->contentData[$folderid]) && isset($this->contentData[$folderid][self::FOLDERUUID]))
00521             return $this->contentData[$folderid][self::FOLDERUUID];
00522         return false;
00523     }
00524 
00535     public function SetFolderUUID($uuid, $folderid = false) {
00536         if ($folderid === false) {
00537             $this->hierarchyUuid = $uuid;
00538             // when unsetting the hierarchycache, also remove saved contentdata and ignoredmessages
00539             if ($folderid === false) {
00540                 $this->contentData = array();
00541                 $this->ignoredMessageIds = array();
00542                 $this->ignoredMessages = array();
00543             }
00544         }
00545         else {
00546 
00547             $contentData = $this->contentData;
00548             if (!isset($contentData[$folderid]) || !is_array($contentData[$folderid]))
00549                 $contentData[$folderid] = array();
00550 
00551             // check if the foldertype is set. This has to be available at this point, as generated during the first HierarchySync
00552             if (!isset($contentData[$folderid][self::FOLDERTYPE]))
00553                 return false;
00554 
00555             if ($uuid)
00556                 $contentData[$folderid][self::FOLDERUUID] = $uuid;
00557             else
00558                 $contentData[$folderid][self::FOLDERUUID] = false;
00559 
00560             $this->contentData = $contentData;
00561         }
00562     }
00563 
00572     public function GetFolderType($folderid) {
00573         if (isset($this->contentData) && isset($this->contentData[$folderid]) &&
00574             isset($this->contentData[$folderid][self::FOLDERTYPE]) )
00575 
00576             return $this->contentData[$folderid][self::FOLDERTYPE];
00577         return false;
00578     }
00579 
00589     public function SetFolderType($folderid, $foldertype) {
00590         $contentData = $this->contentData;
00591 
00592         if (!isset($contentData[$folderid]) || !is_array($contentData[$folderid]))
00593             $contentData[$folderid] = array();
00594         if (!isset($contentData[$folderid][self::FOLDERTYPE]) || $contentData[$folderid][self::FOLDERTYPE] != $foldertype ) {
00595             $contentData[$folderid][self::FOLDERTYPE] = $foldertype;
00596             $this->contentData = $contentData;
00597             return true;
00598         }
00599         return false;
00600     }
00601 
00611     public function GetSupportedFields($folderid) {
00612         if (isset($this->contentData) && isset($this->contentData[$folderid]) &&
00613             isset($this->contentData[$folderid][self::FOLDERUUID]) && $this->contentData[$folderid][self::FOLDERUUID] !== false &&
00614             isset($this->contentData[$folderid][self::FOLDERSUPPORTEDFIELDS]) )
00615 
00616             return $this->contentData[$folderid][self::FOLDERSUPPORTEDFIELDS];
00617 
00618         return false;
00619     }
00620 
00630     public function SetSupportedFields($folderid, $fieldlist) {
00631         $contentData = $this->contentData;
00632         if (!isset($contentData[$folderid]) || !is_array($contentData[$folderid]))
00633             $contentData[$folderid] = array();
00634 
00635         $contentData[$folderid][self::FOLDERSUPPORTEDFIELDS] = $fieldlist;
00636         $this->contentData = $contentData;
00637         return true;
00638     }
00639 }
00640 
00641 ?>