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 ...@@ -8,7 +8,7 @@ Homepage: http://z-push.org
Package: z-push-common Package: z-push-common
Architecture: all 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 Conflicts: d-push, z-push
Replaces: d-push, z-push Replaces: d-push, z-push
Description: open source implementation of the ActiveSync protocol Description: open source implementation of the ActiveSync protocol
...@@ -26,7 +26,7 @@ Description: Z-Push caldav backend ...@@ -26,7 +26,7 @@ Description: Z-Push caldav backend
Package: z-push-backend-carddav Package: z-push-backend-carddav
Architecture: all 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 Description: Z-Push carddav backend
Backend for Z-Push, that adds the ability to connect to a carddav server Backend for Z-Push, that adds the ability to connect to a carddav server
......
...@@ -25,7 +25,7 @@ The specification suggests several ways for client to contact the responsible ...@@ -25,7 +25,7 @@ The specification suggests several ways for client to contact the responsible
server to receive additional information. Tests have shown, that basically all server to receive additional information. Tests have shown, that basically all
mobile phones tested support only the most basic ways. These are sufficient for mobile phones tested support only the most basic ways. These are sufficient for
almost all types of scenarios and are the ones implemented by Z-Push AutoDiscover. almost all types of scenarios and are the ones implemented by Z-Push AutoDiscover.
Please refer to the Mobile Compatibility List (http://z-push.sf.net/compatibility) Please refer to the Mobile Compatibility List (http://z-push.org/compatibility)
for an overview of supported and tested devices. for an overview of supported and tested devices.
The used email address is the key for the process. The client splits it up into The used email address is the key for the process. The client splits it up into
the local and domain part (before and after the @-sign). The client then tries the local and domain part (before and after the @-sign). The client then tries
......
...@@ -104,9 +104,24 @@ class ZPushAutodiscover { ...@@ -104,9 +104,24 @@ class ZPushAutodiscover {
} }
} }
catch (AuthenticationRequiredException $ex) { 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());
}
ZLog::Write(LOGLEVEL_FATAL, sprintf('Exception: (%s) - %s', $exclass, $exception_message));
if ($ex instanceof AuthenticationRequiredException) {
if (isset($incomingXml)) { if (isset($incomingXml)) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover because login failed for user with email '%s'", $incomingXml->Request->EMailAddress)); // 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 { else {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover incorrect request: '%s'", $ex->getMessage())); ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover incorrect request: '%s'", $ex->getMessage()));
...@@ -114,7 +129,7 @@ class ZPushAutodiscover { ...@@ -114,7 +129,7 @@ class ZPushAutodiscover {
http_response_code(401); http_response_code(401);
header('WWW-Authenticate: Basic realm="ZPush"'); header('WWW-Authenticate: Basic realm="ZPush"');
} }
catch (ZPushException $ex) { else if ($ex instanceof ZPushException) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover because of ZPushException. Error: %s", $ex->getMessage())); ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover because of ZPushException. Error: %s", $ex->getMessage()));
if(!headers_sent()) { if(!headers_sent()) {
header('HTTP/1.1 '. $ex->getHTTPCodeString()); header('HTTP/1.1 '. $ex->getHTTPCodeString());
...@@ -123,6 +138,8 @@ class ZPushAutodiscover { ...@@ -123,6 +138,8 @@ class ZPushAutodiscover {
} }
} }
} }
}
$this->sendResponse($response); $this->sendResponse($response);
} }
...@@ -182,21 +199,32 @@ class ZPushAutodiscover { ...@@ -182,21 +199,32 @@ class ZPushAutodiscover {
* @return string $username * @return string $username
*/ */
private function login($backend, $incomingXml) { 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 // Determine the login name depending on the configuration: complete email address or
// the local part only. // the local part only.
if (USE_FULLEMAIL_FOR_LOGIN) { if (USE_FULLEMAIL_FOR_LOGIN) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Using the complete email address for login."));
$username = $incomingXml->Request->EMailAddress; $username = $incomingXml->Request->EMailAddress;
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Using the complete email address for login: '%s'", $username));
} }
else{ else {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Using the username only for login."));
$username = Utils::GetLocalPartFromEmail($incomingXml->Request->EMailAddress); $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."); 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; return $username;
} }
......
...@@ -131,6 +131,15 @@ class PHPWrapper { ...@@ -131,6 +131,15 @@ class PHPWrapper {
$mapimessage = mapi_msgstore_openentry($this->store, $entryid); $mapimessage = mapi_msgstore_openentry($this->store, $entryid);
try { try {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("PHPWrapper->ImportMessageChange(): Getting message from MAPIProvider, sourcekey: '%s', parentsourcekey: '%s', entryid: '%s'", bin2hex($sourcekey), bin2hex($parentsourcekey), bin2hex($entryid))); 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); $message = $this->mapiprovider->GetMessage($mapimessage, $this->contentparameters);
} }
catch (SyncObjectBrokenException $mbe) { catch (SyncObjectBrokenException $mbe) {
......
...@@ -748,6 +748,12 @@ class MAPIProvider { ...@@ -748,6 +748,12 @@ class MAPIProvider {
// android devices require attachment size in order to display an attachment properly // android devices require attachment size in order to display an attachment properly
if (!isset($attachprops[PR_ATTACH_SIZE])) { if (!isset($attachprops[PR_ATTACH_SIZE])) {
$stream = mapi_openpropertytostream($mapiattach, PR_ATTACH_DATA_BIN); $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); $stat = mapi_stream_stat($stream);
$attach->estimatedDataSize = $stat['cb']; $attach->estimatedDataSize = $stat['cb'];
} }
......
...@@ -270,6 +270,24 @@ class ReplyBackImExporter implements IImportChanges, IExportChanges { ...@@ -270,6 +270,24 @@ class ReplyBackImExporter implements IImportChanges, IExportChanges {
* @return boolean * @return boolean
*/ */
public function ImportMessageChange($id, $message) { 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 // data is going to be dropped, inform the user
if (@constant('READ_ONLY_NOTIFY_LOST_DATA')) { if (@constant('READ_ONLY_NOTIFY_LOST_DATA')) {
try { try {
......
...@@ -143,7 +143,7 @@ class SqlStateMachine implements IStateMachine { ...@@ -143,7 +143,7 @@ class SqlStateMachine implements IStateMachine {
* *
* @access public * @access public
* @return string * @return string
* @throws StateNotFoundException, StateInvalidException * @throws StateNotFoundException, StateInvalidException, UnavailableException
*/ */
public function GetStateHash($devid, $type, $key = null, $counter = false) { public function GetStateHash($devid, $type, $key = null, $counter = false) {
$hash = null; $hash = null;
...@@ -155,8 +155,12 @@ class SqlStateMachine implements IStateMachine { ...@@ -155,8 +155,12 @@ class SqlStateMachine implements IStateMachine {
$record = $sth->fetch(PDO::FETCH_ASSOC); $record = $sth->fetch(PDO::FETCH_ASSOC);
if (!$record) { if (!$record) {
$errCode = $sth->errorCode();
$this->clearConnection($this->dbh, $sth, $record); $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 { else {
// datetime->format("U") returns EPOCH // datetime->format("U") returns EPOCH
......
...@@ -1001,6 +1001,13 @@ class DeviceManager { ...@@ -1001,6 +1001,13 @@ class DeviceManager {
catch (StateNotFoundException $snfex) { catch (StateNotFoundException $snfex) {
$this->hierarchySyncRequired = true; $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; return true;
} }
......
...@@ -92,7 +92,7 @@ class FileStateMachine implements IStateMachine { ...@@ -92,7 +92,7 @@ class FileStateMachine implements IStateMachine {
* *
* @access public * @access public
* @return string * @return string
* @throws StateNotFoundException, StateInvalidException * @throws StateNotFoundException, StateInvalidException, UnavailableException
*/ */
public function GetStateHash($devid, $type, $key = false, $counter = false) { public function GetStateHash($devid, $type, $key = false, $counter = false) {
$filename = $this->getFullFilePath($devid, $type, $key, $counter); $filename = $this->getFullFilePath($devid, $type, $key, $counter);
......
...@@ -82,7 +82,7 @@ interface IStateMachine { ...@@ -82,7 +82,7 @@ interface IStateMachine {
* *
* @access public * @access public
* @return string * @return string
* @throws StateNotFoundException, StateInvalidException * @throws StateNotFoundException, StateInvalidException, UnavailableException
*/ */
public function GetStateHash($devid, $type, $key = false, $counter = false); public function GetStateHash($devid, $type, $key = false, $counter = false);
......
...@@ -86,7 +86,11 @@ class MoveItems extends RequestProcessor { ...@@ -86,7 +86,11 @@ class MoveItems extends RequestProcessor {
self::$encoder->startTag(SYNC_MOVE_MOVES); self::$encoder->startTag(SYNC_MOVE_MOVES);
$operationResults = array();
$operationCounter = 0;
$operationTotal = count($moves);
foreach($moves as $move) { foreach($moves as $move) {
$operationCounter++;
self::$encoder->startTag(SYNC_MOVE_RESPONSE); self::$encoder->startTag(SYNC_MOVE_RESPONSE);
self::$encoder->startTag(SYNC_MOVE_SRCMSGID); self::$encoder->startTag(SYNC_MOVE_SRCMSGID);
self::$encoder->content($move["srcmsgid"]); self::$encoder->content($move["srcmsgid"]);
...@@ -141,7 +145,15 @@ class MoveItems extends RequestProcessor { ...@@ -141,7 +145,15 @@ class MoveItems extends RequestProcessor {
$status = $stex->getCode(); $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->startTag(SYNC_MOVE_STATUS);
self::$encoder->content($status); self::$encoder->content($status);
...@@ -153,6 +165,12 @@ class MoveItems extends RequestProcessor { ...@@ -153,6 +165,12 @@ class MoveItems extends RequestProcessor {
self::$encoder->endTag(); 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(); self::$encoder->endTag();
return true; return true;
} }
......
...@@ -254,25 +254,10 @@ class Request { ...@@ -254,25 +254,10 @@ class Request {
// Mobile devices send Authorization header using UTF-8 charset. Outlook sends it using ISO-8859-1 encoding. // 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 // 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. // 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'])) { if (isset(self::$authUser))
$encoding = mb_detect_encoding(self::$authUser, "UTF-8, ISO-8859-1"); self::$authUser = Utils::ConvertAuthorizationToUTF8(self::$authUser);
if (!$encoding) { if (isset(self::$authPassword))
$encoding = mb_detect_encoding(self::$authUser, Utils::GetAvailableCharacterEncodings()); self::$authPassword = Utils::ConvertAuthorizationToUTF8(self::$authPassword);
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);
}
}
} }
/** /**
......
...@@ -1092,15 +1092,36 @@ class Utils { ...@@ -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 * @access public
* @return string * @return string
*/ */
public static function GetFolderOriginFromId($fid) { public static function GetFolderOriginStringFromId($folderid) {
$origin = substr($fid, 0, 1); $origin = substr($folderid, 0, 1);
switch ($origin) { switch ($origin) {
case DeviceManager::FLD_ORIGIN_CONFIG: case DeviceManager::FLD_ORIGIN_CONFIG:
return 'configured'; return 'configured';
...@@ -1111,7 +1132,7 @@ class Utils { ...@@ -1111,7 +1132,7 @@ class Utils {
case DeviceManager::FLD_ORIGIN_USER: case DeviceManager::FLD_ORIGIN_USER:
return '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'; return 'unknown';
} }
...@@ -1130,6 +1151,38 @@ class Utils { ...@@ -1130,6 +1151,38 @@ class Utils {
} }
return array(null, $id); 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 { ...@@ -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)); 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!"); $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) {
if ($sc->GetLastSyncTime()) if ($sc->GetLastSyncTime())
...@@ -121,6 +125,9 @@ class ZPushAdmin { ...@@ -121,6 +125,9 @@ class ZPushAdmin {
// get information about the folder synchronization status from SyncCollections // get information about the folder synchronization status from SyncCollections
$folders = $device->GetAllFolderIds(); $folders = $device->GetAllFolderIds();
// indicate short folderids
$device->hasFolderIdMapping = $device->HasFolderIdMapping();
foreach ($folders as $folderid) { foreach ($folders as $folderid) {
$fstatus = $device->GetFolderSyncStatus($folderid); $fstatus = $device->GetFolderSyncStatus($folderid);
...@@ -493,7 +500,7 @@ class ZPushAdmin { ...@@ -493,7 +500,7 @@ class ZPushAdmin {
foreach ($device->GetAdditionalFolders() as $folder) { foreach ($device->GetAdditionalFolders() as $folder) {
$syncfolderid = $device->GetFolderIdForBackendId($folder['folderid'], false, false, null); $syncfolderid = $device->GetFolderIdForBackendId($folder['folderid'], false, false, null);
$folder['syncfolderid'] = $syncfolderid; $folder['syncfolderid'] = $syncfolderid;
$folder['origin'] = Utils::GetFolderOriginFromId($syncfolderid); $folder['origin'] = Utils::GetFolderOriginStringFromId($syncfolderid);
$new_list[$folder['folderid']] = $folder; $new_list[$folder['folderid']] = $folder;
} }
foreach (ZPush::GetAdditionalSyncFolders() as $fid => $so) { foreach (ZPush::GetAdditionalSyncFolders() as $fid => $so) {
...@@ -506,7 +513,7 @@ class ZPushAdmin { ...@@ -506,7 +513,7 @@ class ZPushAdmin {
'syncfolderid' => $syncfolderid, 'syncfolderid' => $syncfolderid,
'name' => $so->displayname, 'name' => $so->displayname,
'type' => $so->type, 'type' => $so->type,
'origin' => Utils::GetFolderOriginFromId($syncfolderid), 'origin' => Utils::GetFolderOriginStringFromId($syncfolderid),
'flags' => 0, // static folders have no flags 'flags' => 0, // static folders have no flags
); );
} }
......
...@@ -62,7 +62,7 @@ class Webservice { ...@@ -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())); 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 // 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 // the webservice command is handled by its class
if ($commandCode == ZPush::COMMAND_WEBSERVICE_DEVICE) { 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