Commit 2ec6d9b5 authored by Manfred Kutas's avatar Manfred Kutas

Merge pull request #194 in ZP/z-push from release/2.2 to master

* commit 'e45b2627':
  ZP-854 Bumped version to 2.2.10.
  ZP-854 Bumped to 2.2.10 beta1.
  ZP-854 Bumped version. Fixed line endings.
  Merge pull request #180 in ZP/z-push from bugfix/ZP-861-user-with-umlauts-in-user-name-is to develop
  Merge pull request #181 in ZP/z-push from feature/ZP-844-support-out-of-office-start-and-end to develop
  Merge pull request #179 in ZP/z-push from feature/ZP-844-support-out-of-office-start-and-end to develop
  ZP-854 Bumped version. Fixed line endings.
  Merge pull request #156 in ZP/z-push from bugfix/ZP-794-use-safeputcontents-to-ensure-atomacy-2 to develop
  Merge pull request #108 in ZP/z-push from feature/ZP-794-safe_put_contents to develop
  Merge pull request #178 in ZP/z-push from bugfix/ZP-860-show-z-push-version-in-autodiscover to develop
  Merge pull request #159 in ZP/z-push from bugfix/ZP-845-improve-utils-fixfileowner to develop
  Merge pull request #177 in ZP/z-push from bugfix/ZP-842-outlook-via-as-does-not-synchronize to develop
  Merge pull request #176 in ZP/z-push from feature/ZP-844-support-out-of-office-start-and-end to develop
parents a2eef6ce e45b2627
......@@ -73,6 +73,7 @@ class ZPushAutodiscover {
*/
public static function DoZPushAutodiscover() {
ZLog::Write(LOGLEVEL_DEBUG, '-------- Start ZPushAutodiscover');
ZLog::Write(LOGLEVEL_INFO, sprintf("Z-Push version='%s'", @constant('ZPUSH_VERSION')));
// TODO use filterevilinput?
if (stripos($_SERVER["REQUEST_METHOD"], "GET") !== false) {
ZLog::Write(LOGLEVEL_WARN, "GET request for autodiscover. Exiting.");
......
......@@ -1135,6 +1135,8 @@ define('PR_EC_BASE' , 0x6700);
define('PR_EC_OUTOFOFFICE' ,mapi_prop_tag(PT_BOOLEAN, PR_EC_BASE+0x60));
define('PR_EC_OUTOFOFFICE_MSG' ,mapi_prop_tag(PT_STRING8, PR_EC_BASE+0x61));
define('PR_EC_OUTOFOFFICE_SUBJECT' ,mapi_prop_tag(PT_STRING8, PR_EC_BASE+0x62));
define('PR_EC_OUTOFOFFICE_FROM', mapi_prop_tag(PT_SYSTIME, PR_EC_BASE+0x63));
define('PR_EC_OUTOFOFFICE_UNTIL', mapi_prop_tag(PT_SYSTIME, PR_EC_BASE+0x64));
/* quota support */
define('PR_QUOTA_WARNING_THRESHOLD' ,mapi_prop_tag(PT_LONG, PR_EC_BASE+0x21));
......
......@@ -418,8 +418,6 @@ class MAPIUtils {
if (isset($supportmask[PR_STORE_SUPPORT_MASK]) && ($supportmask[PR_STORE_SUPPORT_MASK] & STORE_UNICODE_OK)) {
ZLog::Write(LOGLEVEL_DEBUG, "Store supports properties containing Unicode characters.");
define('STORE_SUPPORTS_UNICODE', true);
//setlocale to UTF-8 in order to support properties containing Unicode characters
setlocale(LC_CTYPE, "en_US.UTF-8");
define('STORE_INTERNET_CPID', INTERNET_CPID_UTF8);
}
}
......
......@@ -75,6 +75,8 @@ include_once('backend/zarafa/mapistreamwrapper.php');
include_once('backend/zarafa/importer.php');
include_once('backend/zarafa/exporter.php');
//setlocale to UTF-8 in order to support properties containing Unicode characters
setlocale(LC_CTYPE, "en_US.UTF-8");
class BackendZarafa implements IBackend, ISearchProvider {
private $mainUser;
......@@ -1372,10 +1374,10 @@ class BackendZarafa implements IBackend, ISearchProvider {
private function settingsOOF(&$oof) {
//if oof state is set it must be set of oof and get otherwise
if (isset($oof->oofstate)) {
$this->settingsOOFSEt($oof);
$this->settingsOofSet($oof);
}
else {
$this->settingsOOFGEt($oof);
$this->settingsOofGet($oof);
}
}
......@@ -1387,8 +1389,8 @@ class BackendZarafa implements IBackend, ISearchProvider {
* @access private
* @return void
*/
private function settingsOOFGEt(&$oof) {
$oofprops = mapi_getprops($this->defaultstore, array(PR_EC_OUTOFOFFICE, PR_EC_OUTOFOFFICE_MSG, PR_EC_OUTOFOFFICE_SUBJECT));
private function settingsOofGet(&$oof) {
$oofprops = mapi_getprops($this->defaultstore, array(PR_EC_OUTOFOFFICE, PR_EC_OUTOFOFFICE_MSG, PR_EC_OUTOFOFFICE_SUBJECT, PR_EC_OUTOFOFFICE_FROM, PR_EC_OUTOFOFFICE_UNTIL));
$oof->oofstate = SYNC_SETTINGSOOF_DISABLED;
$oof->Status = SYNC_SETTINGSSTATUS_SUCCESS;
if ($oofprops != false) {
......@@ -1401,6 +1403,26 @@ class BackendZarafa implements IBackend, ISearchProvider {
$oofmessage->bodytype = $oof->bodytype;
unset($oofmessage->appliesToExternal, $oofmessage->appliesToExternalUnknown);
$oof->oofmessage[] = $oofmessage;
// check whether time based out of office is set
if ($oof->oofstate == SYNC_SETTINGSOOF_GLOBAL && isset($oofprops[PR_EC_OUTOFOFFICE_FROM]) && isset($oofprops[PR_EC_OUTOFOFFICE_UNTIL])) {
if ($oofprops[PR_EC_OUTOFOFFICE_FROM] < $oofprops[PR_EC_OUTOFOFFICE_UNTIL]) {
$oof->oofstate = SYNC_SETTINGSOOF_TIMEBASED;
$oof->starttime = $oofprops[PR_EC_OUTOFOFFICE_FROM];
$oof->endtime = $oofprops[PR_EC_OUTOFOFFICE_UNTIL];
}
else {
ZLog::Write(LOGLEVEL_WARN, sprintf("Zarafa->settingsOofGet(): Time based out of office set but end time ('%s') is before startime ('%s').",
date("Y-m-d H:i:s", $oofprops[PR_EC_OUTOFOFFICE_FROM]), date("Y-m-d H:i:s", $oofprops[PR_EC_OUTOFOFFICE_UNTIL])));
$oof->Status = SYNC_SETTINGSSTATUS_PROTOCOLLERROR;
}
}
elseif ($oof->oofstate == SYNC_SETTINGSOOF_GLOBAL && (isset($oofprops[PR_EC_OUTOFOFFICE_FROM]) || isset($oofprops[PR_EC_OUTOFOFFICE_UNTIL]))) {
ZLog::Write(LOGLEVEL_WARN, sprintf("Zarafa->settingsOofGet(): Time based out of office set but either start time ('%s') or end time ('%s') is missing.",
(isset($oofprops[PR_EC_OUTOFOFFICE_FROM]) ? date("Y-m-d H:i:s", $oofprops[PR_EC_OUTOFOFFICE_FROM]) : 'empty'),
(isset($oofprops[PR_EC_OUTOFOFFICE_UNTIL]) ? date("Y-m-d H:i:s", $oofprops[PR_EC_OUTOFOFFICE_UNTIL]) : 'empty')));
$oof->Status = SYNC_SETTINGSSTATUS_PROTOCOLLERROR;
}
}
else {
ZLog::Write(LOGLEVEL_WARN, "Unable to get out of office information");
......@@ -1418,7 +1440,7 @@ class BackendZarafa implements IBackend, ISearchProvider {
* @access private
* @return void
*/
private function settingsOOFSEt(&$oof) {
private function settingsOofSet(&$oof) {
$oof->Status = SYNC_SETTINGSSTATUS_SUCCESS;
$props = array();
if ($oof->oofstate == SYNC_SETTINGSOOF_GLOBAL || $oof->oofstate == SYNC_SETTINGSOOF_TIMEBASED) {
......@@ -1429,9 +1451,22 @@ class BackendZarafa implements IBackend, ISearchProvider {
$props[PR_EC_OUTOFOFFICE_SUBJECT] = "Out of office";
}
}
if ($oof->oofstate == SYNC_SETTINGSOOF_TIMEBASED) {
if(isset($oof->starttime) && isset($oof->endtime)) {
$props[PR_EC_OUTOFOFFICE_FROM] = $oof->starttime;
$props[PR_EC_OUTOFOFFICE_UNTIL] = $oof->endtime;
}
elseif (isset($oof->starttime) || isset($oof->endtime)) {
$oof->Status = SYNC_SETTINGSSTATUS_PROTOCOLLERROR;
}
}
else {
$deleteProps = array(PR_EC_OUTOFOFFICE_FROM, PR_EC_OUTOFOFFICE_UNTIL);
}
}
elseif($oof->oofstate == SYNC_SETTINGSOOF_DISABLED) {
$props[PR_EC_OUTOFOFFICE] = false;
$deleteProps = array(PR_EC_OUTOFOFFICE_FROM, PR_EC_OUTOFOFFICE_UNTIL);
}
if (!empty($props)) {
......@@ -1443,6 +1478,10 @@ class BackendZarafa implements IBackend, ISearchProvider {
}
}
if (!empty($deleteProps)) {
@mapi_deleteprops($this->defaultstore, $deleteProps);
}
return true;
}
......
......@@ -228,6 +228,12 @@ class ChangesMemoryWrapper extends HierarchyCache implements IImportChanges, IEx
return false;
}
// check if the parent ID is known on the device
if (!isset($folder->parentid) || $folder->parentid != "0" && !$this->GetFolder($folder->parentid)) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ChangesMemoryWrapper->ImportFolderChange(): Change for folder '%s' will not be sent as parent folder is not set or not known on mobile.", $folder->displayname));
return false;
}
// load this change into memory
$this->changes[] = array(self::CHANGE, $folder);
......
......@@ -154,7 +154,7 @@ class FileStateMachine implements IStateMachine {
$state = serialize($state);
$filename = $this->getFullFilePath($devid, $type, $key, $counter);
if (($bytes = file_put_contents($filename, $state)) === false)
if (($bytes = Utils::SafePutContents($filename, $state)) === false)
throw new FatalMisconfigurationException(sprintf("FileStateMachine->SetState(): Could not write state '%s'",$filename));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("FileStateMachine->SetState() written %d bytes on file: '%s'", $bytes, $filename));
......@@ -244,7 +244,7 @@ class FileStateMachine implements IStateMachine {
}
if ($changed) {
$bytes = file_put_contents($this->userfilename, serialize($users));
$bytes = Utils::SafePutContents($this->userfilename, serialize($users));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("FileStateMachine->LinkUserDevice(): wrote %d bytes to users file", $bytes));
}
else
......@@ -293,7 +293,7 @@ class FileStateMachine implements IStateMachine {
}
if ($changed) {
$bytes = file_put_contents($this->userfilename, serialize($users));
$bytes = Utils::SafePutContents($this->userfilename, serialize($users));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("FileStateMachine->UnLinkUserDevice(): wrote %d bytes to users file", $bytes));
}
else
......@@ -381,8 +381,7 @@ class FileStateMachine implements IStateMachine {
$settings[self::VERSION] = $version;
ZLog::Write(LOGLEVEL_INFO, sprintf("FileStateMachine->SetStateVersion() saving supported state version, value '%d'", $version));
$status = file_put_contents($this->settingsfilename, serialize($settings));
Utils::FixFileOwner($this->settingsfilename);
$status = Utils::SafePutContents($this->settingsfilename, serialize($settings));
return $status;
}
......
......@@ -886,11 +886,16 @@ class Utils {
if(posix_getuid() == 0 && file_exists($file)) {
$dir = dirname($file);
$perm_dir = stat($dir);
$perm_log = stat($file);
$perm_file = stat($file);
if($perm_dir[4] !== $perm_log[4] || $perm_dir[5] !== $perm_log[5]) {
chown($file, $perm_dir[4]);
chgrp($file, $perm_dir[5]);
if ($perm_file['uid'] == 0 && $perm_dir['uid'] == 0) {
unlink($file);
throw new FatalException("FixFileOwner: $dir must be owned by the nginx/apache/php user instead of root");
}
if($perm_dir['uid'] !== $perm_file['uid'] || $perm_dir['gid'] !== $perm_file['gid']) {
chown($file, $perm_dir['uid']);
chgrp($file, $perm_dir['gid']);
}
}
return true;
......@@ -947,6 +952,30 @@ class Utils {
$pow = pow(1024, $base - $fBase);
return sprintf ("%.{$precision}f %s", $pow, $units[$fBase]);
}
/**
* Safely write data to disk, using an unique tmp file (concurrent write),
* and using rename for atomicity. It also calls FixFileOwner to prevent
* ownership/rights problems when running as root
*
* If you use SafePutContents, you can safely use file_get_contents
* (you will always read a fully written file)
*
* @param string $filename
* @param string $data
* @return boolean|int
*/
public static function SafePutContents($filename, $data) {
//put the 'tmp' as a prefix (and not suffix) so all glob call will not see temp files
$tmp = dirname($filename).DIRECTORY_SEPARATOR.'tmp-'.getmypid().'-'.basename($filename);
if (($res = file_put_contents($tmp, $data)) !== false) {
self::FixFileOwner($tmp);
if (rename($tmp, $filename) !== true)
$res = false;
}
return $res;
}
}
......
......@@ -41,6 +41,6 @@
* Consult LICENSE file for details
************************************************/
define("ZPUSH_VERSION", "2.2.9");
define("ZPUSH_VERSION", "2.2.10");
?>
\ No newline at end of file
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