/** * Marks a a device of the Request::GetGETUser() for resynchronization * * @param string $deviceId the device id * * @access public * @return boolean * @throws SoapFault */ public function ResyncDevice($deviceId) { $deviceId = preg_replace("/[^A-Za-z0-9]/", "", $deviceId); ZLog::Write(LOGLEVEL_INFO, sprintf("WebserviceDevice::ResyncDevice('%s'): mark device of user '%s' for resynchronization", $deviceId, Request::GetGETUser())); if (!ZPushAdmin::ResyncDevice(Request::GetGETUser(), $deviceId)) { ZPush::GetTopCollector()->AnnounceInformation(ZLog::GetLastMessage(LOGLEVEL_ERROR), true); throw new SoapFault("ERROR", ZLog::GetLastMessage(LOGLEVEL_ERROR)); } ZPush::GetTopCollector()->AnnounceInformation(sprintf("Resync requested - device id '%s'", $deviceId), true); return true; }
/** * Prints detailed informations about a device * * @param string $deviceId the id of the device * @param string $user the user * * @return * @access private */ private static function printDeviceData($deviceId, $user) { $device = ZPushAdmin::GetDeviceDetails($deviceId, $user); if (!$device instanceof ASDevice) { echo sprintf("Folder resync failed: %s\n", ZLog::GetLastMessage(LOGLEVEL_ERROR)); return false; } // Gather some statistics about synchronized folders $folders = $device->GetAllFolderIds(); $synchedFolders = 0; $synchedFolderTypes = array(); $syncedFoldersInProgress = 0; foreach ($folders as $folderid) { if ($device->GetFolderUUID($folderid)) { $synchedFolders++; $type = $device->GetFolderType($folderid); switch ($type) { case SYNC_FOLDER_TYPE_APPOINTMENT: case SYNC_FOLDER_TYPE_USER_APPOINTMENT: $gentype = "Calendars"; break; case SYNC_FOLDER_TYPE_CONTACT: case SYNC_FOLDER_TYPE_USER_CONTACT: $gentype = "Contacts"; break; case SYNC_FOLDER_TYPE_TASK: case SYNC_FOLDER_TYPE_USER_TASK: $gentype = "Tasks"; break; case SYNC_FOLDER_TYPE_NOTE: case SYNC_FOLDER_TYPE_USER_NOTE: $gentype = "Notes"; break; default: $gentype = "Emails"; break; } if (!isset($synchedFolderTypes[$gentype])) { $synchedFolderTypes[$gentype] = 0; } $synchedFolderTypes[$gentype]++; // set the folder name for all folders which are not fully synchronized yet $fstatus = $device->GetFolderSyncStatus($folderid); if ($fstatus !== false && is_array($fstatus)) { // TODO would be nice if we could see the real name of the folder, right now we use the folder type as name $fstatus['name'] = $gentype; $device->SetFolderSyncStatus($folderid, $fstatus); $syncedFoldersInProgress++; } } } $folderinfo = ""; foreach ($synchedFolderTypes as $gentype => $count) { $folderinfo .= $gentype; if ($count > 1) { $folderinfo .= "({$count})"; } $folderinfo .= " "; } if (!$folderinfo) { $folderinfo = "None available"; } echo "-----------------------------------------------------\n"; echo "DeviceId:\t\t{$deviceId}\n"; echo "Device type:\t\t" . ($device->GetDeviceType() !== ASDevice::UNDEFINED ? $device->GetDeviceType() : "unknown") . "\n"; echo "UserAgent:\t\t" . ($device->GetDeviceUserAgent() !== ASDevice::UNDEFINED ? $device->GetDeviceUserAgent() : "unknown") . "\n"; // TODO implement $device->GetDeviceUserAgentHistory() // device information transmitted during Settings command if ($device->GetDeviceModel()) { echo "Device Model:\t\t" . $device->GetDeviceModel() . "\n"; } if ($device->GetDeviceIMEI()) { echo "Device IMEI:\t\t" . $device->GetDeviceIMEI() . "\n"; } if ($device->GetDeviceFriendlyName()) { echo "Device friendly name:\t" . $device->GetDeviceFriendlyName() . "\n"; } if ($device->GetDeviceOS()) { echo "Device OS:\t\t" . $device->GetDeviceOS() . "\n"; } if ($device->GetDeviceOSLanguage()) { echo "Device OS Language:\t" . $device->GetDeviceOSLanguage() . "\n"; } if ($device->GetDevicePhoneNumber()) { echo "Device Phone nr:\t" . $device->GetDevicePhoneNumber() . "\n"; } if ($device->GetDeviceMobileOperator()) { echo "Device Operator:\t" . $device->GetDeviceMobileOperator() . "\n"; } if ($device->GetDeviceEnableOutboundSMS()) { echo "Device Outbound SMS:\t" . $device->GetDeviceEnableOutboundSMS() . "\n"; } echo "ActiveSync version:\t" . ($device->GetASVersion() ? $device->GetASVersion() : "unknown") . "\n"; echo "First sync:\t\t" . strftime("%Y-%m-%d %H:%M", $device->GetFirstSyncTime()) . "\n"; echo "Last sync:\t\t" . ($device->GetLastSyncTime() ? strftime("%Y-%m-%d %H:%M", $device->GetLastSyncTime()) : "never") . "\n"; echo "Total folders:\t\t" . count($folders) . "\n"; echo "Synchronized folders:\t" . $synchedFolders; if ($syncedFoldersInProgress > 0) { echo " (" . $syncedFoldersInProgress . " in progress)"; } echo "\n"; echo "Synchronized data:\t{$folderinfo}\n"; if ($syncedFoldersInProgress > 0) { echo "Synchronization progress:\n"; foreach ($folders as $folderid) { $d = $device->GetFolderSyncStatus($folderid); if ($d) { $status = ""; if ($d['total'] > 0) { $percent = round($d['done'] * 100 / $d['total']); $status = sprintf("Status: %s%d%% (%d/%d)", $percent < 10 ? " " : "", $percent, $d['done'], $d['total']); } printf("\tFolder: %s%s Sync: %s %s\n", $d['name'], str_repeat(" ", 12 - strlen($d['name'])), $d['status'], $status); } } } echo "Status:\t\t\t"; switch ($device->GetWipeStatus()) { case SYNC_PROVISION_RWSTATUS_OK: echo "OK\n"; break; case SYNC_PROVISION_RWSTATUS_PENDING: echo "Pending wipe\n"; break; case SYNC_PROVISION_RWSTATUS_REQUESTED: echo "Wipe requested on device\n"; break; case SYNC_PROVISION_RWSTATUS_WIPED: echo "Wiped\n"; break; default: echo "Not available\n"; break; } echo "WipeRequest on:\t\t" . ($device->GetWipeRequestedOn() ? strftime("%Y-%m-%d %H:%M", $device->GetWipeRequestedOn()) : "not set") . "\n"; echo "WipeRequest by:\t\t" . ($device->GetWipeRequestedBy() ? $device->GetWipeRequestedBy() : "not set") . "\n"; echo "Wiped on:\t\t" . ($device->GetWipeActionOn() ? strftime("%Y-%m-%d %H:%M", $device->GetWipeActionOn()) : "not set") . "\n"; echo "Attention needed:\t"; if ($device->GetDeviceError()) { echo $device->GetDeviceError() . "\n"; } else { if (!isset($device->ignoredmessages) || empty($device->ignoredmessages)) { echo "No errors known\n"; } else { printf("%d messages need attention because they could not be synchronized\n", count($device->ignoredmessages)); foreach ($device->ignoredmessages as $im) { $info = ""; if (isset($im->asobject->subject)) { $info .= sprintf("Subject: '%s'", $im->asobject->subject); } if (isset($im->asobject->fileas)) { $info .= sprintf("FileAs: '%s'", $im->asobject->fileas); } if (isset($im->asobject->from)) { $info .= sprintf(" - From: '%s'", $im->asobject->from); } if (isset($im->asobject->starttime)) { $info .= sprintf(" - On: '%s'", strftime("%Y-%m-%d %H:%M", $im->asobject->starttime)); } $reason = $im->reasonstring; if ($im->reasoncode == 2) { $reason = "Message was causing loop"; } printf("\tBroken object:\t'%s' ignored on '%s'\n", $im->asclass, strftime("%Y-%m-%d %H:%M", $im->timestamp)); printf("\tInformation:\t%s\n", $info); printf("\tReason: \t%s (%s)\n", $reason, $im->reasoncode); printf("\tItem/Parent id: %s/%s\n", $im->id, $im->folderid); echo "\n"; } } } }
/** * Returns a list of all known devices with users and when they synchronized for the first time * * @access public * @return array */ public function ListDevicesDetails() { $devices = ZPushAdmin::ListDevices(false); $output = array(); ZLog::Write(LOGLEVEL_INFO, sprintf("WebserviceUsers::ListLastSync(): found %d devices", count($devices))); ZPush::GetTopCollector()->AnnounceInformation(sprintf("Retrieved details of %d devices and getting users", count($devices)), true); foreach ($devices as $deviceId) { $output[$deviceId] = array(); $users = ZPushAdmin::ListUsers($deviceId); foreach ($users as $user) { $output[$deviceId][$user] = ZPushAdmin::GetDeviceDetails($deviceId, $user); } } return $output; }
/** * Imports a move of a message. This occurs when a user moves an item to another folder * * @param string $id * @param string $newfolder * * @access public * @return boolean */ public function ImportMessageMove($id, $newfolder) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesCombined->ImportMessageMove('%s', '%s')", $id, $newfolder)); if (!$this->icc) { ZLog::Write(LOGLEVEL_ERROR, "ImportChangesCombined->ImportMessageMove icc not configured"); return false; } if ($this->backend->GetBackendId($this->folderid) != $this->backend->GetBackendId($newfolder)) { ZLog::Write(LOGLEVEL_WARN, "ImportChangesCombined->ImportMessageMove() cannot move message between two backends"); return false; } $res = $this->icc->ImportMessageMove($id, $this->backend->GetBackendFolder($newfolder)); if ($res) { //TODO: we should add newid to new folder, instead of a full folder resync ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesCombined->ImportMessageMove(): Force resync of dest folder (%s)", $newfolder)); ZPushAdmin::ResyncFolder(Request::GetAuthUser(), Request::GetDeviceID(), $newfolder); } return $res; }
/** * Execute the migration. * * @access public * @return true */ public function DoMigration() { print "StateMigratorFileToDB->DoMigration(): Starting migration routine." . PHP_EOL; $starttime = time(); $deviceCount = 0; $stateCount = 0; try { // Fix hierarchy folder data before starting the migration ZPushAdmin::FixStatesHierarchyFolderData(); $this->fsm = new FileStateMachine(); if (!$this->fsm instanceof FileStateMachine) { throw new FatalNotImplementedException("This conversion script is only able to convert states from the FileStateMachine"); } // get all state information for all devices $alldevices = $this->fsm->GetAllDevices(false); foreach ($alldevices as $devid) { $deviceCount++; $lowerDevid = strtolower($devid); $allStates = $this->fsm->GetAllStatesForDevice($lowerDevid); printf("Processing device: %s with %s states\t", str_pad($devid, 35), str_pad(count($allStates), 4, ' ', STR_PAD_LEFT)); $migrated = 0; foreach ($allStates as $stateInfo) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("StateMigratorFileToDB->DoMigration(): Migrating state type:'%s' uuid:'%s' counter:'%s'", Utils::PrintAsString($stateInfo['type']), Utils::PrintAsString($stateInfo['uuid']), Utils::PrintAsString($stateInfo['counter']))); $state = $this->fsm->GetState($lowerDevid, $stateInfo['type'], $stateInfo['uuid'], (int) $stateInfo['counter'], false); $this->dbsm->SetState($state, $lowerDevid, $stateInfo['type'], empty($stateInfo['uuid']) ? NULL : $stateInfo['uuid'], (int) $stateInfo['counter']); $migrated++; } // link devices to users $devState = $this->fsm->GetState($lowerDevid, IStateMachine::DEVICEDATA); foreach ($devState->devices as $user => $dev) { $this->dbsm->LinkUserDevice($user, $dev->deviceid); } print " completed migration of {$migrated} states" . PHP_EOL; $stateCount += $migrated; } } catch (ZPushException $ex) { print PHP_EOL . "Something went wrong during the migration. The script will now exit." . PHP_EOL; die(get_class($ex) . ": " . $ex->getMessage() . PHP_EOL); } $timeSpent = gmdate("H:i:s", time() - $starttime); printf(PHP_EOL . "StateMigratorFileToDB->DoMigration(): Migration completed successfuly. Migrated %d devices with %d states in %s." . PHP_EOL . PHP_EOL, $deviceCount, $stateCount, $timeSpent); }
/** * Removes an additional folder from the given device and the Request::GetGETUser(). * * @param string $deviceId device id of where the folder should be removed. * @param string $add_folderid the folder id of the additional folder. * * @access public * @return boolean */ public function AdditionalFolderRemove($deviceId, $add_folderid) { $user = Request::GetGETUser(); $deviceId = preg_replace("/[^A-Za-z0-9]/", "", $deviceId); $add_folderid = preg_replace("/[^A-Za-z0-9]/", "", $add_folderid); $status = ZPushAdmin::AdditionalFolderRemove($user, $deviceId, $add_folderid); if (!$status) { ZPush::GetTopCollector()->AnnounceInformation(ZLog::GetLastMessage(LOGLEVEL_ERROR), true); throw new SoapFault("ERROR", ZLog::GetLastMessage(LOGLEVEL_ERROR)); } ZLog::Write(LOGLEVEL_INFO, sprintf("WebserviceDevice::AdditionalFolderRemove(): removed folder for device '%s' of user '%s': %s", $deviceId, $user, Utils::PrintAsString($status))); ZPush::GetTopCollector()->AnnounceInformation("Removed additional folder", true); return $status; }