Page MenuHomePhorge

No OneTemporary

Size
23 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/init.php b/lib/init.php
index e41bdca..8a96b68 100644
--- a/lib/init.php
+++ b/lib/init.php
@@ -1,120 +1,121 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| 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/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
// Roundcube Framework constants
define('RCMAIL_START', microtime(true));
define('RCMAIL_VERSION', '0.9-git');
define('RCMAIL_CHARSET', 'UTF-8');
define('INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/');
define('RCMAIL_CONFIG_DIR', INSTALL_PATH . 'config');
+define('RCMAIL_PLUGINS_DIR', INSTALL_PATH . 'plugins');
// PHP configuration
$config = array(
'error_reporting' => E_ALL &~ (E_NOTICE | E_STRICT),
'mbstring.func_overload' => 0,
// 'suhosin.session.encrypt' => 0,
// 'session.auto_start' => 0,
// 'file_uploads' => 1,
'magic_quotes_runtime' => 0,
'magic_quotes_sybase' => 0,
);
foreach ($config as $optname => $optval) {
if ($optval != ini_get($optname) && @ini_set($optname, $optval) === false) {
die("ERROR: Wrong '$optname' option value!");
}
}
// Define include path
$include_path = INSTALL_PATH . 'lib' . PATH_SEPARATOR;
$include_path .= INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR;
$include_path .= INSTALL_PATH . 'lib/kolab' . PATH_SEPARATOR;
$include_path .= INSTALL_PATH . 'lib/ext/Roundcube' . PATH_SEPARATOR;
$include_path .= ini_get('include_path');
set_include_path($include_path);
// @TODO: what is a reasonable value for ActiveSync?
@set_time_limit(600);
// set internal encoding for mbstring extension
if (extension_loaded('mbstring')) {
mb_internal_encoding(RCMAIL_CHARSET);
@mb_regex_encoding(RCMAIL_CHARSET);
}
// include global functions from Roundcube Framework
require_once 'rcube_shared.inc';
// Register main autoloader
spl_autoload_register('kolab_sync_autoload');
// set PEAR error handling (will also load the PEAR main class)
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
// Autoloader for Syncroton
//require_once 'Zend/Loader/Autoloader.php';
//$autoloader = Zend_Loader_Autoloader::getInstance();
//$autoloader->setFallbackAutoloader(true);
/**
* Use PHP5 autoload for dynamic class loading
*/
function kolab_sync_autoload($classname)
{
// Roundcube Framework
$filename = preg_replace(
array(
'/Mail_(.+)/',
'/Net_(.+)/',
'/Auth_(.+)/',
'/^html_.+/',
'/^utf8$/',
),
array(
'Mail/\\1',
'Net/\\1',
'Auth/\\1',
'html',
'utf8.class',
),
$classname
);
if ($fp = @fopen("$filename.php", 'r', true)) {
fclose($fp);
include_once "$filename.php";
return true;
}
// Syncroton, replacement for Zend autoloader
$filename = str_replace('_', DIRECTORY_SEPARATOR, $classname);
if ($fp = @fopen("$filename.php", 'r', true)) {
fclose($fp);
include_once "$filename.php";
return true;
}
return false;
}
diff --git a/lib/kolab_sync.php b/lib/kolab_sync.php
index f34df68..ab0e3d5 100644
--- a/lib/kolab_sync.php
+++ b/lib/kolab_sync.php
@@ -1,335 +1,314 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| 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/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
/**
* Main application class (based on Roundcube Framework)
*/
class kolab_sync extends rcube
{
/**
* Application name
*
* @var string
*/
public $app_name = 'ActiveSync for Kolab'; // no double quotes inside
/**
* Current user
*
* @var rcube_user
*/
public $user;
- private $data = array();
-
const CHARSET = 'UTF-8';
- const VERSION = "1.1";
+ const VERSION = "2.0";
/**
* 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
$debug_mode = $this->config->get('activesync_debug') ? kolab_sync_logger::DEBUG : kolab_sync_logger::WARN;
$this->logger = new kolab_sync_logger($debug_mode);
+
+ // Get list of plugins
+ // WARNING: We can use only plugins that are prepared for this
+ // e.g. are not using output or rcmail objects or
+ // doesn't throw errors when using them
+ $plugins = (array)$this->config->get('activesync_plugins');
+
+ // Initialize/load plugins
+ $this->plugins = kolab_sync_plugin_api::get_instance();
+ $this->plugins->init($this, $this->task);
+ $this->plugins->load_plugins($plugins);
}
/**
* Application execution (authentication and ActiveSync)
*/
public function run()
{
+ $this->plugins->exec_hook('startup', array('task' => 'login'));
+
// 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::set(Syncroton_Registry::POLICYBACKEND, new kolab_sync_backend_policy);
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::setGALDataClass('kolab_sync_data_gal');
// Run Syncroton
$syncroton = new Syncroton_Server($userid);
$syncroton->handle();
}
/**
- * Authenticates a user in LDAP and Roundcube
+ * Authenticates a user
+ *
+ * @param string $username User name
+ * @param string $password User password
+ *
+ * @param int User ID
*/
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)
- {
- @include_once(RCMAIL_CONFIG_DIR . "/kolab_auth.inc.php");
-
- $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)) {
- $this->logger->warn("No address book configured to authenticate the user.");
- return null;
+ $auth = $this->plugins->exec_hook('authenticate', array(
+ 'host' => $this->select_host($username),
+ 'user' => $username,
+ 'pass' => $password,
+ 'valid' => true,
+ ));
+
+ // Authenticate - get Roundcube user ID
+ if ($auth['valid'] && !$auth['abort']
+ && ($userid = $this->login($auth['user'], $auth['pass'], $auth['host']))) {
+ return $userid;
}
- if (empty($login_attr)) {
- $this->logger->warn("No login attribute configured.");
- 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];
- }
+ $this->plugins->exec_hook('login_failed', array(
+ 'host' => $auth['host'],
+ 'user' => $auth['user'],
+ ));
}
/**
- * Prepares filter query for LDAP search
+ * Storage host selection
*/
- private function parse_vars($str, $user, $host)
+ private function select_host($username)
{
- $domain = $this->config->get('username_domain');
+ // Get IMAP host
+ $host = $this->config->get('default_host');
+
+ if (is_array($host)) {
+ list($user, $domain) = explode('@', $username);
+
+ // try to select host by mail domain
+ if (!empty($domain)) {
+ foreach ($host as $storage_host => $mail_domains) {
+ if (is_array($mail_domains) && in_array_nocase($domain, $mail_domains)) {
+ $host = $storage_host;
+ break;
+ }
+ else if (stripos($storage_host, $domain) !== false || stripos(strval($mail_domains), $domain) !== false) {
+ $host = is_numeric($storage_host) ? $mail_domains : $storage_host;
+ break;
+ }
+ }
+ }
- 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);
+ // take the first entry if $host is not found
+ if (is_array($host)) {
+ list($key, $val) = each($default_host);
+ $host = is_numeric($key) ? $val : $key;
+ }
}
- // 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);
+ return rcube_utils::parse_host($host);
}
/**
- * Returns Roundcube user ID for specified username and host.
- * Also sets IMAP connection credentials.
+ * Authenticates a user in IMAP and returns Roundcube user ID.
*/
- private function get_rcube_user($username, $password, $host)
+ private function login($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) {
if ($login_lc == 2 || $login_lc === true) {
$username = mb_strtolower($username);
}
else if (strpos($username, '@')) {
// lowercase domain name
list($local, $domain) = explode('@', $username);
$username = $local . '@' . mb_strtolower($domain);
}
}
// Here we need IDNA ASCII
// Only rcube_contacts class is using domain names in Unicode
$host = rcube_utils::idn_to_ascii($host);
$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;
$username = $user->data['username'];
// authenticate user in IMAP
$storage = $this->get_storage();
if (!$storage->connect($host, $username, $password, $port, $ssl)) {
return null;
}
// overwrite config with user preferences
$this->config->set_user_prefs((array)$this->user->get_prefs());
$this->set_storage_prop();
setlocale(LC_ALL, 'en_US.utf8', 'en_US.UTF-8');
// force reloading of mailboxes list/data
//$storage->clear_cache('mailboxes', true);
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['QUERY_STRING'] . ($mem ? " [$mem]" : '');
+ $query = $_SERVER['QUERY_STRING'];
+ $log = $query . ($mem ? ($query ? ' ' : '') . "[$mem]" : '');
+
if (defined('RCMAIL_START'))
self::print_timer(RCMAIL_START, $log);
else
self::console($log);
}
}
}
diff --git a/lib/kolab_sync_plugin_api.php b/lib/kolab_sync_plugin_api.php
new file mode 100644
index 0000000..1b7bac4
--- /dev/null
+++ b/lib/kolab_sync_plugin_api.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ +--------------------------------------------------------------------------+
+ | Kolab Sync (ActiveSync for Kolab) |
+ | |
+ | Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
+ | |
+ | This program is free software: you can redistribute it and/or modify |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 of the License, or |
+ | (at your option) any later version. |
+ | |
+ | 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/> |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak@kolabsys.com> |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * The plugin loader and global API
+ *
+ * @package PluginAPI
+ */
+class kolab_sync_plugin_api extends rcube_plugin_api
+{
+ /**
+ * This implements the 'singleton' design pattern
+ *
+ * @return rcube_plugin_api The one and only instance if this class
+ */
+ static function get_instance()
+ {
+ if (!self::$instance) {
+ self::$instance = new kolab_sync_plugin_api();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Initialize plugin engine
+ *
+ * This has to be done after rcmail::load_gui() or rcmail::json_init()
+ * was called because plugins need to have access to rcmail->output
+ *
+ * @param object rcube Instance of the rcube base class
+ * @param string Current application task (used for conditional plugin loading)
+ */
+ public function init($app, $task = '')
+ {
+ $this->task = $task;
+ }
+
+
+ /**
+ * Register a handler function for template objects
+ *
+ * @param string $name Object name
+ * @param string $owner Plugin name that registers this action
+ * @param mixed $callback Callback: string with global function name or array($obj, 'methodname')
+ */
+ public function register_handler($name, $owner, $callback)
+ {
+ // empty
+ }
+
+
+ /**
+ * Register this plugin to be responsible for a specific task
+ *
+ * @param string $task Task name (only characters [a-z0-9_.-] are allowed)
+ * @param string $owner Plugin name that registers this action
+ */
+ public function register_task($task, $owner)
+ {
+ $this->tasks[$task] = $owner;
+ }
+
+
+ /**
+ * Include a plugin script file in the current HTML page
+ *
+ * @param string $fn Path to script
+ */
+ public function include_script($fn)
+ {
+ //empty
+ }
+
+
+ /**
+ * Include a plugin stylesheet in the current HTML page
+ *
+ * @param string $fn Path to stylesheet
+ */
+ public function include_stylesheet($fn)
+ {
+ //empty
+ }
+}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Mar 19, 1:32 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
458661
Default Alt Text
(23 KB)

Event Timeline