Page MenuHomePhorge

No OneTemporary

Size
17 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/kolab_sync.php b/lib/kolab_sync.php
index 6f015c1..d412262 100644
--- a/lib/kolab_sync.php
+++ b/lib/kolab_sync.php
@@ -1,307 +1,307 @@
<?php
/**
* Main application class (based on Roundcube Framework)
*/
class kolab_sync extends rcube
{
public $app_name = 'ActiveSync for Kolab'; // no double quotes inside
private $data = array();
const CHARSET = 'UTF-8';
/**
* This implements the 'singleton' design pattern
*
* @return kolab_sync The one and only instance
*/
static function get_instance()
{
if (!self::$instance || !is_a(self::$instance, 'kolab_sync')) {
self::$instance = new kolab_sync();
self::$instance->startup(); // init AFTER object was linked with self::$instance
}
return self::$instance;
}
public function startup()
{
// Initialize Syncroton Logger
$this->logger = new Zend_Log();
if ($this->config->get('activesync_debug')) {
$priority = Zend_Log::DEBUG;
$log_file = 'logs/console';
}
else {
$priority = Zend_Log::ERR; // Zend_Log::WARN
$log_file = 'logs/errors';
}
$writer = new Zend_Log_Writer_Stream($log_file);
$filter = new Zend_Log_Filter_Priority($priority);
$this->logger->addWriter($writer);
$this->logger->addFilter($filter);
}
/**
* Application execution (authentication and ActiveSync)
*/
public function run()
{
// when used with (f)cgi no PHP_AUTH* variables are available without defining a special rewrite rule
if (!isset($_SERVER['PHP_AUTH_USER'])) {
// "Basic didhfiefdhfu4fjfjdsa34drsdfterrde..."
if (isset($_SERVER["REMOTE_USER"])) {
$basicAuthData = base64_decode(substr($_SERVER["REMOTE_USER"], 6));
} elseif (isset($_SERVER["REDIRECT_REMOTE_USER"])) {
$basicAuthData = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6));
} elseif (isset($_SERVER["Authorization"])) {
$basicAuthData = base64_decode(substr($_SERVER["Authorization"], 6));
} elseif (isset($_SERVER["HTTP_AUTHORIZATION"])) {
$basicAuthData = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6));
}
if (isset($basicAuthData) && !empty($basicAuthData)) {
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(":", $basicAuthData);
}
}
if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
// Convert domain.tld\username into username@domain (?)
$username = explode("\\", $_SERVER['PHP_AUTH_USER']);
if (count($username) == 2) {
$_SERVER['PHP_AUTH_USER'] = $username[1];
if (!strpos($_SERVER['PHP_AUTH_USER'], '@') && !empty($username[0])) {
$_SERVER['PHP_AUTH_USER'] .= '@' . $username[0];
}
}
$userid = $this->authenticate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
}
if (empty($userid)) {
header('WWW-Authenticate: Basic realm="' . $this->app_name .'"');
header('HTTP/1.1 401 Unauthorized');
exit;
}
// Register Syncroton backends
Syncroton_Registry::set('loggerBackend', $this->logger);
Syncroton_Registry::set(Syncroton_Registry::DATABASE, new kolab_sync_db);
Syncroton_Registry::set(Syncroton_Registry::TRANSACTIONMANAGER, kolab_sync_transaction_manager::getInstance());
Syncroton_Registry::set(Syncroton_Registry::DEVICEBACKEND, new kolab_sync_backend_device);
Syncroton_Registry::set(Syncroton_Registry::FOLDERBACKEND, new kolab_sync_backend_folder);
Syncroton_Registry::set(Syncroton_Registry::SYNCSTATEBACKEND, new kolab_sync_backend_state);
Syncroton_Registry::set(Syncroton_Registry::CONTENTSTATEBACKEND, new kolab_sync_backend_content);
Syncroton_Registry::setContactsDataClass('kolab_sync_data_contacts');
Syncroton_Registry::setCalendarDataClass('kolab_sync_data_calendar');
Syncroton_Registry::setEmailDataClass('kolab_sync_data_email');
-// Syncroton_Registry::setTasksDataClass('kolab_sync_data_tasks');
+ Syncroton_Registry::setTasksDataClass('kolab_sync_data_tasks');
// Run Syncroton
$syncroton = new Syncroton_Server($userid);
$syncroton->handle();
}
/**
* Authenticates a user in LDAP and Roundcube
*/
public function authenticate($username, $password)
{
// Get IMAP host
$host = $this->config->get('default_host');
$host = rcube_utils::parse_host($host);
// Get user
$user = $this->get_ldap_user($username, $host);
// Get Roundcube user ID
$userid = $this->get_rcube_user($user, $password, $host);
return $userid;
}
/**
* Returns user login attribute from LDAP server
*/
private function get_ldap_user($username, $host)
{
$login_attr = $this->config->get('kolab_auth_login');
$addressbook = $this->config->get('kolab_auth_addressbook');
$filter = $this->config->get('kolab_auth_filter');
$filter = $this->parse_vars($filter, $username, $host);
if (!is_array($addressbook)) {
$ldap_config = (array)$this->config->get('ldap_public');
$addressbook = $ldap_config[$addressbook];
}
if (empty($addressbook)) {
return null;
}
if (empty($login_attr)) {
return null;
}
$addressbook['filter'] = $filter;
$addressbook['sizelimit'] = 2;
$this->ldap = new rcube_ldap(
$addressbook,
$this->config->get('ldap_debug'),
$this->config->mail_domain($host)
);
if (!$this->ldap->ready) {
return null;
}
// get record
$results = $this->ldap->list_records();
if (count($results->records) != 1) {
return null;
}
if ($record = $results->records[0]) {
return is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr];
}
}
/**
* Prepares filter query for LDAP search
*/
private function parse_vars($str, $user, $host)
{
$domain = $this->config->get('username_domain');
if (!empty($domain) && strpos($user, '@') === false) {
if (is_array($domain) && isset($domain[$host]))
$user .= '@'.rcube_utils::parse_host($domain[$host], $host);
else if (is_string($domain))
$user .= '@'.rcube_utils::parse_host($domain, $host);
}
// replace variables in filter
list($u, $d) = explode('@', $user);
$dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string
$replaces = array('%dc' => $dc, '%d' => $d, '%fu' => $user, '%u' => $u);
return strtr($str, $replaces);
}
/**
* Returns Roundcube user ID for specified username and host.
* Also sets IMAP connection credentials.
*/
private function get_rcube_user($username, $password, $host)
{
if (empty($username)) {
return null;
}
$login_lc = $this->config->get('login_lc');
// parse $host
$a_host = parse_url($host);
if ($a_host['host']) {
$host = $a_host['host'];
$ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null;
if (!empty($a_host['port'])) {
$port = $a_host['port'];
}
else if ($ssl && $ssl != 'tls' && (!$config['default_port'] || $config['default_port'] == 143)) {
$port = 993;
}
}
if (!$port) {
$port = $this->config->get('default_port');
}
// Convert username to lowercase. If storage backend
// is case-insensitive we need to store always the same username
if ($login_lc) {
$username = mb_strtolower($username);
}
// Here we need IDNA ASCII
// Only rcube_contacts class is using domain names in Unicode
$host = rcube_utils::idn_to_ascii($host);
if (strpos($username, '@')) {
// lowercase domain name
list($local, $domain) = explode('@', $username);
$username = $local . '@' . mb_strtolower($domain);
$username = rcube_utils::idn_to_ascii($username);
}
// user already registered?
$user = rcube_user::query($username, $host);
if (!is_object($user)) {
// @TODO: log error
return null;
}
// Configure environment
$this->user = $user;
// rcube::get_storage() uses session, kolab-sync doesn't
// @TODO: modify framework to support private class variables
// or other method to provide storage credentials
global $_SESSION;
$_SESSION['storage_host'] = $host;
$_SESSION['username'] = $username;
$_SESSION['storage_port'] = $port;
$_SESSION['storage_ssl'] = $ssl;
$_SESSION['password'] = $this->encrypt($password);
// $this->set_storage_prop();
// force reloading complete list of subscribed mailboxes
// $storage->clear_cache('mailboxes', true);
// overwrite config with user preferences
$this->config->set_user_prefs((array)$this->user->get_prefs());
return $user->ID;
}
/**
* Function to be executed in script shutdown
*/
public function shutdown()
{
parent::shutdown();
if ($this->ldap) {
$this->ldap->close();
}
// write performance stats to logs/console
if ($this->config->get('devel_mode')) {
if (function_exists('memory_get_usage'))
$mem = sprintf('%.1f', memory_get_usage() / 1048576);
if (function_exists('memory_get_peak_usage'))
$mem .= '/' . sprintf('%.1f', memory_get_peak_usage() / 1048576);
$log = $_SERVER['REQUEST_URI'] . ($mem ? " [$mem]" : '');
if (defined('RCMAIL_START'))
self::print_timer(RCMAIL_START, $log);
else
self::console($log);
}
}
}
diff --git a/lib/kolab_sync_data_tasks.php b/lib/kolab_sync_data_tasks.php
new file mode 100644
index 0000000..626dfb6
--- /dev/null
+++ b/lib/kolab_sync_data_tasks.php
@@ -0,0 +1,229 @@
+<?php
+
+/**
+ *
+ */
+class kolab_sync_data_tasks extends kolab_sync_data
+{
+ /**
+ * Mapping from ActiveSync Calendar namespace fields
+ */
+ protected $mapping = array(
+ 'Body' => 'description',
+ 'Categories' => 'categories',
+ //'Complete' => 'complete', // handled separately
+ 'DateCompleted' => 'changed',
+ 'DueDate' => 'due',
+ 'Importance' => 'priority',
+ //'Recurrence' => 'recurrence',
+ //'ReminderSet' => 'reminderset',
+ //'ReminderTime' => 'remindertime',
+ 'Sensitivity' => 'sensitivity',
+ 'StartDate' => 'start',
+ 'Subject' => 'title',
+ 'UtcDueDate' => 'due',
+ 'UtcStartDate' => 'start',
+ );
+
+ /**
+ * Sensitivity values
+ */
+ const SENSITIVITY_NORMAL = 0;
+ const SENSITIVITY_PERSONAL = 1;
+ const SENSITIVITY_PRIVATE = 2;
+ const SENSITIVITY_CONFIDENTIAL = 3;
+
+ /**
+ * mapping of sensitivity
+ *
+ * @var array
+ */
+ protected $sensitivityMap = array(
+ 'public' => self::SENSITIVITY_PERSONAL,
+ 'private' => self::SENSITIVITY_PRIVATE,
+ 'confidential' => self::SENSITIVITY_CONFIDENTIAL,
+ );
+
+
+ /**
+ * Kolab object type
+ *
+ * @var string
+ */
+ protected $modelName = 'task';
+
+ /**
+ * Type of the default folder
+ *
+ * @var int
+ */
+ protected $defaultFolderType = Syncroton_Command_FolderSync::FOLDERTYPE_TASK;
+
+ /**
+ * Default container for new entries
+ *
+ * @var string
+ */
+ protected $defaultFolder = 'Tasks';
+
+ /**
+ * Type of user created folders
+ *
+ * @var int
+ */
+ protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_TASK_USER_CREATED;
+
+ /**
+ * Default namespace
+ *
+ * @var string
+ */
+ protected $defaultNS = 'Tasks';
+
+ /**
+ * Field to sort search results by
+ *
+ * @var string
+ */
+ protected $sortField = 'n_fileas';
+
+
+ /**
+ * Appends contact data to xml element
+ *
+ * @param Syncroton_Model_SyncCollection $collection Collection data
+ * @param string $serverId Local entry identifier
+ */
+ public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId)
+ {
+ $task = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId);
+ $config = $this->getFolderConfig($task['_mailbox']);
+ $result = array();
+
+ // Completion status (required)
+ $result['Complete'] = intval(!empty($task['status']) && $task['status'] == 'COMPLETED');
+
+ // Calendar namespace fields
+ foreach ($this->mapping as $key => $name) {
+ $value = $this->getKolabDataItem($task, $name);
+
+ switch ($name) {
+ case 'due':
+ case 'start':
+ if (preg_match('/^UTC/i', $key)) {
+ $value = self::date_from_kolab($value);
+ }
+ break;
+
+ case 'changed':
+ $value = $result['Complete'] ? self::date_from_kolab($value) : null;
+ break;
+
+ case 'description':
+ $value = $this->setBody($value);
+ break;
+
+ case 'sensitivity':
+ $value = intval($this->sensitivityMap[$value]);
+ break;
+
+ case 'priority':
+ // ActiveSync has only 3 levels of importance:
+ // 0 - Low, 1 - Normal, 2 - High
+ // but Kolab uses ten levels:
+ // 0 - unknown and 1-9 where 1 is the highest
+ if ($value) {
+ $result['Importance'] = $value > 5 ? 2 : 0;
+ }
+ break;
+ }
+
+ if (empty($value) || is_array($value)) {
+ continue;
+ }
+
+ $result[$key] = $value;
+ }
+
+ // Recurrence
+ $result['Recurrence'] = $this->recurrence_from_kolab($task, 'Task');
+
+ return new Syncroton_Model_Task($result);
+ }
+
+ /**
+ * convert contact from xml to libkolab array
+ *
+ * @param Syncroton_Model_IEntry $data Contact to convert
+ * @param string $folderid Folder identifier
+ * @param array $entry Existing entry
+ *
+ * @return array
+ */
+ public function toKolab(Syncroton_Model_IEntry $data, $folderid, $entry = null)
+ {
+ $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid);
+ $task = !empty($entry) ? $entry : array();
+ $config = $this->getFolderConfig($foldername);
+
+ $task['allday'] = 0;
+
+ // Calendar namespace fields
+ foreach ($this->mapping as $key => $name) {
+ $value = $data->$key;
+
+ switch ($name) {
+ case 'sensitivity':
+ $map = array_flip($this->sensitivityMap);
+ $value = $map[$value];
+ break;
+
+ case 'description':
+ $value = $this->getBody($value);
+ break;
+
+ case 'priority':
+ if ($value !== null) {
+ if ($value == 1) {
+ $task['priority'] = 0;
+ }
+ else {
+ $task['priority'] = !$value ? 9 : 1;
+ }
+ }
+ break;
+ }
+
+ $this->setKolabDataItem($task, $name, $value);
+ }
+
+ if (!empty($data->Complete)) {
+ $task['status'] = 'COMPLETED';
+ $task['complete'] = 100;
+ }
+
+ // recurrence
+ $task['recurrence'] = $this->recurrence_to_kolab($data);
+
+ return $task;
+ }
+
+
+ /**
+ * Returns filter query array according to specified ActiveSync FilterType
+ *
+ * @param int $filter_type Filter type
+ *
+ * @param array Filter query
+ */
+ protected function filter($filter_type = 0)
+ {
+ $filter = array();
+
+ if ($filter_type == Syncroton_Command_Sync::FILTER_INCOMPLETE) {
+ $filter[] = array('tags', '!~', 'x-complete');
+ }
+
+ return $filter;
+ }
+}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Apr 19, 1:12 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
435924
Default Alt Text
(17 KB)

Event Timeline