Commit a2376402 authored by Sebastian Kummer's avatar Sebastian Kummer

Merging in latest from upstream (ZP/z-push:refs/heads/develop)

* commit '6a7a9763': (45 commits)
  ZP-824 Remove local $sc as it is not needed.
  ZP-825 Rename ReplaceNullCharFilter classname, register filter in WBXMLEncoder before it is being used.
  ZP-824 Invalidate all pingable flags on folders when doing a FolderSync (with changes) or FolderChange (Create, Update, Delete) operation.
  ZP-707 Remove debug.
  ZP-707 use MAPIStreamWrapper where possible.
  ZP-823 Remove empty line.
  ZP-823 Do not sync suggested contacts folder.
  ZP-708 Wrap the plaintext body, html body or mime message into a StringStreamWrapper. While the wrapper correctly truncates (UTF-8 compatible), we can also truncate before loading the data in.
  ZP-817 Set task as private if sensitivity is private or greater.
  ZP-808 Set appointment as private if sensitivity is private or greater.
  ZP-781 Use comma as decimal and dot as thousand separators, add 's' as unit for time usage.
  ZP-781 Nicer format for memory usage.
  ZP-817 Unsetting private task in Outlook is not saved on the server.
  ZP-793 Cache requested folderid so only the SyncCollections get changed that really had a change in flags.
  ZP-817 Sensitivity (private) of tasks is not saved on the server.
  ZP-766 Accept outlook response schema on autodiscover, send XML response only for mobile response schema or empty otherwise.
  ZP-641 Make sure CleanStates does not touch permanent backend storage files, unless we really want to delete them.
  ZP-641 Revert "For Backend Storage type files, add a user element to the file name so that multiple accounts on the same device do not overwrite each others data in a single file named only for the device."
  ZP-682 Compare the configured LOGBACKEND lowercase.
  ZP-682 "filelog" and "syslog" classes can not be found by autoloader (because they are in camel case and not lowercase). Rewriting the backend loaded by ZLog to the class name, as this is more end-user friendly. Throwing a FatalNotImplementedException causes a recursion that eats up all available memory before it fails, as that exception tries to log which then throws the exception again.
  ...
parents 350c7a88 6a7a9763
......@@ -5,6 +5,6 @@
"homepage": "http://z-push.org/",
"license": "AGPL-3.0",
"require": {
"php": ">=5.2.0"
"php": ">=5.4.0"
}
}
composer.phar
After creating a new file or removing an existing one you must refresh the autoload code.
curl -sS https://getcomposer.org/installer | php
php composer.phar dump-autoload -o
......@@ -41,24 +41,12 @@
* Consult LICENSE file for details
************************************************/
include_once('../lib/core/zpushdefs.php');
include_once('../lib/exceptions/exceptions.php');
include_once('../lib/utils/compat.php');
include_once('../lib/utils/utils.php');
include_once('../lib/core/zpush.php');
include_once('../lib/core/zlog.php');
include_once('../lib/interface/ibackend.php');
include_once('../lib/interface/ichanges.php');
include_once('../lib/interface/iexportchanges.php');
include_once('../lib/interface/iimportchanges.php');
include_once('../lib/interface/isearchprovider.php');
include_once('../lib/interface/istatemachine.php');
include_once('../lib/request/request.php');
include_once('../version.php');
include_once('config.php');
require_once '../vendor/autoload.php';
require_once '../config.php';
class ZPushAutodiscover {
const ACCEPTABLERESPONSESCHEMA = 'http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006';
const ACCEPTABLERESPONSESCHEMAMOBILESYNC = 'http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006';
const ACCEPTABLERESPONSESCHEMAOUTLOOK = 'http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a';
const MAXINPUTSIZE = 8192; // Bytes, the autodiscover request shouldn't exceed that value
private static $instance;
......@@ -111,8 +99,11 @@ class ZPushAutodiscover {
$email = ($this->getAttribFromUserDetails($userDetails, 'emailaddress')) ? $this->getAttribFromUserDetails($userDetails, 'emailaddress') : $incomingXml->Request->EMailAddress;
$userFullname = ($this->getAttribFromUserDetails($userDetails, 'fullname')) ? $this->getAttribFromUserDetails($userDetails, 'fullname') : $email;
ZLog::Write(LOGLEVEL_WBXML, sprintf("Resolved user's '%s' fullname to '%s'", $username, $userFullname));
$response = $this->createResponse($email, $userFullname);
setcookie("membername", $username);
// At the moment Z-Push only supports mobile response schema for autodiscover. Send empty response if the client request outlook response schema.
if ($incomingXml->Request->AcceptableResponseSchema == ZPushAutodiscover::ACCEPTABLERESPONSESCHEMAMOBILESYNC) {
$response = $this->createResponse($email, $userFullname);
setcookie("membername", $username);
}
}
catch (AuthenticationRequiredException $ex) {
......@@ -175,7 +166,7 @@ class ZPushAutodiscover {
throw new FatalException('Invalid input XML: no AcceptableResponseSchema.');
}
if ($xml->Request->AcceptableResponseSchema != ZPushAutodiscover::ACCEPTABLERESPONSESCHEMA) {
if ($xml->Request->AcceptableResponseSchema != ZPushAutodiscover::ACCEPTABLERESPONSESCHEMAMOBILESYNC && $xml->Request->AcceptableResponseSchema != ZPushAutodiscover::ACCEPTABLERESPONSESCHEMAOUTLOOK) {
throw new FatalException('Invalid input XML: not a mobilesync responseschema.');
}
......
The Author of this backend is dupondje, I could have modified it.
You can find the original code here:
https://github.com/dupondje/PHP-Push-2
REQUIREMENTS:
php-curl
libawl-php
INSTALL:
Add your awl folder to the include_path variable (/etc/php.ini or similar)
CalDAV server (DAViCal, Sabredav, Sogo, Owncloud...)
This diff is collapsed.
<?php
/***********************************************
* File : exceptions.php
* File : config.php
* Project : Z-Push
* Descr : Includes all Z-Push exceptions
* Descr : CalDAV backend configuration file
*
* Created : 06.02.2012
* Created : 27.11.2012
*
* Copyright 2007 - 2013 Zarafa Deutschland GmbH
* Copyright 2012 - 2014 Jean-Louis Dupond
*
* Jean-Louis Dupond released this code as AGPLv3 here: https://github.com/dupondje/PHP-Push-2/issues/93
*
* 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,
......@@ -41,24 +43,32 @@
* Consult LICENSE file for details
************************************************/
// main exception
include_once('zpushexception.php');
// ************************
// BackendCalDAV settings
// ************************
// Server protocol: http or https
define('CALDAV_PROTOCOL', 'https');
// Server name
define('CALDAV_SERVER', 'caldavserver.domain.com');
// Server port
define('CALDAV_PORT', '443');
// Path
define('CALDAV_PATH', '/caldav.php/%u/');
// Default CalDAV folder (calendar folder/principal). This will be marked as the default calendar in the mobile
define('CALDAV_PERSONAL', 'PRINCIPAL');
// If the CalDAV server supports the sync-collection operation
// DAViCal, SOGo and SabreDav support it
// SabreDav version must be at least 1.9.0, otherwise set this to false
// Setting this to false will work with most servers, but it will be slower
define('CALDAV_SUPPORTS_SYNC', false);
// Fatal exceptions
include_once('fatalexception.php');
include_once('fatalmisconfigurationexception.php');
include_once('fatalnotimplementedexception.php');
include_once('wbxmlexception.php');
include_once('nopostrequestexception.php');
include_once('httpreturncodeexception.php');
include_once('authenticationrequiredexception.php');
include_once('provisioningrequiredexception.php');
// Non fatal exceptions
include_once('notimplementedexception.php');
include_once('syncobjectbrokenexception.php');
include_once('statusexception.php');
include_once('statenotfoundexception.php');
include_once('stateinvalidexception.php');
include_once('nohierarchycacheavailableexception.php');
include_once('statenotyetavailableexception.php');
// Maximum period to sync.
// Some servers don't support more than 10 years so you will need to change this
define('CALDAV_MAX_SYNC_PERIOD', 2147483647);
\ No newline at end of file
This is a CardDAV backend based in the vcarddir backend.
It supports DAViCal, Sogo, OwnCloud, SabreDav... and should works with any carddav server. So if it doesn't work with your server, please open a issue.
It supports ChangesSink method that will detect and send faster changes to your device.
DAViCal implements the SYNC operation, it's a very fast method to detect changes in your vcards.
The others servers don't implement it, so the code will fallback to a slower method (suggest your carddav server developers to implement it!!).
This is controlled with a flag in the config.php file.
Also, it can autodetect multiple addressbooks and will present them to the mobile device as an unique addressbook (only iOS supports multiple addressbook).
REQUIREMENTS:
php-curl
php-xsl
CardDAV server (DAViCal, Sabredav, Sogo, Owncloud...)
\ No newline at end of file
*Drenalina SRL (www.drenalina.com)* sponsored the development of the following features in the BackendCardDAV, any existing bug it's my fault not theirs ;-)
Thank you very much for helping to improve it!!
- Autodetecting addressbooks within a DAV principal.
- Merging multiple addressbooks so the device will see a unique one. Only iOS based devices support multiple addressbooks, so we will merge them for now.
- Selecting default addressbook to store new contacts created from the device.
- GAL addressbook and GAL search.
\ No newline at end of file
This diff is collapsed.
<?php
/***********************************************
* File : config.php
* Project : Z-Push
* Descr : CardDAV backend configuration file
*
* Created : 16.03.2013
*
* Copyright 2013 - 2016 Francisco Miguel Biete
*
* 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
************************************************/
// ************************
// BackendCardDAV settings
// ************************
// Server protocol: http or https
define('CARDDAV_PROTOCOL', 'https');
// Server name
define('CARDDAV_SERVER', 'localhost');
// Server port
define('CARDDAV_PORT', '443');
// Server path to the addressbook, or the principal with the addressbooks
// If your user has more than 1 addressbook point it to the principal.
// Example: user test@domain.com will have 2 addressbooks
// http://localhost/caldav.php/test@domain.com/addresses/personal
// http://localhost/caldav.php/test@domain.com/addresses/work
// You set the CARDDAV_PATH to '/caldav.php/%u/addresses/' and personal and work will be autodiscovered
// %u: replaced with the username
// %d: replaced with the domain
// Add the trailing /
define('CARDDAV_PATH', '/caldav.php/%u/');
// Server path to the default addressbook
// Mobile device will create new contacts here. It must be under CARDDAV_PATH
// %u: replaced with the username
// %d: replaced with the domain
// Add the trailing /
define('CARDDAV_DEFAULT_PATH', '/caldav.php/%u/addresses/');
// Server path to the GAL addressbook. This addressbook is readonly and searchable by the user, but it will NOT be synced.
// If you don't want GAL, comment it
// %u: replaced with the username
// %d: replaced with the domain
// Add the trailing /
define('CARDDAV_GAL_PATH', '/caldav.php/%d/GAL/');
// Minimal length for the search pattern to do the real search.
define('CARDDAV_GAL_MIN_LENGTH', 5);
// Addressbook display name, the name showed in the mobile device
// %u: replaced with the username
// %d: replaced with the domain
define('CARDDAV_CONTACTS_FOLDER_NAME', '%u Addressbook');
// If the CardDAV server supports the sync-collection operation
// DAViCal and SabreDav support it, but Owncloud, SOGo don't
// SabreDav version must be at least 1.9.0, otherwise set this to false
// Setting this to false will work with most servers, but it will be slower: 1 petition for the href of vcards, and 1 petition for each vcard
define('CARDDAV_SUPPORTS_SYNC', false);
// If the CardDAV server supports the FN attribute for searches
// DAViCal supports it, but SabreDav, Owncloud and SOGo don't
// Setting this to true will search by FN. If false will search by sn, givenName and email
// It's safe to leave it as false
define('CARDDAV_SUPPORTS_FN_SEARCH', false);
// If your carddav server needs to use file extension to recover a vcard.
// Davical needs it
// SOGo official demo online needs it, but some SOGo installation don't need it, so test it
define('CARDDAV_URL_VCARD_EXTENSION', '.vcf');
\ No newline at end of file
......@@ -74,6 +74,15 @@ class BackendCombinedConfig {
'v' => array(
'name' => 'BackendVCardDir',
),
'l' => array(
'name' => 'BackendLDAP',
),
'd' => array(
'name' => 'BackendCardDAV',
),
'c' => array(
'name' => 'BackendCalDAV',
),
),
'delimiter' => '/',
//force one type of folder to one backend
......
......@@ -1024,37 +1024,39 @@ class BackendIMAP extends BackendDiff {
if (Request::GetProtocolVersion() >= 12.0) {
$output->asbody = new SyncBaseBody();
$data = "";
switch($bpReturnType) {
case SYNC_BODYPREFERENCE_PLAIN:
$output->asbody->data = $plainBody;
$data = $plainBody;
break;
case SYNC_BODYPREFERENCE_HTML:
if ($htmlBody == "") {
$output->asbody->data = $plainBody;
$data = $plainBody;
$bpReturnType = SYNC_BODYPREFERENCE_PLAIN;
}
else {
$output->asbody->data = $htmlBody;
$data = $htmlBody;
}
break;
case SYNC_BODYPREFERENCE_MIME:
//We don't need to create a new MIME mail, we already have one!!
$output->asbody->data = $mail;
$data = $mail;
break;
case SYNC_BODYPREFERENCE_RTF:
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->GetMessage RTF Format NOT CHECKED");
$output->asbody->data = base64_encode($plainBody);
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->GetMessage RTF Format NOT SUPPORTED");
// TODO: this is broken. This is no RTF.
$data = base64_encode($plainBody);
break;
}
// truncate body, if requested
if(strlen($output->asbody->data) > $truncsize) {
$output->asbody->data = Utils::Utf8_truncate($output->asbody->data, $truncsize);
if(strlen($data) > $truncsize) {
$data = Utils::Utf8_truncate($data, $truncsize);
$output->asbody->truncated = 1;
}
$output->asbody->data = StringStreamWrapper::Open($data);
$output->asbody->type = $bpReturnType;
$output->nativebodytype = $bpReturnType;
$output->asbody->estimatedDataSize = strlen($output->asbody->data);
$output->asbody->estimatedDataSize = strlen($data);
$bpo = $contentparameters->BodyPreference($output->asbody->type);
if (Request::GetProtocolVersion() >= 14.0 && $bpo->GetPreview()) {
......@@ -1068,28 +1070,22 @@ class BackendIMAP extends BackendDiff {
else { // ASV_2.5
$output->bodytruncated = 0;
/* BEGIN fmbiete's contribution r1528, ZP-320 */
$data = "";
if ($bpReturnType == SYNC_BODYPREFERENCE_MIME) {
if (strlen($mail) > $truncsize) {
$output->mimedata = Utils::Utf8_truncate($mail, $truncsize);
$output->mimetruncated = 1;
}
else {
$output->mimetruncated = 0;
$output->mimedata = $mail;
}
$output->mimesize = strlen($output->mimedata);
$data = $mail;
}
else {
// truncate body, if requested
if (strlen($plainBody) > $truncsize) {
$output->body = Utils::Utf8_truncate($plainBody, $truncsize);
$output->bodytruncated = 1;
}
else {
$output->body = $plainBody;
$output->bodytruncated = 0;
}
$output->bodysize = strlen($output->body);
$data = $plainBody;
}
$output->mimesize = strlen($data);
if (strlen($data) > $truncsize) {
$output->mimedata = StringStreamWrapper::Open(Utils::Utf8_truncate($data, $truncsize));
$output->mimetruncated = 1;
}
else {
$output->mimetruncated = 0;
$output->mimedata = StringStreamWrapper::Open($data);
}
/* END fmbiete's contribution r1528, ZP-320 */
}
......
......@@ -401,6 +401,7 @@ class MAPIMapping {
"status" => "PT_LONG:PSETID_Task:0x8101",
"icon" => PR_ICON_INDEX,
"owner" => "PT_STRING8:PSETID_Task:0x811F",
"private" => "PT_BOOLEAN:PSETID_Common:0x8506",
);
}
......@@ -460,7 +461,7 @@ class MAPIMapping {
public static function GetNoteMapping() {
return array(
"categories" => "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords",
"lastmodificationtime" => PR_LAST_MODIFICATION_TIME,
"lastmodified" => PR_LAST_MODIFICATION_TIME,
"messageclass" => PR_MESSAGE_CLASS,
"subject" => PR_SUBJECT,
);
......
......@@ -851,7 +851,7 @@ class MAPIProvider {
if (isset($folderprops[PR_SOURCE_KEY]) && !isset($folderprops[PR_ENTRYID]) && !isset($folderprops[PR_CONTAINER_CLASS])) {
$entryid = mapi_msgstore_entryidfromsourcekey($this->store, $folderprops[PR_SOURCE_KEY]);
$mapifolder = mapi_msgstore_openentry($this->store, $entryid);
$folderprops = mapi_getprops($mapifolder, array(PR_DISPLAY_NAME, PR_PARENT_ENTRYID, PR_ENTRYID, PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY, PR_CONTAINER_CLASS, PR_ATTR_HIDDEN));
$folderprops = mapi_getprops($mapifolder, array(PR_DISPLAY_NAME, PR_PARENT_ENTRYID, PR_ENTRYID, PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY, PR_CONTAINER_CLASS, PR_ATTR_HIDDEN, PR_EXTENDED_FOLDER_FLAGS));
ZLog::Write(LOGLEVEL_DEBUG, "MAPIProvider->GetFolder(): received insuffient of data from ICS. Fetching required data.");
}
......@@ -877,6 +877,16 @@ class MAPIProvider {
return false;
}
// ignore suggested contacts folder
if (isset($folderprops[PR_CONTAINER_CLASS]) && $folderprops[PR_CONTAINER_CLASS] == "IPF.Contact" && isset($folderprops[PR_EXTENDED_FOLDER_FLAGS])) {
// the PR_EXTENDED_FOLDER_FLAGS is a binary value which consists of subproperties. 070403000000 indicates a suggested contacts folder
$extendedFlags = bin2hex($folderprops[PR_EXTENDED_FOLDER_FLAGS]);
if (substr_count($extendedFlags, "070403000000") > 0) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->GetFolder(): folder '%s' should not be synchronized", $folderprops[PR_DISPLAY_NAME]));
return false;
}
}
$folder->serverid = bin2hex($folderprops[PR_SOURCE_KEY]);
if($folderprops[PR_PARENT_ENTRYID] == $storeprops[PR_IPM_SUBTREE_ENTRYID])
$folder->parentid = "0";
......@@ -1176,7 +1186,7 @@ class MAPIProvider {
$props[$appointmentprops["responsestatus"]] = (isset($appointment->responsestatus)) ? $appointment->responsestatus : olResponseNone;
//sensitivity is not enough to mark an appointment as private, so we use another mapi tag
$private = (isset($appointment->sensitivity) && $appointment->sensitivity == 0) ? false : true;
$private = (isset($appointment->sensitivity) && $appointment->sensitivity >= SENSITIVITY_PRIVATE) ? true : false;
// Set commonstart/commonend to start/end and remindertime to start, duration, private and cleanGlobalObjectId
$props[$appointmentprops["commonstart"]] = $appointment->starttime;
......@@ -1589,6 +1599,8 @@ class MAPIProvider {
$recurrence->setRecurrence($recur);
}
$props[$taskprops["private"]] = (isset($task->sensitivity) && $task->sensitivity >= SENSITIVITY_PRIVATE) ? true : false;
//open addresss book for user resolve to set the owner
$addrbook = $this->getAddressbook();
......@@ -2363,24 +2375,39 @@ class MAPIProvider {
if (isset($message->asbody))
$message->asbody->type = $bpReturnType;
return $stat;
}
}
$stream = mapi_openproperty($mapimessage, $property, IID_IStream, 0, 0);
$stat = mapi_stream_stat($stream);
$streamsize = $stat['cb'];
$body = mapi_message_openproperty($mapimessage, $property);
//set the properties according to supported AS version
if (Request::GetProtocolVersion() >= 12.0) {
$message->asbody = new SyncBaseBody();
$message->asbody->type = $bpReturnType;
if ($bpReturnType == SYNC_BODYPREFERENCE_RTF)
$message->asbody->data = base64_encode($body);
elseif (isset($message->internetcpid) && $bpReturnType == SYNC_BODYPREFERENCE_HTML)
$message->asbody->data = Utils::ConvertCodepageStringToUtf8($message->internetcpid, $body);
else
$message->asbody->data = w2u($body);
$message->asbody->estimatedDataSize = strlen($message->asbody->data);
if ($bpReturnType == SYNC_BODYPREFERENCE_RTF) {
$body = mapi_stream_read($stream, $streamsize);
$message->asbody->data = StringStreamWrapper::Open(base64_encode($body));
}
elseif (isset($message->internetcpid) && $bpReturnType == SYNC_BODYPREFERENCE_HTML) {
// if PR_HTML is UTF-8 we can stream it directly, else we have to convert to UTF-8 & wrap it
if (Utils::GetCodepageCharset($message->internetcpid) == "utf-8") {
$message->asbody->data = MAPIStreamWrapper::Open($stream);
}
else {
$body = mapi_stream_read($stream, $streamsize);
$message->asbody->data = StringStreamWrapper::Open(Utils::ConvertCodepageStringToUtf8($message->internetcpid, $body));
}
}
else {
$message->asbody->data = MAPIStreamWrapper::Open($stream);
}
$message->asbody->estimatedDataSize = $streamsize;
}
else {
$body = mapi_stream_read($stream, $streamsize);
$message->body = str_replace("\n","\r\n", w2u(str_replace("\r", "", $body)));
$message->bodysize = strlen($message->body);
$message->bodysize = $streamsize;
$message->bodytruncated = 0;
}
......@@ -2407,22 +2434,20 @@ class MAPIProvider {
if (Request::GetProtocolVersion() >= 12.0) {
if (!isset($message->asbody))
$message->asbody = new SyncBaseBody();
//TODO data should be wrapped in a MapiStreamWrapper
$message->asbody->data = mapi_stream_read($stream, $streamsize);
$message->asbody->data = MapiStreamWrapper::Open($stream);
$message->asbody->estimatedDataSize = $streamsize;
$message->asbody->truncated = 0;
}
else {
$message->mimetruncated = 0;
//TODO mimedata should be a wrapped in a MapiStreamWrapper
$message->mimedata = mapi_stream_read($stream, $streamsize);
$message->mimedata = MapiStreamWrapper::Open($stream);
$message->mimesize = $streamsize;
$message->mimetruncated = 0;
}
unset($message->body, $message->bodytruncated);
return true;
}
else {
ZLog::Write(LOGLEVEL_ERROR, sprintf("Error opening attachment for imtoinet"));
ZLog::Write(LOGLEVEL_ERROR, sprintf("MAPIProvider->imtoinet(): got no stream or content from mapi_inetmapi_imtoinet()"));
}
}
......@@ -2456,12 +2481,11 @@ class MAPIProvider {
//only set the truncation size data if device set it in request
if ( $bpo->GetTruncationSize() != false &&
$bpReturnType != SYNC_BODYPREFERENCE_MIME &&
$message->asbody->estimatedDataSize > $bpo->GetTruncationSize() &&
$contentparameters->GetTruncation() != SYNC_TRUNCATION_ALL // do not truncate message if the whole is requested, e.g. on fetch
$message->asbody->estimatedDataSize > $bpo->GetTruncationSize()
) {
$message->asbody->data = Utils::Utf8_truncate($message->asbody->data, $bpo->GetTruncationSize());
// truncate data stream
ftruncate($message->asbody->data, $bpo->GetTruncationSize());
$message->asbody->truncated = 1;
}
// set the preview or windows phones won't show the preview of an email
if (Request::GetProtocolVersion() >= 14.0 && $bpo->GetPreview()) {
......@@ -2618,15 +2642,16 @@ class MAPIProvider {
* @return void
*/
private function setASbody($asbody, &$props, $appointmentprops) {
if (isset($asbody->type) && isset($asbody->data) && strlen($asbody->data) > 0) {
// TODO: fix checking for the length
if (isset($asbody->type) && isset($asbody->data) /*&& strlen($asbody->data) > 0*/) {
switch ($asbody->type) {
case SYNC_BODYPREFERENCE_PLAIN:
default:
//set plain body if the type is not in valid range
$props[$appointmentprops["body"]] = u2w($asbody->data);
$props[$appointmentprops["body"]] = stream_get_contents($asbody->data);
break;
case SYNC_BODYPREFERENCE_HTML:
$props[$appointmentprops["html"]] = u2w($asbody->data);
$props[$appointmentprops["html"]] = stream_get_contents($asbody->data);
break;
case SYNC_BODYPREFERENCE_RTF:
break;
......
......@@ -48,6 +48,7 @@ class MAPIStreamWrapper {
private $mapistream;
private $position;
private $streamlength;
private $toTruncate;
/**
* Opens the stream
......@@ -68,6 +69,7 @@ class MAPIStreamWrapper {
return false;
$this->position = 0;
$this->toTruncate = false;
// this is our stream!
$this->mapistream = $contextOptions[self::PROTOCOL]['stream'];
......@@ -91,8 +93,18 @@ class MAPIStreamWrapper {
*/
public function stream_read($len) {
$len = ($this->position + $len > $this->streamlength) ? ($this->streamlength - $this->position) : $len;
// read 4 additional bytes from the stream so we can always truncate correctly
if ($this->toTruncate)
$len += 4;
$data = mapi_stream_read($this->mapistream, $len);
$this->position += strlen($data);
// we need to truncate UTF8 compatible if ftruncate() was called
if ($this->toTruncate && $this->position >= $this->streamlength) {
$data = Utils::Utf8_truncate($data, $this->streamlength);
}
return $data;
}
......@@ -137,6 +149,23 @@ class MAPIStreamWrapper {
return ($this->position >= $this->streamlength);
}
/**
* Truncates the stream to the new size.
*
* @param int $new_size
* @return boolean
*/
public function stream_truncate ($new_size) {
$this->streamlength = $new_size;
$this->toTruncate = true;
if ($this->position > $this->streamlength) {
ZLog::Write(LOGLEVEL_WARN, sprintf("MAPIStreamWrapper->stream_truncate(): stream position (%d) ahead of new size of %d. Repositioning pointer to end of stream.", $this->position, $this->streamlength));
$this->position = $this->streamlength;
}
return true;
}
/**
* Retrieves information about a stream
*
......
{
"autoload": {
"classmap": ["autodiscover/", "include/", "lib/"],
"files": ["version.php", "lib/core/zpushdefs.php", "lib/utils/compat.php"]
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -54,84 +54,10 @@ else {
// ignore user abortions because this can lead to weird errors - see ZP-239
ignore_user_abort(true);
include_once('lib/exceptions/exceptions.php');
include_once('lib/utils/utils.php');
include_once('lib/utils/compat.php');
include_once('lib/utils/timezoneutil.php');
include_once('lib/utils/stringstreamwrapper.php');
include_once('lib/core/zpushdefs.php');
include_once('lib/core/stateobject.php');
include_once('lib/core/interprocessdata.php');
include_once('lib/core/pingtracking.php');
include_once('lib/core/topcollector.php');
include_once('lib/core/loopdetection.php');
include_once('lib/core/asdevice.php');
include_once('lib/core/statemanager.php');
include_once('lib/core/devicemanager.php');
include_once('lib/core/zpush.php');
include_once('lib/core/zlog.php');
include_once('lib/log/log.php');
include_once('lib/log/filelog.php');
include_once('lib/log/syslog.php');
include_once('lib/interface/ibackend.php');
include_once('lib/interface/ichanges.php');
include_once('lib/interface/iexportchanges.php');
include_once('lib/interface/iimportchanges.php');
include_once('lib/interface/isearchprovider.php');
include_once('lib/interface/istatemachine.php');
include_once('lib/core/streamer.php');
include_once('lib/core/streamimporter.php');
include_once('lib/core/synccollections.php');
include_once('lib/core/hierarchycache.php');
include_once('lib/core/changesmemorywrapper.php');
include_once('lib/core/syncparameters.php');
include_once('lib/core/bodypreference.php');
include_once('lib/core/contentparameters.php');
include_once('lib/wbxml/wbxmldefs.php');
include_once('lib/wbxml/wbxmldecoder.php');
include_once('lib/wbxml/wbxmlencoder.php');
include_once('lib/syncobjects/syncobject.php');
include_once('lib/syncobjects/syncbasebody.php');
include_once('lib/syncobjects/syncbaseattachment.php');
include_once('lib/syncobjects/syncmailflags.php');
include_once('lib/syncobjects/syncrecurrence.php');
include_once('lib/syncobjects/syncappointment.php');
include_once('lib/syncobjects/syncappointmentexception.php');
include_once('lib/syncobjects/syncattachment.php');
include_once('lib/syncobjects/syncattendee.php');
include_once('lib/syncobjects/syncmeetingrequestrecurrence.php');
include_once('lib/syncobjects/syncmeetingrequest.php');
include_once('lib/syncobjects/syncmail.php');
include_once('lib/syncobjects/syncnote.php');
include_once('lib/syncobjects/synccontact.php');
include_once('lib/syncobjects/syncfolder.php');
include_once('lib/syncobjects/syncprovisioning.php');
include_once('lib/syncobjects/synctaskrecurrence.php');
include_once('lib/syncobjects/synctask.php');
include_once('lib/syncobjects/syncoofmessage.php');
include_once('lib/syncobjects/syncoof.php');
include_once('lib/syncobjects/syncuserinformation.php');
include_once('lib/syncobjects/syncdeviceinformation.php');
include_once('lib/syncobjects/syncdevicepassword.php');
include_once('lib/syncobjects/syncitemoperationsattachment.php');
include_once('lib/syncobjects/syncsendmail.php');
include_once('lib/syncobjects/syncsendmailsource.php');
include_once('lib/syncobjects/syncvalidatecert.php');
include_once('lib/syncobjects/syncresolverecipients.php');
include_once('lib/syncobjects/syncresolverecipient.php');
include_once('lib/syncobjects/syncresolverecipientsresponse.php');
include_once('lib/syncobjects/syncresolverecipientsoptions.php');
include_once('lib/syncobjects/syncresolverecipientsavailability.php');
include_once('lib/syncobjects/syncresolverecipientscertificates.php');
include_once('lib/syncobjects/syncresolverecipientspicture.php');
include_once('lib/default/backend.php');
include_once('lib/default/searchprovider.php');
include_once('lib/request/request.php');
include_once('lib/request/requestprocessor.php');
require_once 'vendor/autoload.php';
if (!defined('ZPUSH_CONFIG')) define('ZPUSH_CONFIG', 'config.php');
include_once(ZPUSH_CONFIG);
include_once('version.php');
// Attempt to set maximum execution time
......
......@@ -196,6 +196,11 @@ class Streamer implements Serializable {
if(!$decoder->getElementEndTag())
return false;
}
else if($map[self::STREAMER_TYPE] == self::STREAMER_TYPE_STREAM_ASPLAIN) {
$decoded = StringStreamWrapper::Open($decoder->getElementContent());
if(!$decoder->getElementEndTag())
return false;
}
else {
$subdecoder = new $map[self::STREAMER_TYPE]();
if($subdecoder->Decode($decoder) === false)
......
......@@ -72,6 +72,27 @@ class SyncCollections implements Iterator {
private $waitingTime = 0;
/**
* Invalidates all pingable flags for all folders.
*
* @access public
* @return boolean
*/
static public function InvalidatePingableFlags() {
ZLog::Write(LOGLEVEL_DEBUG, "SyncCollections::InvalidatePingableFlags(): Invalidating now");
try {
$sc = new SyncCollections();
$sc->LoadAllCollections();
foreach ($sc as $folderid => $spa) {
$spa->DelPingableFlag();
$sc->SaveCollection($spa);
}
return true;
}
catch (ZPushException $e) {}
return false;
}
/**
* Constructor
*/
......@@ -330,11 +351,11 @@ class SyncCollections implements Iterator {
}
/**
* Returns the global window size of items to be exported in total over all
* Returns the global window size of items to be exported in total over all
* requested collections.
*
* @access public
* @return int/boolean returns requested windows size, 512 (max) or the
* @return int/boolean returns requested windows size, 512 (max) or the
* value of config SYNC_MAX_ITEMS if it is lower
*/
public function GetGlobalWindowSize() {
......
......@@ -140,13 +140,16 @@ class ZLog {
static public function WriteEnd() {
if (LOGLEVEL_DEBUG <= LOGLEVEL || (LOGLEVEL_DEBUG <= LOGUSERLEVEL && self::$userLog)) {
if (version_compare(phpversion(), '5.4.0') < 0) {
$time_used = number_format(time() - $_SERVER["REQUEST_TIME"], 4);
$time_used = number_format(time() - $_SERVER["REQUEST_TIME"], 2, ',', '.');
}
else {
$time_used = number_format(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"], 4);
$time_used = number_format(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"], 2, ',', '.');
}
$peakUsage = memory_get_peak_usage(false);
$truePeakUsage = memory_get_peak_usage(true);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Memory usage information: %s/%s - Execution time: %s - HTTP responde code: %s", memory_get_peak_usage(false), memory_get_peak_usage(true), $time_used, http_response_code()));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Memory usage information: %s/%s (%s B/%s B) - Execution time: %ss - HTTP responde code: %s",
Utils::FormatBytes($peakUsage), Utils::FormatBytes($truePeakUsage), $peakUsage, $truePeakUsage, $time_used, http_response_code()));
ZLog::Write(LOGLEVEL_DEBUG, "-------- End");
}
}
......@@ -161,9 +164,12 @@ class ZLog {
static private function getLogger() {
if (!self::$logger) {
global $specialLogUsers; // This variable comes from the configuration file (config.php)
$logger = LOGBACKEND;
$logger = LOGBACKEND_CLASS;
if (!class_exists($logger)) {
throw new FatalNotImplementedException('The logging class `'.$logger.'` does not exist.');
$errmsg = 'The configured logging class `'.$logger.'` does not exist. Check your configuration.';
error_log($errmsg);
throw new \Exception($errmsg);
}
list($user) = Utils::SplitDomainUser(strtolower(Request::GetGETUser()));
......
......@@ -224,8 +224,8 @@ class ZPush {
define('LOGBACKEND', 'filelog');
}
if (LOGBACKEND == 'syslog') {
if (strtolower(LOGBACKEND) == 'syslog') {
define('LOGBACKEND_CLASS', 'Syslog');
if (!defined('LOG_SYSLOG_FACILITY')) {
define('LOG_SYSLOG_FACILITY', LOG_LOCAL0);
}
......@@ -250,8 +250,8 @@ class ZPush {
throw new FatalMisconfigurationException("LOG_SYSLOG_HOST is defined but the LOG_SYSLOG_PORT does not seem to be valid.");
}
}
elseif (LOGBACKEND == 'filelog') {
elseif (strtolower(LOGBACKEND) == 'filelog') {
define('LOGBACKEND_CLASS', 'FileLog');
if (!defined('LOGFILEDIR'))
throw new FatalMisconfigurationException("The LOGFILEDIR is not configured. Check if the config.php file is in place.");
......@@ -271,6 +271,9 @@ class ZPush {
Utils::FixFileOwner(LOGFILE);
Utils::FixFileOwner(LOGERRORFILE);
}
else {
define('LOGBACKEND_CLASS', LOGBACKEND);
}
// set time zone
// code contributed by Robert Scheck (rsc)
......@@ -397,7 +400,6 @@ class ZPush {
}
else {
// Initialize the default StateMachine
include_once('lib/default/filestatemachine.php');
ZPush::$stateMachine = new FileStateMachine();
}
......
......@@ -183,8 +183,22 @@ abstract class Backend implements IBackend {
* @return SyncObject $settings
*/
public function Settings($settings) {
if ($settings instanceof SyncOOF || $settings instanceof SyncUserInformation)
if ($settings instanceof SyncOOF) {
$isget = !empty($settings->bodytype);
$settings = new SyncOOF();
if ($isget) {
//oof get
$settings->oofstate = 0;
$settings->Status = SYNC_SETTINGSSTATUS_SUCCESS;
} else {
//oof set
$settings->Status = SYNC_SETTINGSSTATUS_PROTOCOLLERROR;
}
}
if ($settings instanceof SyncUserInformation) {
$settings->emailaddresses = array(ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser())['emailaddress']);
$settings->Status = SYNC_SETTINGSSTATUS_SUCCESS;
}
return $settings;
}
......
......@@ -51,15 +51,6 @@
* Consult LICENSE file for details
************************************************/
// default backend
include_once('lib/default/backend.php');
// DiffBackend components
include_once('diffstate.php');
include_once('importchangesdiff.php');
include_once('exportchangesdiff.php');
abstract class BackendDiff extends Backend {
protected $store;
......
......@@ -176,6 +176,11 @@ class FileStateMachine implements IStateMachine {
* @throws StateInvalidException
*/
public function CleanStates($devid, $type, $key, $counter = false) {
// Don't remove permanent backend storage files, unless we explicitily want that
if ($key === false && $type === IStateMachine::BACKENDSTORAGE && $counter != IStateMachine::HIGHEST_COUNTER) {
return;
}
$matching_files = glob($this->getFullFilePath($devid, $type, $key). "*", GLOB_NOSORT);
if (is_array($matching_files)) {
foreach($matching_files as $state) {
......@@ -209,7 +214,6 @@ class FileStateMachine implements IStateMachine {
* @return boolean indicating if the user was added or not (existed already)
*/
public function LinkUserDevice($username, $devid) {
include_once("simplemutex.php");
$mutex = new SimpleMutex();
$changed = false;
......@@ -254,7 +258,6 @@ class FileStateMachine implements IStateMachine {
* @return boolean
*/
public function UnLinkUserDevice($username, $devid) {
include_once("simplemutex.php");
$mutex = new SimpleMutex();
$changed = false;
......
......@@ -60,6 +60,7 @@ interface IStateMachine {
const FAILSAVE = "fs";
const HIERARCHY = "hc";
const BACKENDSTORAGE = "bs";
const HIGHEST_COUNTER = 99999999999;
const STATEVERSION_01 = "1"; // Z-Push 2.0.x - default value if unset
const STATEVERSION_02 = "2"; // Z-Push 2.1.0 Milestone 1
......
......@@ -247,6 +247,9 @@ class FolderChange extends RequestProcessor {
// update SPA & save it
$spa->SetSyncKey($newsynckey);
self::$deviceManager->GetStateManager()->SetSynchedFolderState($spa);
// invalidate all pingable flags
SyncCollections::InvalidatePingableFlags();
}
return true;
......
......@@ -259,6 +259,9 @@ class FolderSync extends RequestProcessor {
// update SPA & save it
$spa->SetSyncKey($newsynckey);
self::$deviceManager->GetStateManager()->SetSynchedFolderState($spa);
// invalidate all pingable flags
SyncCollections::InvalidatePingableFlags();
}
}
}
......
......@@ -103,9 +103,8 @@ class Ping extends RequestProcessor {
}
if(($el = self::$decoder->getElementStartTag(SYNC_PING_FOLDERS)) && $el[EN_FLAGS] & EN_FLAGS_CONTENT) {
// remove PingableFlag from all collections
foreach ($sc as $folderid => $spa)
$spa->DelPingableFlag();
// cache requested (pingable) folderids
$pingable = array();
while(self::$decoder->getElementStartTag(SYNC_PING_FOLDER)) {
WBXMLDecoder::ResetInWhile("pingFolder");
......@@ -143,13 +142,24 @@ class Ping extends RequestProcessor {
$foundchanges = true;
}
else if ($class == $spa->GetContentClass()) {
$spa->SetPingableFlag(true);
$pingable[] = $folderid;
ZLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): using saved sync state for '%s' id '%s'", $spa->GetContentClass(), $folderid));
}
}
if(!self::$decoder->getElementEndTag())
return false;
// update pingable flags
foreach ($sc as $folderid => $spa) {
// if the folderid is in $pingable, we should ping it, else remove the flag
if (in_array($folderid, $pingable)) {
$spa->SetPingableFlag(true);
}
else {
$spa->DelPingableFlag();
}
}
}
if(!self::$decoder->getElementEndTag())
return false;
......
......@@ -56,7 +56,8 @@ class SyncBaseBody extends SyncObject {
SYNC_AIRSYNCBASE_TYPE => array (self::STREAMER_VAR => "type"),
SYNC_AIRSYNCBASE_ESTIMATEDDATASIZE => array (self::STREAMER_VAR => "estimatedDataSize"),
SYNC_AIRSYNCBASE_TRUNCATED => array (self::STREAMER_VAR => "truncated"),
SYNC_AIRSYNCBASE_DATA => array (self::STREAMER_VAR => "data"),
SYNC_AIRSYNCBASE_DATA => array (self::STREAMER_VAR => "data",
self::STREAMER_TYPE => self::STREAMER_TYPE_STREAM_ASPLAIN),
);
if(Request::GetProtocolVersion() >= 14.0) {
$mapping[SYNC_AIRSYNCBASE_PREVIEW] = array (self::STREAMER_VAR => "preview");
......
......@@ -130,7 +130,8 @@ class SyncMail extends SyncObject {
SYNC_POOMMAIL_MIMETRUNCATED => array ( self::STREAMER_VAR => "mimetruncated",
self::STREAMER_CHECKS => array( self::STREAMER_CHECK_ZEROORONE => self::STREAMER_CHECK_SETZERO)),
SYNC_POOMMAIL_MIMEDATA => array ( self::STREAMER_VAR => "mimedata"), //TODO mimedata should be of a type stream
SYNC_POOMMAIL_MIMEDATA => array ( self::STREAMER_VAR => "mimedata",
self::STREAMER_TYPE => self::STREAMER_TYPE_STREAM_ASPLAIN),
SYNC_POOMMAIL_MIMESIZE => array ( self::STREAMER_VAR => "mimesize",
self::STREAMER_CHECKS => array( self::STREAMER_CHECK_CMPHIGHER => -1)),
......
......@@ -58,7 +58,9 @@ class SyncResolveRecipientsPicture extends SyncObject {
$mapping[SYNC_RESOLVERECIPIENTS_MAXSIZE] = array ( self::STREAMER_VAR => "maxsize");
$mapping[SYNC_RESOLVERECIPIENTS_MAXPICTURES] = array ( self::STREAMER_VAR => "maxpictures");
$mapping[SYNC_RESOLVERECIPIENTS_STATUS] = array ( self::STREAMER_VAR => "status");
$mapping[SYNC_RESOLVERECIPIENTS_DATA] = array ( self::STREAMER_VAR => "data");
$mapping[SYNC_RESOLVERECIPIENTS_DATA] = array ( self::STREAMER_VAR => "data",
self::STREAMER_TYPE => self::STREAMER_TYPE_STREAM_ASBASE64,
);
}
parent::SyncObject($mapping);
......
......@@ -145,6 +145,24 @@ class StringStreamWrapper {
return ($this->position >= $this->stringlength);
}
/**
* Truncates the stream to the new size.
*
* @param int $new_size
* @return boolean
*/
public function stream_truncate ($new_size) {
// cut the string!
$this->stringstream = Utils::Utf8_truncate($this->stringstream, $new_size);
$this->streamlength = strlen($this->stringstream);
if ($this->position > $this->streamlength) {
ZLog::Write(LOGLEVEL_WARN, sprintf("MAPIStreamWrapper->stream_truncate(): stream position (%d) ahead of new size of %d. Repositioning pointer to end of stream.", $this->position, $this->streamlength));
$this->position = $this->streamlength;
}
return true;
}
/**
* Retrieves information about a stream
*
......
......@@ -1100,25 +1100,42 @@ class TimezoneUtil {
ZLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::GetFullTZ() for ". $phptimezone);
$servertzname = self::guessTZNameFromPHPName($phptimezone);
$offset = self::$tzonesoffsets[$servertzname];
return self::GetFullTZFromTZName($servertzname);
}
/**
* Returns a full timezone array
*
* @param string $tzname a TZID value
*
* @access public
* @return array
*/
static public function GetFullTZFromTZName($tzname) {
if (!array_key_exists($tzname, self::$tzonesoffsets)) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetFullTZFromTZName('%s'): Is a PHP TimeZone, converting", $tzname));
$tzname = self::guessTZNameFromPHPName($tzname);
}
$offset = self::$tzonesoffsets[$tzname];
$tz = array(
"bias" => $offset[0],
"tzname" => self::encodeTZName(self::getMSTZnameFromTZName($servertzname)),
"tzname" => self::encodeTZName(self::getMSTZnameFromTZName($tzname)),
"dstendyear" => $offset[3],
"dstendmonth" => $offset[4],
"dstendday" => $offset[6],
"dstendweek" => $offset[5],
"dstendday" => $offset[5],
"dstendweek" => $offset[6],
"dstendhour" => $offset[7],
"dstendminute" => $offset[8],
"dstendsecond" => $offset[9],
"dstendmillis" => $offset[10],
"stdbias" => $offset[1],
"tznamedst" => self::encodeTZName(self::getMSTZnameFromTZName($servertzname)),
"tznamedst" => self::encodeTZName(self::getMSTZnameFromTZName($tzname)),
"dststartyear" => $offset[11],
"dststartmonth" => $offset[12],
"dststartday" => $offset[14],
"dststartweek" => $offset[13],
"dststartday" => $offset[13],
"dststartweek" => $offset[14],
"dststarthour" => $offset[15],
"dststartminute" => $offset[16],
"dststartsecond" => $offset[17],
......@@ -1210,7 +1227,7 @@ class TimezoneUtil {
* @access public
* @return string
*/
static private function getMSTZnameFromTZName($name) {
static public function getMSTZnameFromTZName($name) {
foreach (self::$mstzones as $mskey => $msdefs) {
if ($name == $msdefs[0])
return $msdefs[1];
......@@ -1278,4 +1295,60 @@ class TimezoneUtil {
return $packed;
}
/**
* Generate date object from string and timezone.
*
* @param string $value
* @param string $timezone
*
* @access public
* @return int epoch
*/
public static function MakeUTCDate($value, $timezone = null) {
$tz = null;
if ($timezone) {
$tz = timezone_open($timezone);
}
if (!$tz) {
//If there is no timezone set, we use the default timezone
$tz = timezone_open(date_default_timezone_get());
}
//20110930T090000Z
$date = date_create_from_format('Ymd\THis\Z', $value, timezone_open("UTC"));
if (!$date) {
//20110930T090000
$date = date_create_from_format('Ymd\THis', $value, $tz);
}
if (!$date) {
//20110930 (Append T000000Z to the date, so it starts at midnight)
$date = date_create_from_format('Ymd\THis\Z', $value . "T000000Z", $tz);
}
return date_timestamp_get($date);
}
/**
* Generate a tzid from various formats
*
* @param str $timezone
*
* @access public
* @return timezone id
*/
public static function ParseTimezone($timezone) {
//(GMT+01.00) Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna
if (preg_match('/GMT(\\+|\\-)0(\d)/', $timezone, $matches)) {
return "Etc/GMT" . $matches[1] . $matches[2];
}
//(GMT+10.00) XXX / XXX / XXX / XXX
if (preg_match('/GMT(\\+|\\-)1(\d)/', $timezone, $matches)) {
return "Etc/GMT" . $matches[1] . "1" . $matches[2];
}
///inverse.ca/20101018_1/Europe/Amsterdam or /inverse.ca/20101018_1/America/Argentina/Buenos_Aires
if (preg_match('/\/[.[:word:]]+\/\w+\/(\w+)\/([\w\/]+)/', $timezone, $matches)) {
return $matches[1] . "/" . $matches[2];
}
return TimezoneUtil::getMSTZnameFromTZName(trim($timezone, '"'));
}
}
......@@ -950,6 +950,24 @@ class Utils {
return $res;
}
/**
* Format bytes to a more human readable value.
* @param int $bytes
* @param int $precision
*
* @access public
* @return void|string
*/
public static function FormatBytes($bytes, $precision = 2) {
if ($bytes <= 0) return '0 B';
$units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB');
$base = log ($bytes, 1024);
$fBase = floor($base);
$pow = pow(1024, $base - $fBase);
return sprintf ("%.{$precision}f %s", $pow, $units[$fBase]);
}
}
......
......@@ -282,7 +282,7 @@ class ZPushAdmin {
StateManager::UnLinkState($device, false);
// remove backend storage permanent data
ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::BACKENDSTORAGE, false, 99999999999);
ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::BACKENDSTORAGE, false, IStateMachine::HIGHEST_COUNTER);
// remove devicedata and unlink user from device
unset($devices[$user]);
......
......@@ -41,7 +41,7 @@
* Consult LICENSE file for details
************************************************/
class replace_nullchar_filter extends php_user_filter {
class ReplaceNullcharFilter extends php_user_filter {
/**
* This method is called whenever data is read from or written to the attached stream.
......@@ -66,5 +66,3 @@ class replace_nullchar_filter extends php_user_filter {
return PSFS_PASS_ON;
}
}
stream_filter_register('replacenullchar', 'replace_nullchar_filter');
\ No newline at end of file
......@@ -194,7 +194,7 @@ class WBXMLEncoder extends WBXMLDefs {
*/
public function contentStream($stream, $asBase64 = false) {
if (!$asBase64) {
include_once('lib/wbxml/replacenullcharfilter.php');
stream_filter_register('replacenullchar', 'ReplaceNullcharFilter');
$rnc_filter = stream_filter_append($stream, 'replacenullchar');
}
......
......@@ -67,8 +67,6 @@ class Webservice {
// the webservice command is handled by its class
if ($commandCode == ZPush::COMMAND_WEBSERVICE_DEVICE) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): executing WebserviceDevice service", $commandCode));
include_once('webservicedevice.php');
$this->server->setClass("WebserviceDevice");
}
......@@ -82,7 +80,6 @@ class Webservice {
if(ZPush::GetBackend()->Setup("SYSTEM", true) == false)
throw new AuthenticationRequiredException(sprintf("User '%s' has no admin privileges", Request::GetAuthUser()));
include_once('webserviceusers.php');
$this->server->setClass("WebserviceUsers");
}
......
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInitd6749fc2fb9944bbe86b2b7d79a7852f::getLoader();
This diff is collapsed.
Copyright (c) 2015 Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
This diff is collapsed.
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'158e247719544c05f5e89c414f630c24' => $baseDir . '/version.php',
'7e65a9fc8bb44d8c2fe16fa283aeaaee' => $baseDir . '/lib/core/zpushdefs.php',
'd2a63a53b4a43a2bd71de0cec5c1abfb' => $baseDir . '/lib/utils/compat.php',
);
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitd6749fc2fb9944bbe86b2b7d79a7852f
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitd6749fc2fb9944bbe86b2b7d79a7852f', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitd6749fc2fb9944bbe86b2b7d79a7852f', 'loadClassLoader'));
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register(true);
$includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequired6749fc2fb9944bbe86b2b7d79a7852f($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequired6749fc2fb9944bbe86b2b7d79a7852f($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
This diff is collapsed.
This diff is collapsed.
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