/** * Constructor * * @access public */ public function __construct() { $this->statemachine = ZPush::GetStateMachine(); $this->deviceHash = false; $this->devid = Request::GetDeviceID(); $this->saveDevice = true; $this->windowSize = array(); $this->latestFolder = false; $this->hierarchySyncRequired = false; // only continue if deviceid is set if ($this->devid) { $this->device = new ASDevice($this->devid, Request::GetDeviceType(), Request::GetGETUser(), Request::GetUserAgent()); $this->loadDeviceData(); ZPush::GetTopCollector()->SetUserAgent($this->device->GetDeviceUserAgent()); } else { throw new FatalNotImplementedException("Can not proceed without a device id."); } $this->loopdetection = new LoopDetection(); $this->loopdetection->ProcessLoopDetectionInit(); $this->loopdetection->ProcessLoopDetectionPreviousConnectionFailed(); $this->stateManager = new StateManager(); $this->stateManager->SetDevice($this->device); $this->additionalFoldersHash = $this->getAdditionalFoldersHash(); if ($this->IsKoe() && $this->device->GetKoeVersion() !== false) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("KOE: %s / %s / %s", $this->device->GetKoeVersion(), $this->device->GetKoeBuild(), strftime("%Y-%m-%d %H:%M", $this->device->GetKoeBuildDate()))); } }
/** * Constructor * * @access public */ public function DeviceManager() { $this->statemachine = ZPush::GetStateMachine(); $this->deviceHash = false; $this->devid = Request::GetDeviceID(); $this->windowSize = array(); $this->latestFolder = false; $this->hierarchySyncRequired = false; // only continue if deviceid is set if ($this->devid) { $this->device = new ASDevice($this->devid, Request::GetDeviceType(), Request::GetGETUser(), Request::GetUserAgent()); $this->loadDeviceData(); ZPush::GetTopCollector()->SetUserAgent($this->device->GetDeviceUserAgent()); } else { throw new FatalNotImplementedException("Can not proceed without a device id."); } $this->loopdetection = new LoopDetection(); $this->loopdetection->ProcessLoopDetectionInit(); $this->loopdetection->ProcessLoopDetectionPreviousConnectionFailed(); $this->stateManager = new StateManager(); $this->stateManager->SetDevice($this->device); }
/** * Execute the migration * * @access public * @return true */ public function DoMigration() { // go through all files $files = glob(STATE_DIR . "/*/*/*", GLOB_NOSORT); $filetotal = count($files); $filecount = 0; $rencount = 0; $igncount = 0; foreach ($files as $file) { $filecount++; $newfile = strtolower($file); echo "[1G"; if ($file !== $newfile) { $rencount++; rename($file, $newfile); } else { $igncount++; } printf("Migrating file %d/%d\t%s", $filecount, $filetotal, $file); } echo "[1G" . sprintf("Migrated total of %d files, %d renamed and %d ignored (as already correct)%s\n\n", $filetotal, $rencount, $igncount, str_repeat(" ", 50)); // get all states of synchronized devices $alldevices = $this->sm->GetAllDevices(false); foreach ($alldevices as $devid) { $lowerDevid = strtolower($devid); echo "Processing device: " . $devid . "\t"; // update device data $devState = ZPush::GetStateMachine()->GetState($lowerDevid, IStateMachine::DEVICEDATA); $newdata = array(); foreach ($devState->devices as $user => $dev) { if (!isset($dev->deviceidOrg)) { $dev->deviceidOrg = $dev->deviceid; } $dev->deviceid = strtolower($dev->deviceid); $dev->useragenthistory = array_unique($dev->useragenthistory); $newdata[$user] = $dev; } $devState->devices = $newdata; $this->sm->SetState($devState, $lowerDevid, IStateMachine::DEVICEDATA); // go through the users again: device was updated sucessfully, now we change the global user <-> device link foreach ($devState->devices as $user => $dev) { printf("\n\tUn-linking %s with old device id %s", $user, $dev->deviceidOrg); $this->sm->UnLinkUserDevice($user, $dev->deviceidOrg); printf("\n\tRe-linking %s with new device id %s", $user, $dev->deviceid); $this->sm->LinkUserDevice($user, $dev->deviceid); } echo "\n\tcompleted\n"; } echo "\nSetting new StateVersion\n"; $this->sm->SetStateVersion(self::TOVERSION); echo "Migration completed!\n\n"; return true; }
/** * UnLinks all states from a folder id * Old states are removed assisting the StateMachine to get rid of old data. * The UUID is then removed from the device * * @param ASDevice $device * @param string $folderid * @param boolean $removeFromDevice indicates if the device should be * notified that the state was removed * @param boolean $retrieveUUIDFromDevice indicates if the UUID should be retrieved from * device. If not true this parameter will be used as UUID. * * @access public * @return boolean */ public static function UnLinkState(&$device, $folderid, $removeFromDevice = true, $retrieveUUIDFromDevice = true) { if ($retrieveUUIDFromDevice === true) { $savedUuid = $device->GetFolderUUID($folderid); } else { $savedUuid = $retrieveUUIDFromDevice; } if ($savedUuid) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("StateManager::UnLinkState('%s'): saved state '%s' will be deleted.", $folderid, $savedUuid)); ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::DEFTYPE, $savedUuid, self::FIXEDHIERARCHYCOUNTER * 2); ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::FOLDERDATA, $savedUuid); // CPO ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::FAILSAVE, $savedUuid, self::FIXEDHIERARCHYCOUNTER * 2); ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::BACKENDSTORAGE, $savedUuid, self::FIXEDHIERARCHYCOUNTER * 2); // remove all messages which could not be synched before $device->RemoveIgnoredMessage($folderid, false); if ($folderid === false && $savedUuid !== false) { ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::HIERARCHY, $savedUuid, self::FIXEDHIERARCHYCOUNTER * 2); } } // delete this id from the uuid cache if ($removeFromDevice) { return $device->SetFolderUUID(false, $folderid); } else { return true; } }
/** * Marks a all folders synchronized to a device for re-synchronization * If no user is set all user which are synchronized for a device are marked for re-synchronization. * If no device id is set all devices of that user are marked for re-synchronization. * If no user and no device are set then ALL DEVICES are marked for resynchronization (use with care!). * * @param string $user (opt) user of the device * @param string $devid (opt)device id which should be wiped * * @return boolean * @access public */ public static function ResyncDevice($user, $devid = false) { // search for target devices if ($devid === false) { $devicesIds = ZPush::GetStateMachine()->GetAllDevices($user); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncDevice(): all '%d' devices for user '%s' found to be re-synchronized", count($devicesIds), $user)); foreach ($devicesIds as $deviceid) { if (!self::ResyncDevice($user, $deviceid)) { ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): wipe devices failed for device '%s' of user '%s'. Aborting", $deviceid, $user)); return false; } } } else { // get devicedata try { $devicedata = ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA); } catch (StateNotFoundException $e) { ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): state for device '%s' can not be found", $devid)); return false; } // loop through all users which currently use this device if ($user === false && $devicedata instanceof StateObject && isset($devicedata->devices) && is_array($devicedata->devices) && count($devicedata->devices) > 1) { foreach (array_keys($devicedata) as $aUser) { if (!self::ResyncDevice($aUser, $devid)) { ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): re-synchronization failed for device '%s' of user '%s'. Aborting", $devid, $aUser)); return false; } } } // load device data $device = new ASDevice($devid, ASDevice::UNDEFINED, $user, ASDevice::UNDEFINED); try { $device->SetData($devicedata, false); if ($device->IsNewDevice()) { ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): data of user '%s' not synchronized on device '%s'. Aborting.", $user, $devid)); return false; } // delete all uuids foreach ($device->GetAllFolderIds() as $folderid) { StateManager::UnLinkState($device, $folderid); } // remove hierarchcache StateManager::UnLinkState($device, false); ZPush::GetStateMachine()->SetState($device->GetData(), $devid, IStateMachine::DEVICEDATA); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncDevice(): all folders synchronized to device '%s' of user '%s' marked to be re-synchronized.", $devid, $user)); } catch (StateNotFoundException $e) { ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): state for device '%s' of user '%s' can not be found or saved", $devid, $user)); return false; } } return true; }
/** * Authenticates the user on each backend * * @param string $username * @param string $domain * @param string $password * * @access public * @return boolean */ public function Logon($username, $domain, $password) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("Combined->Logon('%s', '%s',***))", $username, $domain)); if (!is_array($this->backends)) { return false; } foreach ($this->backends as $i => $b) { $u = $username; $d = $domain; $p = $password; // Apply mapping from configuration if (isset($this->config['backends'][$i]['users'])) { if (!isset($this->config['backends'][$i]['users'][$username])) { unset($this->backends[$i]); continue; } if (isset($this->config['backends'][$i]['users'][$username]['username'])) { $u = $this->config['backends'][$i]['users'][$username]['username']; } if (isset($this->config['backends'][$i]['users'][$username]['password'])) { $p = $this->config['backends'][$i]['users'][$username]['password']; } if (isset($this->config['backends'][$i]['users'][$username]['domain'])) { $d = $this->config['backends'][$i]['users'][$username]['domain']; } } // Apply username mapping from state backend if (isset($this->config['usemapping']) && $this->config['usemapping']) { $mappedUsername = ZPush::GetStateMachine()->GetMappedUsername($u, strtolower($this->config['backends'][$i]['name'])); if ($mappedUsername !== null) { $u = $mappedUsername; } } if ($this->backends[$i]->Logon($u, $d, $p) == false) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("Combined->Logon() failed on %s ", $this->config['backends'][$i]['name'])); return false; } $this->backends[$i]->SetOriginalUsername($username); } ZLog::Write(LOGLEVEL_DEBUG, "Combined->Logon() success"); return true; }
/** * Fixes states of the user linking to the states * and removes all obsolete states * * @return boolean * @access public */ public static function FixStatesUserToStatesLinking() { $processed = 0; $deleted = 0; $devices = ZPush::GetStateMachine()->GetAllDevices(false); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::FixStatesUserToStatesLinking(): found %d devices", count($devices))); foreach ($devices as $devid) { try { // we work on device level $devicedata = ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA); $knownUuids = array(); // get all known UUIDs for this device foreach (self::ListUsers($devid) as $username) { $device = new ASDevice($devid, ASDevice::UNDEFINED, $username, ASDevice::UNDEFINED); $device->SetData($devicedata, false); // get all known uuids of this device $folders = $device->GetAllFolderIds(); // add a "false" folder id so the hierarchy UUID is retrieved $folders[] = false; foreach ($folders as $folderid) { $uuid = $device->GetFolderUUID($folderid); if ($uuid) { $knownUuids[] = $uuid; } } } } catch (StateNotFoundException $e) { } // get all uuids for deviceid from statemachine $existingStates = ZPush::GetStateMachine()->GetAllStatesForDevice($devid); $processed = count($existingStates); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::FixStatesUserToStatesLinking(): found %d valid uuids and %d states for device device '%s'", count($knownUuids), $processed, $devid)); // remove states for all unknown uuids foreach ($existingStates as $obsoleteState) { if ($obsoleteState['type'] === IStateMachine::DEVICEDATA) { continue; } if (!in_array($obsoleteState['uuid'], $knownUuids)) { if (is_numeric($obsoleteState['counter'])) { $obsoleteState['counter']++; } ZPush::GetStateMachine()->CleanStates($devid, $obsoleteState['type'], $obsoleteState['uuid'], $obsoleteState['counter']); $deleted++; } } } return array($processed, $deleted); }
/** * Unmaps a username for a specific backend. * * @param string $user The username * @param string $backend Name of the backend to unmap * * @return boolean */ public static function RemoveUsernameMapping($user, $backend) { if (!ZPush::GetStateMachine()->UnmapUsername($user, $backend)) { ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::RemoveUsernameMapping(): unable to remove mapping for user %s and backend %s", $user, $backend)); return false; } ZLog::Write(LOGLEVEL_INFO, sprintf("ZPushAdmin::RemoveUsernameMapping(): successfully unmapped user %s and backend %s", $user, $backend)); return true; }