Commit d5759a24 authored by Sebastian Kummer's avatar Sebastian Kummer

Merge pull request #402 in ZP/z-push from release/2.3 to master

* commit 'ec254052': (23 commits)
  ZP-1073 Use exit() instead of die().
  ZP-1076 Catch StatusException in ZPushAdmin::GetDeviceDetails().
  ZP-1073 list-shared-folders script, incl. usage examples (in file).
  ZP-1073 Refactor Utils::GetFolderOriginFromId() into GetFolderOriginStringFromId() so GetFolderOriginFromId() returns a value comparable to DeviceManager::FLD_ORIGIN_*.
  ZP-1017 Replace z-push.sf.net url with z-push.org.
  ZP-1062 depend on php instead of php7.0. Released under the Affero GNU General Public License (AGPL) version 3.
  ZP-1058 autodiscover: Fix mistake: always send response
  ZP-1056 Fail earlier when no password is provided. Log used username before trying to login in the backend. The $username will always be set and doesn't need to be checked again.
  ZP-1054 Use sprintf.
  ZP-1054 Throw UnavailableException if the hash cannot be loaded.
  ZP-1047 Count the elements to be moved only once.
  ZP-1047 Better logging when moving large amounts of messages in one request.
  ZP-1063 Items marked as private are shown in shared folders.
  ZP-1069 Ignore incoming KOE reply flag category update.
  ZP-1056 Fix authorization encoding and also add it to autodiscover. Released under the Affero GNU General Public License (AGPL) version 3.
  ZP-1060 Before ignoring SyncNote changes make sure they're coming from KOE and the notes capability is enabled.
  ZP-1063 Items marked as private are shown in shared folders.
  ZP-1060 Ignore incoming KOE updates from PatchItem.
  ZP-1058 autodiscover: Rework exception handling to match z-push core.
  ZP-1058 autodiscover: Print IP to log on failed authentication for usage with e.g. fail2ban
  ...
parents f9ac780e ec254052
......@@ -8,7 +8,7 @@ Homepage: http://z-push.org
Package: z-push-common
Architecture: all
Depends: ${misc:Depends}, php5 (>= 5.4) | php7.0, php5-cli | php7.0-cli, php-soap
Depends: ${misc:Depends}, php5 (>= 5.4) | php (>= 5.4) , php5-cli | php-cli, php-soap
Conflicts: d-push, z-push
Replaces: d-push, z-push
Description: open source implementation of the ActiveSync protocol
......@@ -26,7 +26,7 @@ Description: Z-Push caldav backend
Package: z-push-backend-carddav
Architecture: all
Depends: ${misc:Depends}, z-push-common (= ${binary:Version}), php-curl | php5-curl, php5-xsl | php7.0-xsl
Depends: ${misc:Depends}, z-push-common (= ${binary:Version}), php-curl | php5-curl, php5-xsl | php-xml
Description: Z-Push carddav backend
Backend for Z-Push, that adds the ability to connect to a carddav server
......
This diff is collapsed.
......@@ -104,25 +104,42 @@ class ZPushAutodiscover {
}
}
catch (AuthenticationRequiredException $ex) {
if (isset($incomingXml)) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover because login failed for user with email '%s'", $incomingXml->Request->EMailAddress));
catch (Exception $ex) {
// Extract any previous exception message for logging purpose.
$exclass = get_class($ex);
$exception_message = $ex->getMessage();
if($ex->getPrevious()){
do {
$current_exception = $ex->getPrevious();
$exception_message .= ' -> ' . $current_exception->getMessage();
} while($current_exception->getPrevious());
}
else {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover incorrect request: '%s'", $ex->getMessage()));
ZLog::Write(LOGLEVEL_FATAL, sprintf('Exception: (%s) - %s', $exclass, $exception_message));
if ($ex instanceof AuthenticationRequiredException) {
if (isset($incomingXml)) {
// log the failed login attemt e.g. for fail2ban
if (defined('LOGAUTHFAIL') && LOGAUTHFAIL != false)
ZLog::Write(LOGLEVEL_WARN, sprintf("Unable to complete autodiscover because login failed for user with email '%s' from IP %s.", $incomingXml->Request->EMailAddress, $_SERVER["REMOTE_ADDR"]));
}
else {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover incorrect request: '%s'", $ex->getMessage()));
}
http_response_code(401);
header('WWW-Authenticate: Basic realm="ZPush"');
}
http_response_code(401);
header('WWW-Authenticate: Basic realm="ZPush"');
}
catch (ZPushException $ex) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover because of ZPushException. Error: %s", $ex->getMessage()));
if(!headers_sent()) {
header('HTTP/1.1 '. $ex->getHTTPCodeString());
foreach ($ex->getHTTPHeaders() as $h) {
header($h);
else if ($ex instanceof ZPushException) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover because of ZPushException. Error: %s", $ex->getMessage()));
if(!headers_sent()) {
header('HTTP/1.1 '. $ex->getHTTPCodeString());
foreach ($ex->getHTTPHeaders() as $h) {
header($h);
}
}
}
}
$this->sendResponse($response);
}
......@@ -182,21 +199,32 @@ class ZPushAutodiscover {
* @return string $username
*/
private function login($backend, $incomingXml) {
// don't even try to login if there is no PW set
if (!isset($_SERVER['PHP_AUTH_PW'])) {
throw new AuthenticationRequiredException("Access denied. No password provided.");
}
// Determine the login name depending on the configuration: complete email address or
// the local part only.
if (USE_FULLEMAIL_FOR_LOGIN) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Using the complete email address for login."));
$username = $incomingXml->Request->EMailAddress;
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Using the complete email address for login: '%s'", $username));
}
else{
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Using the username only for login."));
else {
$username = Utils::GetLocalPartFromEmail($incomingXml->Request->EMailAddress);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Using the username only for login: '%s'", $username));
}
if($backend->Logon($username, "", $_SERVER['PHP_AUTH_PW']) == false) {
// Mobile devices send Authorization header using UTF-8 charset. Outlook sends it using ISO-8859-1 encoding.
// For the successful authentication the user and password must be UTF-8 encoded. Try to determine which
// charset was sent by the client and convert it to UTF-8. See https://jira.z-hub.io/browse/ZP-864.
$username = Utils::ConvertAuthorizationToUTF8($username);
$password = Utils::ConvertAuthorizationToUTF8($_SERVER['PHP_AUTH_PW']);
if ($backend->Logon($username, "", $password) == false) {
throw new AuthenticationRequiredException("Access denied. Username or password incorrect.");
}
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAutodiscover->login() Using '%s' as the username.", $username));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAutodiscover->login() successfull with '%s' as the username.", $username));
return $username;
}
......
......@@ -131,6 +131,15 @@ class PHPWrapper {
$mapimessage = mapi_msgstore_openentry($this->store, $entryid);
try {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("PHPWrapper->ImportMessageChange(): Getting message from MAPIProvider, sourcekey: '%s', parentsourcekey: '%s', entryid: '%s'", bin2hex($sourcekey), bin2hex($parentsourcekey), bin2hex($entryid)));
// do not send private messages from shared folders to the device
$sensitivity = mapi_getprops($mapimessage, array(PR_SENSITIVITY));
$sharedUser = ZPush::GetAdditionalSyncFolderStore(bin2hex($this->folderid));
if ($sharedUser != false && $sharedUser != 'SYSTEM' && isset($sensitivity[PR_SENSITIVITY]) && $sensitivity[PR_SENSITIVITY] >= SENSITIVITY_PRIVATE) {
ZLog::Write(LOGLEVEL_DEBUG, "PHPWrapper->ImportMessageChange(): ignoring private message from a shared folder");
return SYNC_E_IGNORE;
}
$message = $this->mapiprovider->GetMessage($mapimessage, $this->contentparameters);
}
catch (SyncObjectBrokenException $mbe) {
......
......@@ -748,6 +748,12 @@ class MAPIProvider {
// android devices require attachment size in order to display an attachment properly
if (!isset($attachprops[PR_ATTACH_SIZE])) {
$stream = mapi_openpropertytostream($mapiattach, PR_ATTACH_DATA_BIN);
// It's not possible to open some (embedded only?) messages, so we need to open the attachment object itself to get the data
if (mapi_last_hresult()) {
$embMessage = mapi_attach_openobj($mapiattach);
$addrbook = $this->getAddressbook();
$stream = mapi_inetmapi_imtoinet($this->session, $addrbook, $embMessage, array('use_tnef' => -1));
}
$stat = mapi_stream_stat($stream);
$attach->estimatedDataSize = $stat['cb'];
}
......
......@@ -270,6 +270,24 @@ class ReplyBackImExporter implements IImportChanges, IExportChanges {
* @return boolean
*/
public function ImportMessageChange($id, $message) {
if(ZPush::GetDeviceManager()->IsKoe()) {
// Ignore incoming update events of KOE caused by PatchItem - ZP-1060
if (KOE_CAPABILITY_NOTES && $id && $message instanceof SyncNote && !isset($message->asbody)) {
ZLog::Write(LOGLEVEL_DEBUG, "ReplyBackImExporter->ImportMessageChange(): KOE patch item update. Ignoring incoming update.");
return true;
}
// KOE ZP-990: OL updates the deleted category which causes a race condition if more than one KOE is connected to that user
if (KOE_CAPABILITY_RECEIVEFLAGS && $message instanceof SyncMail && !isset($message->flag) && isset($message->categories)) {
// check if the categories changed
$serverMessage = $this->getMessage($id, false);
if((empty($message->categories) && empty($serverMessage->categories)) ||
(is_array($mapiCategories) && count(array_diff($mapiCategories, $message->categories)) == 0 && count(array_diff($message->categories, $mapiCategories)) == 0)) {
ZLog::Write(LOGLEVEL_DEBUG, "ReplyBackImExporter->ImportMessageChange(): KOE update of flag categories. Ignoring incoming update.");
return true;
}
}
}
// data is going to be dropped, inform the user
if (@constant('READ_ONLY_NOTIFY_LOST_DATA')) {
try {
......
......@@ -143,7 +143,7 @@ class SqlStateMachine implements IStateMachine {
*
* @access public
* @return string
* @throws StateNotFoundException, StateInvalidException
* @throws StateNotFoundException, StateInvalidException, UnavailableException
*/
public function GetStateHash($devid, $type, $key = null, $counter = false) {
$hash = null;
......@@ -155,8 +155,12 @@ class SqlStateMachine implements IStateMachine {
$record = $sth->fetch(PDO::FETCH_ASSOC);
if (!$record) {
$errCode = $sth->errorCode();
$this->clearConnection($this->dbh, $sth, $record);
throw new StateNotFoundException("SqlStateMachine->GetStateHash(): Could not locate state");
if ($errCode == 'HY000') {
throw new UnavailableException("SqlStateMachine->GetStateHash(): Database not available", $errCode, null, LOGLEVEL_WARN);
}
throw new StateNotFoundException(sprintf("SqlStateMachine->GetStateHash(): Could not locate state with error code: %s", $errCode));
}
else {
// datetime->format("U") returns EPOCH
......
......@@ -1001,6 +1001,13 @@ class DeviceManager {
catch (StateNotFoundException $snfex) {
$this->hierarchySyncRequired = true;
}
catch (UnavailableException $uaex) {
// This is temporary and can be ignored e.g. in PING - see https://jira.z-hub.io/browse/ZP-1054
// If the hash was not available before we treat it like a StateNotFoundException.
if ($this->deviceHash === false) {
$this->hierarchySyncRequired = true;
}
}
return true;
}
......
......@@ -92,7 +92,7 @@ class FileStateMachine implements IStateMachine {
*
* @access public
* @return string
* @throws StateNotFoundException, StateInvalidException
* @throws StateNotFoundException, StateInvalidException, UnavailableException
*/
public function GetStateHash($devid, $type, $key = false, $counter = false) {
$filename = $this->getFullFilePath($devid, $type, $key, $counter);
......
......@@ -82,7 +82,7 @@ interface IStateMachine {
*
* @access public
* @return string
* @throws StateNotFoundException, StateInvalidException
* @throws StateNotFoundException, StateInvalidException, UnavailableException
*/
public function GetStateHash($devid, $type, $key = false, $counter = false);
......
......@@ -86,7 +86,11 @@ class MoveItems extends RequestProcessor {
self::$encoder->startTag(SYNC_MOVE_MOVES);
$operationResults = array();
$operationCounter = 0;
$operationTotal = count($moves);
foreach($moves as $move) {
$operationCounter++;
self::$encoder->startTag(SYNC_MOVE_RESPONSE);
self::$encoder->startTag(SYNC_MOVE_SRCMSGID);
self::$encoder->content($move["srcmsgid"]);
......@@ -141,7 +145,15 @@ class MoveItems extends RequestProcessor {
$status = $stex->getCode();
}
self::$topCollector->AnnounceInformation(sprintf("Operation status: %s", $status), true);
if ($operationCounter % 10 == 0) {
self::$topCollector->AnnounceInformation(sprintf("Moved %d objects out of %d", $operationCounter, $operationTotal));
}
// save the operation result
if (!isset($operationResults[$status])) {
$operationResults[$status] = 0;
}
$operationResults[$status]++;
self::$encoder->startTag(SYNC_MOVE_STATUS);
self::$encoder->content($status);
......@@ -153,6 +165,12 @@ class MoveItems extends RequestProcessor {
self::$encoder->endTag();
}
self::$topCollector->AnnounceInformation(sprintf("Moved %d - Codes", $operationTotal), true);
foreach ($operationResults as $status => $occurences) {
self::$topCollector->AnnounceInformation(sprintf("%dx%d", $occurences, $status), true);
}
self::$encoder->endTag();
return true;
}
......
......@@ -254,25 +254,10 @@ class Request {
// Mobile devices send Authorization header using UTF-8 charset. Outlook sends it using ISO-8859-1 encoding.
// For the successful authentication the user and password must be UTF-8 encoded. Try to determine which
// charset was sent by the client and convert it to UTF-8. See https://jira.z-hub.io/browse/ZP-864.
if (isset($_SERVER['PHP_AUTH_USER'])) {
$encoding = mb_detect_encoding(self::$authUser, "UTF-8, ISO-8859-1");
if (!$encoding) {
$encoding = mb_detect_encoding(self::$authUser, Utils::GetAvailableCharacterEncodings());
if ($encoding) {
ZLog::Write(LOGLEVEL_WARN,
sprintf("Request->ProcessHeaders(): mb_detect_encoding detected '%s' charset. This charset is not in the default detect list. Please report it to Z-Push developers.",
$encoding));
}
else {
ZLog::Write(LOGLEVEL_ERROR, "Request->ProcessHeaders(): mb_detect_encoding failed to detect the Authorization header charset. It's possible that user won't be able to login.");
}
}
if ($encoding && strtolower($encoding) != "utf-8") {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Request->ProcessHeaders(): mb_detect_encoding detected '%s' charset. Authorization header will be converted to UTF-8 from it.", $encoding));
self::$authUser = mb_convert_encoding(self::$authUser, "UTF-8", $encoding);
self::$authPassword = mb_convert_encoding(self::$authPassword, "UTF-8", $encoding);
}
}
if (isset(self::$authUser))
self::$authUser = Utils::ConvertAuthorizationToUTF8(self::$authUser);
if (isset(self::$authPassword))
self::$authPassword = Utils::ConvertAuthorizationToUTF8(self::$authPassword);
}
/**
......
......@@ -1092,15 +1092,36 @@ class Utils {
}
/**
* Returns folder origin from its id.
* Returns folder origin identifier from its id.
*
* @param string $fid
* @param string $folderid
*
* @access public
* @return string|boolean matches values of DeviceManager::FLD_ORIGIN_*
*/
public static function GetFolderOriginFromId($folderid) {
$origin = substr($folderid, 0, 1);
switch ($origin) {
case DeviceManager::FLD_ORIGIN_CONFIG:
case DeviceManager::FLD_ORIGIN_GAB:
case DeviceManager::FLD_ORIGIN_SHARED:
case DeviceManager::FLD_ORIGIN_USER:
return $origin;
}
ZLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginFromId(): Unknown folder origin for folder with id '%s'", $folderid));
return false;
}
/**
* Returns folder origin as string from its id.
*
* @param string $folderid
*
* @access public
* @return string
*/
public static function GetFolderOriginFromId($fid) {
$origin = substr($fid, 0, 1);
public static function GetFolderOriginStringFromId($folderid) {
$origin = substr($folderid, 0, 1);
switch ($origin) {
case DeviceManager::FLD_ORIGIN_CONFIG:
return 'configured';
......@@ -1111,7 +1132,7 @@ class Utils {
case DeviceManager::FLD_ORIGIN_USER:
return 'user';
}
ZLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginFromId(): Unknown folder origin for folder with id '%s'", $fid));
ZLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginStringFromId(): Unknown folder origin for folder with id '%s'", $folderid));
return 'unknown';
}
......@@ -1130,6 +1151,38 @@ class Utils {
}
return array(null, $id);
}
/**
* Detects encoding of the input and converts it to UTF-8.
* This is currently only used for authorization header conversion.
*
* @param string $data input data
*
* @access public
* @return string utf-8 encoded data
*/
public static function ConvertAuthorizationToUTF8($data) {
$encoding = mb_detect_encoding($data, "UTF-8, ISO-8859-1");
if (!$encoding) {
$encoding = mb_detect_encoding($data, Utils::GetAvailableCharacterEncodings());
if ($encoding) {
ZLog::Write(LOGLEVEL_WARN,
sprintf("Utils::ConvertAuthorizationToUTF8(): mb_detect_encoding detected '%s' charset. This charset is not in the default detect list. Please report it to Z-Push developers.",
$encoding));
}
else {
ZLog::Write(LOGLEVEL_ERROR, "Utils::ConvertAuthorizationToUTF8(): mb_detect_encoding failed to detect the Authorization header charset. It's possible that user won't be able to login.");
}
}
if ($encoding && strtolower($encoding) != "utf-8") {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Utils::ConvertAuthorizationToUTF8(): mb_detect_encoding detected '%s' charset. Authorization header will be converted to UTF-8 from it.", $encoding));
return mb_convert_encoding($data, "UTF-8", $encoding);
}
return $data;
}
}
......
......@@ -113,6 +113,10 @@ class ZPushAdmin {
ZLog::Write(LOGLEVEL_WARN, sprintf("ZPushAdmin::GetDeviceDetails(): device '%s' of user '%s' has invalid states. Please sync to solve this issue.", $devid, $user));
$device->SetDeviceError("Invalid states. Please force synchronization!");
}
catch (StatusException $ste) {
ZLog::Write(LOGLEVEL_WARN, sprintf("ZPushAdmin::GetDeviceDetails(): device '%s' of user '%s' has status exceptions. Please sync to solve this issue.", $devid, $user));
$device->SetDeviceError("State exceptions. Please force synchronization or remove device to fix!");
}
if ($sc) {
if ($sc->GetLastSyncTime())
......@@ -121,6 +125,9 @@ class ZPushAdmin {
// get information about the folder synchronization status from SyncCollections
$folders = $device->GetAllFolderIds();
// indicate short folderids
$device->hasFolderIdMapping = $device->HasFolderIdMapping();
foreach ($folders as $folderid) {
$fstatus = $device->GetFolderSyncStatus($folderid);
......@@ -493,7 +500,7 @@ class ZPushAdmin {
foreach ($device->GetAdditionalFolders() as $folder) {
$syncfolderid = $device->GetFolderIdForBackendId($folder['folderid'], false, false, null);
$folder['syncfolderid'] = $syncfolderid;
$folder['origin'] = Utils::GetFolderOriginFromId($syncfolderid);
$folder['origin'] = Utils::GetFolderOriginStringFromId($syncfolderid);
$new_list[$folder['folderid']] = $folder;
}
foreach (ZPush::GetAdditionalSyncFolders() as $fid => $so) {
......@@ -506,7 +513,7 @@ class ZPushAdmin {
'syncfolderid' => $syncfolderid,
'name' => $so->displayname,
'type' => $so->type,
'origin' => Utils::GetFolderOriginFromId($syncfolderid),
'origin' => Utils::GetFolderOriginStringFromId($syncfolderid),
'flags' => 0, // static folders have no flags
);
}
......
......@@ -62,7 +62,7 @@ class Webservice {
ZLog::Write(LOGLEVEL_INFO, sprintf("Webservice::HandleWebservice('%s'): user '%s' executing action for user '%s'", $commandCode, Request::GetAuthUser(), Request::GetGETUser()));
// initialize non-wsdl soap server
$this->server = new SoapServer(null, array('uri' => "http://z-push.sf.net/webservice"));
$this->server = new SoapServer(null, array('uri' => "http://z-push.org/webservice"));
// the webservice command is handled by its class
if ($commandCode == ZPush::COMMAND_WEBSERVICE_DEVICE) {
......
#!/usr/bin/env php
<?php
/**********************************************************
* File : list-shared-folders.php
* Project : Z-Push - tools
* Descr : Lists all users and devices that have open additional folders
*
* Created : 20.10.2016
*
* Copyright 2007 - 2016 Zarafa Deutschland GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation with the following additional
* term according to sec. 7:
*
* According to sec. 7 of the GNU Affero General Public License, version 3,
* the terms of the AGPL are supplemented with the following terms:
*
* "Zarafa" is a registered trademark of Zarafa B.V.
* "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
* The licensing of the Program under the AGPL does not imply a trademark license.
* Therefore any rights, title and interest in our trademarks remain entirely with us.
*
* However, if you propagate an unmodified version of the Program you are
* allowed to use the term "Z-Push" to indicate that you distribute the Program.
* Furthermore you may use our trademarks where it is necessary to indicate
* the intended purpose of a product or service provided you use it in accordance
* with honest practices in industrial or commercial matters.
* If you want to propagate modified versions of the Program under the name "Z-Push",
* you may only do so if you have a written permission by Zarafa Deutschland GmbH
* (to acquire a permission please contact Zarafa at trademark@zarafa.com).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Consult LICENSE file for details
************************************************/
// Please adjust to match your z-push installation directory, usually /usr/share/z-push
define('ZPUSH_BASE_PATH', "/usr/share/z-push");
/**
* Usage:
* php list-shared-folders.php
* List all shared folders for all devices
*
* php list-shared-folders.php | awk -F',' '$6 == "13" && $7 != ""'
* List all shared folders of type calendar (13) that are synchronized on a device (else SyncUUID is empty)
*
* php list-shared-folders.php | awk -F',' '$6 == "13" && $7 != "" { system("z-push-admin -a resync -d " $1 " -u " $2 " -t " $5) }'
* Resynchronizes all shared folders from type calendar (13) that are synchronized already
*/
/************************************************
* MAIN
*/
try {
if (php_sapi_name() != "cli") {
fwrite(STDERR, "This script can only be called from the CLI.\n");
exit(1);
}
if (!defined('ZPUSH_BASE_PATH') || !file_exists(ZPUSH_BASE_PATH . "/config.php")) {
die("ZPUSH_BASE_PATH not set correctly or no config.php file found\n");
}
define('BASE_PATH_CLI', ZPUSH_BASE_PATH ."/");
set_include_path(get_include_path() . PATH_SEPARATOR . ZPUSH_BASE_PATH);
require_once 'vendor/autoload.php';
if (!defined('ZPUSH_CONFIG')) define('ZPUSH_CONFIG', 'config.php');
include_once(ZPUSH_CONFIG);
ZPush::CheckConfig();
$sm = ZPush::GetStateMachine();
$devices = $sm->GetAllDevices();
if (!empty($devices)) {
printf("%s,%s,%s,%s,%s,%s,%s,%s\n", "DeviceId", "User", "Store", "SyncFolderId", "FolderId", "Type", "SyncUUID", "Name");
}
foreach ($devices as $devid) {
$users = ZPushAdmin::ListUsers($devid);
foreach($users as $user) {
$device = ZPushAdmin::GetDeviceDetails($devid, $user);
foreach ($device->GetAdditionalFolders() as $folder) {
$syncfolderid = $device->GetFolderIdForBackendId($folder['folderid'], false, false, null);
if(Utils::GetFolderOriginFromId($syncfolderid) !== DeviceManager::FLD_ORIGIN_SHARED) {
continue;
}
$syncfolder = $device->GetHierarchyCache()->GetFolder($syncfolderid);
// if there is no syncfolder then this folder was not synchronized to the client (e.g. no permissions)
if (!$syncfolder) {
continue;
}
$folderUuid = $device->GetFolderUUID($syncfolderid);
printf("%s,%s,%s,%s,%s,%d,%s,%s\n", $devid, $user, $syncfolder->Store, $syncfolderid, $folder['folderid'], $syncfolder->type, $folderUuid, $syncfolder->displayname);
}
}
}
}
catch (ZPushException $zpe) {
fwrite(STDERR, get_class($zpe) . ": ". $zpe->getMessage() . "\n");
exit(1);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment