Commit 2b349076 authored by Sebastian Kummer's avatar Sebastian Kummer

Merge branch 'develop' of https://stash.z-hub.io/scm/zp/z-push into...

Merge branch 'develop' of https://stash.z-hub.io/scm/zp/z-push into feature/ZP-556-having-access-to-the-public-folder

Conflicts:
	src/lib/core/devicemanager.php
parents ea60b86c 9702de07
......@@ -464,6 +464,8 @@ class MAPIMapping {
"lastmodified" => PR_LAST_MODIFICATION_TIME,
"messageclass" => PR_MESSAGE_CLASS,
"subject" => PR_SUBJECT,
"Color" => "PT_LONG:PSETID_Note:0x8B00",
"Iconindex" => PR_ICON_INDEX,
);
}
......
......@@ -1635,6 +1635,11 @@ class MAPIProvider {
// Setting it to an empty array will unset the property in Zarafa as well
if (!isset($note->categories)) $note->categories = array();
// update icon index to correspond to the color
if (isset($note->Color) && $note->Color > -1 && $note->Color < 5) {
$note->Iconindex = 768 + $note->Color;
}
$this->setPropsInMAPI($mapimessage, $note, MAPIMapping::GetNoteMapping());
$noteprops = MAPIMapping::GetNoteProperties();
......@@ -1644,7 +1649,9 @@ class MAPIProvider {
$props = array();
$props[$noteprops["messageclass"]] = "IPM.StickyNote";
// set body otherwise the note will be "broken" when editing it in outlook
$this->setASbody($note->asbody, $props, $noteprops);
if (isset($note->asbody)) {
$this->setASbody($note->asbody, $props, $noteprops);
}
$props[$noteprops["internetcpid"]] = INTERNET_CPID_UTF8;
mapi_setprops($mapimessage, $props);
......@@ -2435,7 +2442,7 @@ class MAPIProvider {
if (!$stream || $size == 0) {
return "";
}
return mapi_stream_read($stream, $streamsize);
return mapi_stream_read($stream, $size);
}
/**
......@@ -2718,6 +2725,16 @@ class MAPIProvider {
if (!isset($this->storeProps) || empty($this->storeProps)) {
ZLog::Write(LOGLEVEL_DEBUG, "MAPIProvider->getStoreProps(): Getting store properties.");
$this->storeProps = mapi_getprops($this->store, array(PR_IPM_SUBTREE_ENTRYID, PR_IPM_OUTBOX_ENTRYID, PR_IPM_WASTEBASKET_ENTRYID, PR_IPM_SENTMAIL_ENTRYID, PR_ENTRYID, PR_IPM_PUBLIC_FOLDERS_ENTRYID, PR_IPM_FAVORITES_ENTRYID, PR_MAILBOX_OWNER_ENTRYID));
// make sure all properties are set
if(!isset($this->storeProps[PR_IPM_WASTEBASKET_ENTRYID])) {
$this->storeProps[PR_IPM_WASTEBASKET_ENTRYID] = false;
}
if(!isset($this->storeProps[PR_IPM_SENTMAIL_ENTRYID])) {
$this->storeProps[PR_IPM_SENTMAIL_ENTRYID] = false;
}
if(!isset($this->storeProps[PR_IPM_OUTBOX_ENTRYID])) {
$this->storeProps[PR_IPM_OUTBOX_ENTRYID] = false;
}
}
return $this->storeProps;
}
......@@ -2731,8 +2748,33 @@ class MAPIProvider {
private function getInboxProps() {
if (!isset($this->inboxProps) || empty($this->inboxProps)) {
ZLog::Write(LOGLEVEL_DEBUG, "MAPIProvider->getInboxProps(): Getting inbox properties.");
$this->inboxProps = array();
$inbox = mapi_msgstore_getreceivefolder($this->store);
$this->inboxProps = mapi_getprops($inbox, array(PR_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_IPM_TASK_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_JOURNAL_ENTRYID));
if ($inbox) {
$this->inboxProps = mapi_getprops($inbox, array(PR_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_IPM_TASK_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_JOURNAL_ENTRYID));
// make sure all properties are set
if(!isset($this->inboxProps[PR_ENTRYID])) {
$this->inboxProps[PR_ENTRYID] = false;
}
if(!isset($this->inboxProps[PR_IPM_DRAFTS_ENTRYID])) {
$this->inboxProps[PR_IPM_DRAFTS_ENTRYID] = false;
}
if(!isset($this->inboxProps[PR_IPM_TASK_ENTRYID])) {
$this->inboxProps[PR_IPM_TASK_ENTRYID] = false;
}
if(!isset($this->inboxProps[PR_IPM_APPOINTMENT_ENTRYID])) {
$this->inboxProps[PR_IPM_APPOINTMENT_ENTRYID] = false;
}
if(!isset($this->inboxProps[PR_IPM_CONTACT_ENTRYID])) {
$this->inboxProps[PR_IPM_CONTACT_ENTRYID] = false;
}
if(!isset($this->inboxProps[PR_IPM_NOTE_ENTRYID])) {
$this->inboxProps[PR_IPM_NOTE_ENTRYID] = false;
}
if(!isset($this->inboxProps[PR_IPM_JOURNAL_ENTRYID])) {
$this->inboxProps[PR_IPM_JOURNAL_ENTRYID] = false;
}
}
}
return $this->inboxProps;
}
......
This diff is collapsed.
......@@ -280,6 +280,33 @@
// might result in timeout. Default is 10.
define('SEARCH_MAXRESULTS', 10);
/**********************************************************************************
* Kopano Outlook Extension - Settings
*
* The Kopano Outlook Extension (KOE) provides MS Outlook 2013 and newer with
* functionality not provided by ActiveSync or not implemented by Outlook.
* For more information, see: https://wiki.z-hub.io/x/z4Aa
*/
// Global Address Book functionality
define('KOE_CAPABILITY_GAB', true);
// Synchronize mail flags from the server to Outlook/KOE
define('KOE_CAPABILITY_RECEIVEFLAGS', true);
// Encode flags when sending from Outlook/KOE
define('KOE_CAPABILITY_SENDFLAGS', true);
// Out-of-office support
define('KOE_CAPABILITY_OOF', true);
// Out-of-office support with start & end times (superseeds KOE_CAPABILITY_OOF)
define('KOE_CAPABILITY_OOFTIMES', true);
// Notes support
define('KOE_CAPABILITY_NOTES', true);
// To synchronize the GAB KOE, the GAB store and folderid need to be specified.
// Use the gab-sync script to generate this data. The name needs to
// match the config of the gab-sync script.
// More information here: https://wiki.z-hub.io/x/z4Aa (GAB Sync Script)
define('KOE_GAB_STORE', 'SYSTEM');
define('KOE_GAB_FOLDERID', '');
define('KOE_GAB_NAME', 'Z-Push-KOE-GAB');
/**********************************************************************************
* Synchronize additional folders to all mobiles
......
......@@ -72,6 +72,10 @@ class ASDevice extends StateObject {
'announcedASversion' => false,
'foldersynccomplete' => true,
'additionalfolders' => array(),
'koeversion' => false,
'koebuild' => false,
'koebuilddate' => false,
'koegabbackendfolderid' => false,
);
static private $loadedData;
......
......@@ -200,13 +200,21 @@ class ChangesMemoryWrapper extends HierarchyCache implements IImportChanges, IEx
if (isset($this->destinationImporter)) {
// normally the $folder->type is not set, but we need this value to check if the change operation is permitted
// e.g. system folders can normally not be changed - set the type from cache and let the destinationImporter decide
if (!isset($folder->type)) {
if (!isset($folder->type) || ! $folder->type) {
$cacheFolder = $this->GetFolder($folder->serverid);
$folder->type = $cacheFolder->type;
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ChangesMemoryWrapper->ImportFolderChange(): Set foldertype for folder '%s' from cache as it was not sent: '%s'", $folder->displayname, $folder->type));
}
$retFolder = $this->destinationImporter->ImportFolderChange($folder);
// KOE ZO-42: When Notes folders are updated in Outlook, it tries to update the name (that fails by default, as it's a system folder)
// catch this case here and ignore the change
if (($folder->type == SYNC_FOLDER_TYPE_NOTE || $folder->type == SYNC_FOLDER_TYPE_USER_NOTE) && ZPush::GetDeviceManager()->IsKoe()) {
$retFolder = false;
}
// do regular folder update
else {
$retFolder = $this->destinationImporter->ImportFolderChange($folder);
}
// if the operation was sucessfull, update the HierarchyCache
if ($retFolder) {
......
......@@ -107,6 +107,10 @@ class DeviceManager {
$this->stateManager->SetDevice($this->device);
$this->additionalFoldersHash = $this->getAdditionalFoldersHash();
if ($this->IsKoe() && $this->device->GetKoeVersion() !== false) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KOE: %s / %s / %s", $this->device->GetKoeVersion(), $this->device->GetKoeBuild(), strftime("%Y-%m-%d %H:%M", $this->device->GetKoeBuildDate())));
}
}
/**
......@@ -156,6 +160,13 @@ class DeviceManager {
$this->device->SetUserAgent(Request::GetUserAgent());
$this->device->SetASVersion(Request::GetProtocolVersion());
// update data from the OL plugin (if available)
if (Request::HasKoeStats()) {
$this->device->SetKoeVersion(Request::GetKoeVersion());
$this->device->SetKoeBuild(Request::GetKoeBuild());
$this->device->SetKoeBuildDate(Request::GetKoeBuildDate());
}
// data to be saved
$data = $this->device->GetData();
if ($data && Request::IsValidDeviceID() && $this->saveDevice) {
......@@ -452,6 +463,25 @@ class DeviceManager {
return $class;
}
/**
* Returns the backend folder id of the KOE GAB folder.
* This comes either from the configuration or from the device data.
*
* @return string|boolean returns false if not set or found
*/
public function GetKoeGabBackendFolderId() {
$gabid = false;
if (KOE_CAPABILITY_GAB) {
if (KOE_GAB_FOLDERID != false && KOE_GAB_FOLDERID != '') {
$gabid = KOE_GAB_FOLDERID;
}
else if (KOE_GAB_STORE != "" && KOE_GAB_NAME != "") {
$gabid = $this->device->GetKoeGabBackendFolderId();
}
}
return $gabid;
}
/**
* Returns the additional folders as SyncFolder objects.
*
......@@ -461,19 +491,34 @@ class DeviceManager {
public function GetAdditionalUserSyncFolders() {
$folders = array();
foreach($this->device->GetAdditionalFolders() as $df) {
$folder = new SyncFolder();
$folder->BackendId = $df['folderid'];
$folder->serverid = $this->GetFolderIdForBackendId($folder->BackendId, true, DeviceManager::FLD_ORIGIN_SHARED, $df['name']);
$folder->parentid = 0; // only top folders are supported
$folder->displayname = $df['name'];
$folder->type = $df['type'];
// save store as custom property which is not streamed directly to the device
$folder->NoBackendFolder = true;
$folder->Store = $df['store'];
$folder->ReadOnly = $df['readonly'];
$folder = $this->getAdditionalSyncFolder($df['store'], $df['folderid'], $df['name'], $df['type'], $df['readonly'], DeviceManager::FLD_ORIGIN_SHARED);
$folders[$folder->BackendId] = $folder;
}
// ZO-40: add KOE GAB folder
if (KOE_CAPABILITY_GAB && $this->IsKoe() && KOE_GAB_STORE != "" && KOE_GAB_NAME != "") {
// if KOE_GAB_FOLDERID is set, use it
if (KOE_GAB_FOLDERID != "") {
$folder = $this->getAdditionalSyncFolder(KOE_GAB_STORE, KOE_GAB_FOLDERID, KOE_GAB_NAME, SYNC_FOLDER_TYPE_USER_APPOINTMENT, true, DeviceManager::FLD_ORIGIN_GAB);
$folders[$folder->BackendId] = $folder;
}
else {
// get the GAB id from the device and from the backend
$deviceGabId = $this->device->GetKoeGabBackendFolderId();
if (!ZPush::GetBackend()->Setup(KOE_GAB_STORE)) {
ZLog::Write(LOGLEVEL_WARN, sprintf("DeviceManager->GetAdditionalUserSyncFolders(): setup for store '%s' failed. Unable to search for KOE GAB folder.", KOE_GAB_STORE));
}
else {
$backendGabId = ZPush::GetBackend()->GetKoeGabBackendFolderId(KOE_GAB_NAME);
if ($deviceGabId !== $backendGabId) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("DeviceManager->GetAdditionalUserSyncFolders(): Backend found different KOE GAB backend folderid: '%s'. Updating ASDevice.", $backendGabId));
$this->device->SetKoeGabBackendFolderId($backendGabId);
}
$folders[$backendGabId] = $this->getAdditionalSyncFolder(KOE_GAB_STORE, $backendGabId, KOE_GAB_NAME, SYNC_FOLDER_TYPE_USER_APPOINTMENT, true, DeviceManager::FLD_ORIGIN_GAB);
}
}
}
return $folders;
}
......@@ -486,6 +531,11 @@ class DeviceManager {
* @return boolean|string
*/
public function GetAdditionalUserSyncFolderStore($folderid) {
// is this the KOE GAB folder?
if ($folderid == $this->GetKoeGabBackendFolderId()) {
return KOE_GAB_STORE;
}
$f = $this->device->GetAdditionalFolder($folderid);
if ($f) {
return $f['store'];
......@@ -700,6 +750,19 @@ class DeviceManager {
return $this->loopdetection->ProcessLoopDetectionIsHierarchyResyncRequired();
}
/**
* Indicates if an Outlook via ActiveSync is connected.
*
* @access public
* @return boolean
*/
public function IsKoe() {
if (Request::IsOutlook() && ($this->device->GetKoeVersion() !== false || Request::HasKoeStats())) {
return true;
}
return false;
}
/**
* Adds an Exceptions to the process tracking
*
......@@ -1055,11 +1118,38 @@ class DeviceManager {
* @access private
* @return string
*/
private function getPolicyName() {
$policyName = ZPush::GetBackend()->GetUserPolicyName();
$policyName = ((!empty($policyName) && $policyName !== false) ? $policyName : ASDevice::DEFAULTPOLICYNAME);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("DeviceManager->getPolicyName(): determined policy name: '%s'", $policyName));
return $policyName;
}
/**
* Generates and SyncFolder object and returns it.
*
* @param string $store
* @param string $folderid
* @param string $name
* @param int $type
* @param boolean $readonly
* @param string $folderOrigin
*
* @access private
* @returns SyncFolder
*/
private function getAdditionalSyncFolder($store, $folderid, $name, $type, $readonly, $folderOrigin) {
$folder = new SyncFolder();
$folder->BackendId = $folderid;
$folder->serverid = $this->GetFolderIdForBackendId($folder->BackendId, true, $folderOrigin, $name);
$folder->parentid = 0; // only top folders are supported
$folder->displayname = $name;
$folder->type = $type;
// save store as custom property which is not streamed directly to the device
$folder->NoBackendFolder = true;
$folder->Store = $store;
$folder->ReadOnly = $readonly;
return $folder;
}
}
......@@ -6,7 +6,7 @@
*
* Created : 01.10.2007
*
* Copyright 2007 - 2013 Zarafa Deutschland GmbH
* 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,
......@@ -86,8 +86,44 @@ class ImportChangesStream implements IImportChanges {
*/
public function ImportMessageChange($id, $message) {
// ignore other SyncObjects
if(!($message instanceof $this->classAsString))
if(!($message instanceof $this->classAsString)) {
return false;
}
// KOE ZO-42: to sync Notes to Outlook we sync them as Appointments
if ($this->classAsString == "SyncNote") {
if (KOE_CAPABILITY_NOTES && ZPush::GetDeviceManager()->IsKoe()) {
// update category from SyncNote->Color
$message->SetCategoryFromColor();
$appointment = new SyncAppointment();
$appointment->busystatus = 0;
$appointment->sensitivity = 0;
$appointment->alldayevent = 0;
$appointment->reminder = 0;
$appointment->meetingstatus = 0;
$appointment->responserequested = 0;
$appointment->flags = $message->flags;
if (isset($message->asbody))
$appointment->asbody = $message->asbody;
if (isset($message->categories))
$appointment->categories = $message->categories;
if (isset($message->subject))
$appointment->subject = $message->subject;
if (isset($message->lastmodified))
$appointment->dtstamp = $message->lastmodified;
$appointment->starttime = time();
$appointment->endtime = $appointment->starttime + 1;
$message = $appointment;
}
else if (Request::IsOutlook()) {
ZLog::Write(LOGLEVEL_WARN, "MS Outlook is synchronizing Notes folder without active KOE settings or extension. Not streaming SyncNote change!");
return false;
}
}
// prevent sending the same object twice in one request
if (in_array($id, $this->seenObjects)) {
......@@ -110,6 +146,22 @@ class ImportChangesStream implements IImportChanges {
return $stat;
}
// KOE ZO-3: Stream reply/forward flag and time as additional category to KOE
if (ZPush::GetDeviceManager()->IsKoe() && KOE_CAPABILITY_RECEIVEFLAGS && isset($message->lastverbexectime) && isset($message->lastverbexecuted) && $message->lastverbexecuted > 0) {
ZLog::Write(LOGLEVEL_DEBUG, "ImportChangesStream->ImportMessageChange('%s'): KOE detected. Adding LastVerb information as category.");
if (!isset($message->categories)){
$message->categories = array();
}
$s = "Push: Email ";
if ($message->lastverbexecuted == 1) $s .= "replied";
elseif ($message->lastverbexecuted == 2) $s .= "replied-to-all";
elseif ($message->lastverbexecuted == 3) $s .= "forwarded";
$s .= " on " . gmdate("d-m-Y H:i:s", $message->lastverbexectime) . " GMT";
$message->categories[] = $s;
}
if ($message->flags === false || $message->flags === SYNC_NEWMESSAGE)
$this->encoder->startTag(SYNC_ADD);
else {
......
......@@ -86,7 +86,10 @@ class SyncCollections implements Iterator {
$sc = new SyncCollections();
$sc->LoadAllCollections();
foreach ($sc as $folderid => $spa) {
$sc->invalidateFolderStat($spa);
if ($spa->GetPingableFlag() == true) {
$spa->DelPingableFlag();
$sc->SaveCollection($spa);
}
}
return true;
}
......@@ -737,12 +740,13 @@ class SyncCollections implements Iterator {
if ($this->hierarchyExporterChecked === true && !$this->LoadCollection(false, true, false))
throw new StatusException("Invalid states found while re-loading hierarchy data.");
// reset backend to the main store
ZPush::GetBackend()->Setup(false);
$changesMem = ZPush::GetDeviceManager()->GetHierarchyChangesWrapper();
$changesMem = ZPush::GetDeviceManager()->GetHierarchyChangesWrapper();
// the hierarchyCache should now fully be initialized - check for changes in the additional folders
$changesMem->Config(ZPush::GetAdditionalSyncFolders(false));
// reset backend to the main store
ZPush::GetBackend()->Setup(false);
$exporter = ZPush::GetBackend()->GetExporter();
if ($exporter !== false && isset($this->addparms[$folderid]["state"])) {
$exporter->Config($this->addparms[$folderid]["state"]);
......
......@@ -341,6 +341,35 @@ class ZPush {
throw new FatalMisconfigurationException("The PING_HIGHER_BOUND_LIFETIME value must be greater or equal to PING_LOWER_BOUND_LIFETIME.");
}
// Check KOE flags
if (!defined('KOE_CAPABILITY_GAB')) {
define('KOE_CAPABILITY_GAB', false);
}
if (!defined('KOE_CAPABILITY_RECEIVEFLAGS')) {
define('KOE_CAPABILITY_RECEIVEFLAGS', false);
}
if (!defined('KOE_CAPABILITY_SENDFLAGS')) {
define('KOE_CAPABILITY_SENDFLAGS', false);
}
if (!defined('KOE_CAPABILITY_OOF')) {
define('KOE_CAPABILITY_OOF', false);
}
if (!defined('KOE_CAPABILITY_OOFTIMES')) {
define('KOE_CAPABILITY_OOFTIMES', false);
}
if (!defined('KOE_CAPABILITY_NOTES')) {
define('KOE_CAPABILITY_NOTES', false);
}
if (!defined('KOE_GAB_FOLDERID')) {
define('KOE_GAB_FOLDERID', '');
}
if (!defined('KOE_GAB_STORE')) {
define('KOE_GAB_STORE', '');
}
if (!defined('KOE_GAB_NAME')) {
define('KOE_GAB_NAME', false);
}
// the check on additional folders will not throw hard errors, as this is probably changed on live systems
if (isset($additionalFolders) && !is_array($additionalFolders))
ZLog::Write(LOGLEVEL_ERROR, "ZPush::CheckConfig() : The additional folders synchronization not available as array.");
......
......@@ -682,6 +682,7 @@ define("SYNC_NOTES_MESSAGECLASS", "Notes:MessageClass");
define("SYNC_NOTES_LASTMODIFIEDDATE", "Notes:LastModifiedDate");
define("SYNC_NOTES_CATEGORIES", "Notes:Categories");
define("SYNC_NOTES_CATEGORY", "Notes:Category");
define("SYNC_NOTES_IGNORE_COLOR","Notes:IgnoreColor");
//RightsManagement //post 14.0
define("SYNC_RIGHTSMANAGEMENT_SUPPORT", "RightsManagement:RightsManagementSupport");
......
......@@ -365,4 +365,15 @@ abstract class Backend implements IBackend {
return false;
}
/**
* Returns the backend ID of the folder of the KOE GAB.
*
* @param string $foldername
*
* @access public
* @return string|boolean
*/
public function GetKoeGabBackendFolderId($foldername) {
return false;
}
}
......@@ -341,4 +341,14 @@ interface IBackend {
* @return string|boolean
*/
public function GetUserPolicyName();
/**
* Returns the backend ID of the folder of the KOE GAB.
*
* @param string $foldername
*
* @access public
* @return string|boolean
*/
public function GetKoeGabBackendFolderId($foldername);
}
......@@ -134,6 +134,9 @@ class FolderChange extends RequestProcessor {
// the hierarchyCache should now fully be initialized - check for changes in the additional folders
$changesMem->Config(ZPush::GetAdditionalSyncFolders(false));
// reset to default store in backend
self::$backend->Setup(false);
// there are unprocessed changes in the hierarchy, trigger resync
if ($changesMem->GetChangeCount() > 0)
throw new StatusException("HandleFolderChange() can not proceed as there are unprocessed hierarchy changes", SYNC_FSSTATUS_SERVERERROR);
......
......@@ -97,6 +97,9 @@ class FolderSync extends RequestProcessor {
// the hierarchyCache should now fully be initialized - check for changes in the additional folders
$changesMem->Config(ZPush::GetAdditionalSyncFolders(false));
// reset to default store in backend
self::$backend->Setup(false);
// process incoming changes
if(self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_CHANGES)) {
// Ignore <Count> if present
......
......@@ -137,11 +137,10 @@ class Ping extends RequestProcessor {
$fakechanges[$folderid] = 1;
$foundchanges = true;
}
else if ($class == $spa->GetContentClass()) {
else if ($this->isClassValid($class, $spa)) {
$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;
......@@ -273,4 +272,23 @@ class Ping extends RequestProcessor {
}
return true;
}
/**
* Checks if a sent folder class is valid for that SyncParameters object.
*
* @param string $class
* @param SycnParameters $spa
*
* @access public
* @return boolean
*/
private function isClassValid($class, $spa) {
if ($class == $spa->GetContentClass() ||
// KOE ZO-42: Notes are synched as Appointments
(self::$deviceManager->IsKoe() && KOE_CAPABILITY_NOTES && $class == "Calendar" && $spa->GetContentClass() == "Notes")
) {
return true;
}
return false;
}
}
......@@ -54,6 +54,7 @@ class Request {
const NUMBERS_ONLY = 4;
const NUMBERSDOT_ONLY = 5;
const HEX_EXTENDED = 6;
const ISO8601 = 7;
/**
* Command parameters for base64 encoded requests (AS >= 12.1)
......@@ -93,6 +94,9 @@ class Request {
static private $occurence; //TODO
static private $saveInSent;
static private $acceptMultipart;
static private $koeVersion;
static private $koeBuild;
static private $koeBuildDate;
/**
......@@ -232,6 +236,13 @@ class Request {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Request::ProcessHeaders() ASVersion: %s", self::$asProtocolVersion));
if (isset(self::$headers["x-push-plugin"])) {
list($version, $build, $buildDate) = explode("/", self::$headers["x-push-plugin"]);
self::$koeVersion = self::filterEvilInput($version, self::NUMBERSDOT_ONLY);
self::$koeBuild = self::filterEvilInput($build, self::HEX_ONLY);
self::$koeBuildDate = strtotime(self::filterEvilInput($buildDate, self::ISO8601));
}
if (defined('USE_X_FORWARDED_FOR_HEADER') && USE_X_FORWARDED_FOR_HEADER == true && isset(self::$headers["x-forwarded-for"])) {
$forwardedIP = self::filterEvilInput(self::$headers["x-forwarded-for"], self::NUMBERSDOT_ONLY);
if ($forwardedIP) {
......@@ -650,6 +661,7 @@ class Request {
else if ($filter == self::NUMBERS_ONLY) $re = "/[^0-9]/";
else if ($filter == self::NUMBERSDOT_ONLY) $re = "/[^0-9\.]/";
else if ($filter == self::HEX_EXTENDED) $re = "/[^A-Fa-f0-9\:]/";
else if ($filter == self::ISO8601) $re = "/[^\d{8}T\d{6}Z]/";
return ($re) ? preg_replace($re, $replacevalue, $input) : '';
}
......@@ -668,4 +680,63 @@ class Request {
fclose($input);
return $wbxml;
}
/**
* Indicates if the request contained the KOE stats header.
*
* @access public
* @return boolean
*/
static public function HasKoeStats() {
return isset(self::$koeVersion) && isset(self::$koeBuild) && isset(self::$koeBuildDate);
}
/**
* Returns the version number of the KOE informed by the stats header.
*
* @access public
* @return string
*/
static public function GetKoeVersion() {
if (isset(self::$koeVersion))
return self::$koeVersion;
else
return self::UNKNOWN;
}
/**
* Returns the build of the KOE informed by the stats header.
*
* @access public
* @return string
*/
static public function GetKoeBuild() {
if (isset(self::$koeBuild))
return self::$koeBuild;
else
return self::UNKNOWN;
}
/**
* Returns the build date of the KOE informed by the stats header.
*
* @access public
* @return string
*/
static public function GetKoeBuildDate() {
if (isset(self::$koeBuildDate))
return self::$koeBuildDate;
else
return self::UNKNOWN;
}
/**
* Returns whether it is an Outlook client.
*
* @access public
* @return boolean
*/
static public function IsOutlook() {
return (self::GetDeviceType() == "WindowsOutlook");
}
}
......@@ -6,7 +6,7 @@
*
* Created : 16.02.2012
*
* Copyright 2007 - 2013 Zarafa Deutschland GmbH
* Copyright 2007 - 2013, 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,
......@@ -87,6 +87,28 @@ class SendMail extends RequestProcessor {
// no wbxml output is provided, only a http OK
$sm->saveinsent = Request::GetGETSaveInSent();
}
// KOE ZO-6: grep for the KOE header and set flags accordingly.
// The header has the values verb/message-source-key/folder-source-key
if (KOE_CAPABILITY_SENDFLAGS && preg_match("/X-Push-Flags: (\d{3})\/([\da-f]+)\/([\da-f]+)/i", $sm->mime, $ol_flags)) {
// "reply" and "reply-all" are handled as "reply"
if ($ol_flags[1] == 102 || $ol_flags[1] == 103) {
$reply = true;
}
else if ($ol_flags[1] == 104) {
$forward = true;
}
// set source folder+item and replacemime
if (!isset($sm->source)) {
$sm->source = new SyncSendMailSource();
}
$sm->source->itemid = $ol_flags[2];
$sm->source->folderid = $ol_flags[3];
$sm->replacemime = true;
ZLog::Write(LOGLEVEL_DEBUG, "SendMail(): KOE support: overwrite reply/forward flag, set parent-id and item-id, replacemime - original message should not be attached.");
}
// Check if it is a reply or forward. Two cases are possible:
// 1. Either $smartreply or $smartforward are set after reading WBXML
// 2. Either $reply or $forward are set after geting the request parameters
......@@ -111,10 +133,10 @@ class SendMail extends RequestProcessor {
$sm->forwardflag = true;
if (!isset($sm->source->folderid))
ZLog::Write(LOGLEVEL_ERROR, sprintf("No parent folder id while replying or forwarding message:'%s'", (($reply) ? $reply : $forward)));
ZLog::Write(LOGLEVEL_ERROR, sprintf("SendMail(): No parent folder id while replying or forwarding message:'%s'", (($reply) ? $reply : $forward)));
}
self::$topCollector->AnnounceInformation(sprintf("Sending email with %d bytes", strlen($sm->mime)), true);
self::$topCollector->AnnounceInformation(sprintf("SendMail(): Sending email with %d bytes", strlen($sm->mime)), true);
try {
$status = self::$backend->SendMail($sm);
......
......@@ -6,7 +6,7 @@
*
* Created : 16.02.2012
*
* Copyright 2007 - 2013 Zarafa Deutschland GmbH
* 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,
......@@ -55,6 +55,22 @@ class Settings extends RequestProcessor {
if (!self::$decoder->getElementStartTag(SYNC_SETTINGS_SETTINGS))
return false;
// add capability header for KOE
if(self::$deviceManager->IsKoe()) {
// define the supported capabilites
$cap = array();
if(KOE_CAPABILITY_GAB) $cap[] = "gab";
if(KOE_CAPABILITY_RECEIVEFLAGS) $cap[] = "receiveflags";
if(KOE_CAPABILITY_SENDFLAGS) $cap[] = "sendflags";
if(KOE_CAPABILITY_OOFTIMES) $cap[] = "ooftime";
else if(KOE_CAPABILITY_OOF) $cap[] = "oof"; // 'ooftime' superseeds 'oof'. If 'ooftime' is set, 'oof' should not be defined.
if(KOE_CAPABILITY_NOTES) $cap[] = "notes";
self::$specialHeaders = array();
self::$specialHeaders[] = "X-Push-Capabilities: ". implode(",",$cap);
self::$specialHeaders[] = "X-Push-GAB-Name: ". bin2hex(KOE_GAB_NAME);
}
//save the request parameters
$request = array();
......
......@@ -6,7 +6,7 @@
*
* Created : 16.02.2012
*
* Copyright 2007 - 2015 Zarafa Deutschland GmbH
* 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,
......@@ -397,6 +397,12 @@ class Sync extends RequestProcessor {
$spa->SetFilterType(SYNC_FILTERTIME_MAX);
}
// unset filtertype for KOE GAB folder
if (KOE_CAPABILITY_GAB && self::$deviceManager->IsKoe() && $spa->GetBackendFolderId() == self::$deviceManager->GetKoeGabBackendFolderId()) {
$spa->SetFilterType(SYNC_FILTERTYPE_ALL);
ZLog::Write(LOGLEVEL_DEBUG, "HandleSync(): KOE GAB folder - setting filter type to unlimited");
}
if ($currentFilterType != $spa->GetFilterType()) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("HandleSync(): filter type has changed (old: '%s', new: '%s'), removing folderstat to force Exporter setup", $currentFilterType, $spa->GetFilterType()));
$spa->DelFolderStat();
......@@ -467,10 +473,35 @@ class Sync extends RequestProcessor {
// Get the SyncMessage if sent
if(($el = self::$decoder->getElementStartTag(SYNC_DATA)) && ($el[EN_FLAGS] & EN_FLAGS_CONTENT)) {
$message = ZPush::getSyncObjectFromFolderClass($spa->GetContentClass());
$message->Decode(self::$decoder);
// set Ghosted fields
$message->emptySupported(self::$deviceManager->GetSupportedFields($spa->GetFolderId()));
// KOE ZO-42: OL sends Notes as Appointments
if ($spa->GetContentClass() == "Notes" && KOE_CAPABILITY_NOTES && self::$deviceManager->IsKoe()) {
ZLog::Write(LOGLEVEL_DEBUG, "HandleSync(): KOE sends Notes as Appointments, read as SyncAppointment and convert it into a SyncNote object.");
$message = new SyncAppointment();
$message->Decode(self::$decoder);
$note = new SyncNote();
if (isset($message->asbody))
$note->asbody = $message->asbody;
if (isset($message->categories))
$note->categories = $message->categories;
if (isset($message->subject))
$note->subject = $message->subject;
if (isset($message->dtstamp))
$note->lastmodified = $message->dtstamp;
// set SyncNote->Color from a color category
$note->SetColorFromCategory();
$message = $note;
}
else {
$message->Decode(self::$decoder);
// set Ghosted fields
$message->emptySupported(self::$deviceManager->GetSupportedFields($spa->GetFolderId()));
}
if(!self::$decoder->getElementEndTag()) // end applicationdata
return false;
}
......
......@@ -47,11 +47,27 @@
class SyncNote extends SyncObject {
// Outlook transports note colors as categories
static private $colors = array(
0 => "Blue Category",
1 => "Green Category",
2 => "Red Category",
3 => "Yellow Category",
4 => "White Category",
);
// Purple and orange are not supported in PidLidNoteColor
static private $unsupportedColors = array(
"Purple Category",
"Orange Category",
);
public $asbody;
public $categories;
public $lastmodified;
public $messageclass;
public $subject;
public $Color;
function SyncNote() {
$mapping = array(
......@@ -67,8 +83,61 @@ class SyncNote extends SyncObject {
SYNC_NOTES_MESSAGECLASS => array ( self::STREAMER_VAR => "messageclass"),
SYNC_NOTES_SUBJECT => array ( self::STREAMER_VAR => "subject"),
SYNC_NOTES_IGNORE_COLOR => array ( self::STREAMER_VAR => "Color",
self::STREAMER_TYPE => self::STREAMER_TYPE_IGNORE),
);
parent::SyncObject($mapping);
}
/**
* Sets the color index from a known category.
*
* @access public
* @return void
*/
public function SetColorFromCategory() {
if (!empty($this->categories)) {
$result = array_intersect($this->categories, array_values(self::$colors));
if (empty($result)) {
$result = array_intersect($this->categories, array_values(self::$unsupportedColors));
if (!empty($result)) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncNote->SetColorFromCategory(): unsupported color '%s', setting to color white", $result[0]));
$result = array("White Category");
}
}
if (!empty($result)) {
$this->Color = array_search($result[0], self::$colors);
}
}
// unset or empty category means we have to reset the color to yellow
else {
$this->Color = 3;
}
}
/**
* Sets the category for a Color if color categories are not yet set.
*
* @access public
* @return boolean
*/
public function SetCategoryFromColor() {
// is a color other than yellow set
if (isset($this->Color) && $this->Color != 3 && $this->Color > -1 && $this->Color < 5) {
// check existing categories - do not rewrite category if the category is already a supported or unsupported color
if (!empty($this->categories) &&
(!empty(array_intersect($this->categories, array_values(self::$unsupportedColors))) ||
!empty(array_intersect($this->categories, array_values(self::$colors))) )) {
return false;
}
if(!isset($this->categories)) {
$this->categories = array();
}
$this->categories[] = self::$colors[$this->Color];
return true;
}
}
}
......@@ -486,7 +486,7 @@ class ZPushAdmin {
$new_list = array();
foreach ($device->GetAdditionalFolders() as $folder) {
$folder['source'] = 'user';
$folder['syncfolderid'] = $device->GetFolderIdForBackendId($folder['folderid'], false);
$folder['syncfolderid'] = $device->GetFolderIdForBackendId($folder['folderid'], false, false, null);
$new_list[$folder['folderid']] = $folder;
}
foreach (ZPush::GetAdditionalSyncFolders() as $fid => $so) {
......@@ -495,7 +495,7 @@ class ZPushAdmin {
$new_list[$fid] = array(
'store' => $so->Store,
'folderid' => $fid,
'syncfolderid' => $device->GetFolderIdForBackendId($fid, false),
'syncfolderid' => $device->GetFolderIdForBackendId($fid, false, false, null),
'name' => $so->displayname,
'type' => $so->type,
'readonly' => $so->ReadOnly,
......
......@@ -862,6 +862,13 @@ class ZPushAdminCLI {
echo "Wiped on:\t\t". ($device->GetWipeActionOn() ? strftime("%Y-%m-%d %H:%M", $device->GetWipeActionOn()) : "not set")."\n";
echo "Policy name:\t\t". ($device->GetPolicyName() ? $device->GetPolicyName() : ASDevice::DEFAULTPOLICYNAME)."\n";
if ($device->GetKoeVersion()) {
echo "Kopano Outlook Extension:\n";
echo "\tVersion:\t". $device->GetKoeVersion() ."\n";
echo "\tBuild:\t\t". $device->GetKoeBuild() ."\n";
echo "\tBuild Date:\t". strftime("%Y-%m-%d %H:%M",$device->GetKoeBuildDate()) ."\n";
}
echo "Attention needed:\t";
if ($device->GetDeviceError())
......
This diff is collapsed.
<?php
/***********************************************
* File : config.php
* Project : Z-Push - tools - GAB sync
* Descr : Configuration file.
*
* Created : 28.01.2016
*
* Copyright 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
* ************************************************/
// The field to be hashed that is unique and never changes
// in the entire lifetime of the GAB entry.
define('HASHFIELD', 'account');
define('AMOUNT_OF_CHUNKS', 10);
// SyncWorker implementation to be used
define('SYNCWORKER', 'Kopano');
// Unique id to find a contact from the GAB (value to be supplied by -u on the command line)
// Zarafa supports: 'account' and 'smtpAddress' (email)
define('UNIQUEID', 'account');
// Server connection settings
// Depending on your setup, it might be advisable to change the lines below to one defined with your
// default socket location.
// Normally "default:" points to the default setting ("file:///var/run/kopano/server.sock")
// Examples: define("SERVER", "default:");
// define("SERVER", "http://localhost:236/kopano");
// define("SERVER", "https://localhost:237/kopano");
// define("SERVER", "file:///var/run/kopano/server.sock";
// If you are using ZCP >= 7.2.0, set it to the zarafa location, e.g.
// define("SERVER", "http://localhost:236/zarafa");
// define("SERVER", "https://localhost:237/zarafa");
// define("SERVER", "file:///var/run/zarafad/server.sock";
// For ZCP versions prior to 7.2.0 the socket location is different (http(s) sockets are the same):
// define("SERVER", "file:///var/run/zarafa";
define('SERVER', 'default:');
define('USERNAME', '');
define('PASSWORD', '');
define('CERTIFICATE', null);
define('CERTIFICATE_PASSWORD', null);
// Store where the hidden folder is located.
// For the public folder, use SYSTEM
// to use another store, use the same as USERNAME
// or another store where USERNAME has full access to.
define('HIDDEN_FOLDERSTORE', 'SYSTEM');
/// Do not change (unless you know exactly what you do)
define('HIDDEN_FOLDERNAME', 'Z-Push-KOE-GAB');
<?php
/***********************************************
* File : gab-sync.php
* Project : Z-Push - tools - GAB sync
* Descr : GAB-Sync tool.
*
* Created : 28.01.2016
*
* Copyright 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
* ************************************************/
if (!defined('SYNC_CONFIG')) define('SYNC_CONFIG', 'config.php');
include_once(SYNC_CONFIG);
/************************************************
* MAIN
*/
define('BASE_PATH_CLI', dirname(__FILE__) ."/");
set_include_path(get_include_path() . PATH_SEPARATOR . BASE_PATH_CLI);
try {
GabSyncCLI::CheckEnv();
GabSyncCLI::CheckOptions();
if (! GabSyncCLI::SureWhatToDo()) {
// show error message if available
if (GabSyncCLI::GetErrorMessage())
fwrite(STDERR, GabSyncCLI::GetErrorMessage() . PHP_EOL.PHP_EOL);
echo GabSyncCLI::UsageInstructions();
exit(1);
}
else if (!GabSyncCLI::SetupSyncWorker()) {
fwrite(STDERR, GabSyncCLI::GetErrorMessage() . PHP_EOL);
exit(1);
}
GabSyncCLI::RunCommand();
}
catch (Exception $ex) {
die(get_class($ex) . ": ". $ex->getMessage() . PHP_EOL);
}
/************************************************
* GAB SYNC CLI
*/
class GabSyncCLI {
const COMMAND_SIMULATE = 1;
const COMMAND_SYNC = 2;
const COMMAND_SYNC_ONE = 3;
const COMMAND_CLEARALL = 4;
const COMMAND_DELETEALL = 5;
static private $syncWorker;
static private $command;
static private $uniqueId = false;
static private $errormessage;
/**
* Returns usage instructions.
*
* @access public
* @return string
*/
static public function UsageInstructions() {
return "Usage:" .PHP_EOL.
"\tgab-sync.php -a ACTION [options]" .PHP_EOL.PHP_EOL.
"Parameters:" .PHP_EOL.
"\t-a simulate | sync | sync-one | clear-all | delete-all" .PHP_EOL.
"\t[-u] UNIQUE-ID" .PHP_EOL.PHP_EOL.
"Actions:" .PHP_EOL.
"\tsimulate\t\t Simulates the GAB synchronization and prints out statistics and configuration suggestions." .PHP_EOL.
"\tsync\t\t\t Synchronizes all data from the GAB to the global folder, clearing all existing data if configuration changed!" .PHP_EOL.
"\tsync-one -u UNIQUE-ID\t Tries do find the entry with UNIQUE-ID and updates the chunk this entry belongs to." .PHP_EOL.
"\tclear-all\t\t Removes all data from the global folder." .PHP_EOL.
"\tdelete-all\t\t Like clear-all but also deletes the global folder." .PHP_EOL.
PHP_EOL;
}
/**
* Setup of the SyncWorker implementation.
*
* @access public
* @return boolean
*/
static public function SetupSyncWorker() {
$file = "lib/" .strtolower(SYNCWORKER).".php";
if (!file_exists($file)) {
self::$errormessage = "SyncWorker file '".$file."' can not be found. Check your configuration.";
return false;
}
else {
include_once($file);
}
if (!class_exists(SYNCWORKER)) {
self::$errormessage = "SyncWorker file loaded, but class '".SYNCWORKER."' can not be found. Check your implementation.";
}
else {
$s = @constant('SYNCWORKER');
self::$syncWorker = new $s();
return true;
}
return false;
}
/**
* Checks the environment.
*
* @access public
* @return void
*/
static public function CheckEnv() {
if (php_sapi_name() != "cli")
self::$errormessage = "This script can only be called from the CLI.";
if (!function_exists("getopt"))
self::$errormessage = "PHP Function getopt not found. Please check your PHP version and settings.";
}
/**
* Checks the options from the command line.
*
* @access public
* @return void
*/
static public function CheckOptions() {
if (self::$errormessage)
return;
$options = getopt("u:a:");
// get 'unique-id'
if (isset($options['u']) && !empty($options['u']))
self::$uniqueId = strtolower(trim($options['u']));
else if (isset($options['unique-id']) && !empty($options['unique-id']))
self::$uniqueId = strtolower(trim($options['unique-id']));
// get 'action'
$action = false;
if (isset($options['a']) && !empty($options['a']))
$action = strtolower(trim($options['a']));
elseif (isset($options['action']) && !empty($options['action']))
$action = strtolower(trim($options['action']));
// get a command for the requested action
switch ($action) {
// simulate
case "simulate":
self::$command = self::COMMAND_SIMULATE;
break;
// sync!
case "sync":
self::$command = self::COMMAND_SYNC;
break;
// sync one
case "sync-one":
if (self::$uniqueId === false) {
self::$errormessage = "Not possible to synchronize one user, if the unique-id is not specified (-u parameter).";
}
else {
self::$command = self::COMMAND_SYNC_ONE;
}
break;
// clear all data
case "clear-all":
self::$command = self::COMMAND_CLEARALL;
break;
// delete all
case "delete-all":
self::$command = self::COMMAND_DELETEALL;
break;
default:
self::UsageInstructions();
}
}
/**
* Indicates if the options from the command line
* could be processed correctly.
*
* @access public
* @return boolean
*/
static public function SureWhatToDo() {
return isset(self::$command);
}
/**
* Returns a errormessage of things which could have gone wrong.
*
* @access public
* @return string
*/
static public function GetErrorMessage() {
return (isset(self::$errormessage))?self::$errormessage:"";
}
/**
* Runs a command requested from an action of the command line.
*
* @access public
* @return void
*/
static public function RunCommand() {
echo PHP_EOL;
switch(self::$command) {
case self::COMMAND_SIMULATE:
self::$syncWorker->Simulate();
break;
case self::COMMAND_SYNC:
self::$syncWorker->Sync();
break;
case self::COMMAND_SYNC_ONE:
self::$syncWorker->SyncOne(self::$uniqueId);
break;
case self::COMMAND_CLEARALL:
echo "Are you sure you want to remove all chunks and data from the public folder. ALL GAB data will be removed from ALL KOE instances [y/N]: ";
$confirm = strtolower(trim(fgets(STDIN)));
if ( $confirm === 'y' || $confirm === 'yes')
self::$syncWorker->ClearAll();
else
echo "Aborted!".PHP_EOL;
break;
case self::COMMAND_DELETEALL:
echo "Are you sure you want to remove all chunks and data from the public folder and delete it? ALL GAB data will be removed from ALL KOE instances [y/N]: ";
$confirm = strtolower(trim(fgets(STDIN)));
if ( $confirm === 'y' || $confirm === 'yes')
self::$syncWorker->DeleteAll();
else
echo "Aborted!".PHP_EOL;
break;
}
echo PHP_EOL;
}
}
\ No newline at end of file
<?php
/***********************************************
* File : gabentry.php
* Project : Z-Push - tools - GAB sync
* Descr : Data class for a GAB entry.
*
* Created : 28.01.2016
*
* Copyright 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
* ************************************************/
class GABEntry {
const CONTACT = "contact";
const GROUP = "group";
const ROOM = "room";
const EQUIPMENT = "equipment";
public $type; // contact, group, room or equipment
public $memberOf; // groups the item is a member of
public $members; // if this is a group, a list of its members
// GABEntry variable MAPI Property Default LDAP parameter
public $account; // PR_ACCOUNT username
public $displayName; // PR_DISPLAY_NAME
public $givenName; // PR_GIVEN_NAME givenName
public $surname; // PR_SURNAME sn
public $smtpAddress; // PR_SMTP_ADDRESS Email
public $title; // PR_TITLE title
public $companyName; // PR_COMPANY_NAME
public $officeLocation; // PR_OFFICE_LOCATION physicalDeliveryOfficeName
public $businessTelephoneNumber; // PR_BUSINESS_TELEPHONE_NUMBER
public $mobileTelephoneNumber; // PR_MOBILE_TELEPHONE_NUMBER mobile
public $homeTelephoneNumber; // PR_HOME_TELEPHONE_NUMBER Telephone
public $beeperTelephoneNumber; // PR_BEEPER_TELEPHONE_NUMBER pager
public $primaryFaxNumber; // PR_PRIMARY_FAX_NUMBER Fax
public $organizationalIdNumber; // PR_ORGANIZATIONAL_ID_NUMBER employeeNumber
public $postalAddress; // PR_POSTAL_ADDRESS postalAddress
public $businessAddressCity; // PR_BUSINESS_ADDRESS_CITY location
public $businessAddressPostalCode; // PR_BUSINESS_ADDRESS_POSTAL_CODE postalCode
public $businessAddressPostOfficeBox; // PR_BUSINESS_ADDRESS_POST_OFFICE_BOX postBoxOffice
public $businessAddressStateOrProvince; // PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE st
public $initials; // PR_INITIALS initials
public $language; // PR_LANGUAGE preferredLanguage
public $thumbnailPhoto; // PR_EMS_AB_THUMBNAIL_PHOTO jpegPhoto
// TODO
//PR_CHILDRENS_NAMES PT_MV_UNICODE o
}
\ No newline at end of file
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