gunnar: server/php-kolab/Kolab_Freebusy/Freebusy Cache.php, NONE, 1.1 Page.php, NONE, 1.1 domxml-php4-to-php5.php, 1.1, NONE freebusy.class.php, 1.5, NONE freebusycache.class.php, 1.2, NONE freebusycollector.class.php, 1.2, NONE freebusyimapcache.class.php, 1.2, NONE freebusyldap.class.php, 1.2, NONE freebusyldap_dummy.class.php, 1.2, NONE misc.php, 1.2, NONE recurrence.class.php, 1.3, NONE
cvs at kolab.org
cvs at kolab.org
Thu Nov 22 17:53:07 CET 2007
Author: gunnar
Update of /kolabrepository/server/php-kolab/Kolab_Freebusy/Freebusy
In directory doto:/tmp/cvs-serv2216/Freebusy
Added Files:
Cache.php Page.php
Removed Files:
domxml-php4-to-php5.php freebusy.class.php
freebusycache.class.php freebusycollector.class.php
freebusyimapcache.class.php freebusyldap.class.php
freebusyldap_dummy.class.php misc.php recurrence.class.php
Log Message:
Fully restructured the perl package. Implements the newest free/busy concepts.
--- NEW FILE: Cache.php ---
<?php
/*
* COPYRIGHT
* ---------
*
* See ../AUTHORS file
*
*
* LICENSE
* -------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision: 1.1 $
*
* ABOUT
* -----
*
* This provides the necessary utilities to handle the file based
* free/busy cache.
*
*/
/* We require the iCalendar library to build the free/busy list */
require_once 'Horde/iCalendar.php';
require_once 'Horde/iCalendar/vfreebusy.php';
class FreeBusyCache {
var $_cache_dir;
function FreeBusyCache($cache_dir)
{
$this->_cache_dir = $cache_dir;
}
function store($access)
{
$folder = $this->_getFolder($access);
/* Now we really need the free/busy library */
require_once('Horde/Kolab/Freebusy.php');
$fb = &new Horde_Kolab_Freebusy();
$result = $fb->connect($folder);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$vCal = $fb->generate(null, null, $access->fbpast, $access->fbfuture,
$access->owner);
if (is_a($vCal, 'PEAR_Error')) {
$vCal;
}
$fbfilename = $this->_getFilename($folder, $access->owner);
$c_pvcal = &new FreeBusyCacheFile_pvcal($this->_cache_dir, $fbfilename);
$c_acl = &new FreeBusyCacheFile_acl($this->_cache_dir, $fbfilename);
$c_xacl = &new FreeBusyCacheFile_xacl($this->_cache_dir, $fbfilename);
/* missing data means delete the cache files */
if (empty($vCal)) {
Horde::logMessage(sprintf(_("No events. Purging cache %s."),
$fbfilename),
__FILE__, __LINE__, PEAR_LOG_DEBUG);
$result = $c_pvcal->purge();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$result = $c_acl->purge();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$result = $c_xacl->purge();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
} else {
$result = $c_pvcal->storePVcal($vCal);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$relevance = $fb->getRelevance();
if (is_a($relevance, 'PEAR_Error')) {
$relevance;
}
$acl = $fb->getACL();
if (is_a($acl, 'PEAR_Error')) {
$acl;
}
$result = $c_acl->storeACL($acl, $relevance);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$xacl = $fb->getExtendedACL();
if (is_a($xacl, 'PEAR_Error')) {
$xacl;
}
/* The owner may always look at the extended attributes */
$xacl .= ' ' . $access->owner;
$result = $c_xacl->storeXACL($xacl);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
Horde::logMessage(sprintf(_("FreeBusyCache::store(file=%s, relevance=%s, acl=%s, xacl=%s)"),
$fbfilename, $relevance, $acl, $xacl),
__FILE__, __LINE__, PEAR_LOG_DEBUG);
}
}
function &loadPartial(&$access, $extended)
{
$folder = $this->_getFolder($access);
$file = $this->_getFilename($folder, $access->owner);
$aclcache = &FreeBusyCacheDB_acl::singleton('acl', $this->_cache_dir);
$relevant = false;
foreach ($access->groups as $id) {
if ($aclcache->has($file, $id)) {
$relevant = true;
break;
}
}
if (!$relevant) {
return PEAR::raiseError(sprintf(_("Folder %s is irrelevant for user %s."),
$folder, $access->user));
}
if ($extended) {
$extended = $this->_allowExtended($file, $access);
}
$c_pvcal = &new FreeBusyCacheFile_pvcal($this->_cache_dir, $file);
$pvCal = $c_pvcal->loadPVcal($extended);
if (is_a($pvCal, 'PEAR_Error')) {
return $pvCal;
}
return $pvCal;
}
function &load(&$access, $extended)
{
/* Which files will we access? */
$aclcache = &FreeBusyCacheDB_acl::singleton('acl', $this->_cache_dir);
$files = array();
foreach ($access->groups as $id) {
$add = $aclcache->get($id);
if (is_a($add, 'PEAR_Error')) {
return $add;
}
$files = array_unique(array_merge($files, $add));
}
$filesnames = array();
$c_file = $this->_getFilename($access->user, $access->owner);
$c_vcal = &new FreeBusyCacheFile_vcal($this->_cache_dir, $c_file);
/* If the current vCal cache did not expire, we can deliver it */
if (!$c_vcal->expired($files)) {
$vCal = $c_vcal->loadVcal();
if (is_a($vCal, 'PEAR_Error')) {
return $vCal;
}
return $vCal;
}
// Create the new iCalendar.
$vCal = &new Horde_iCalendar();
$vCal->setAttribute('PRODID', '-//proko2//freebusy 1.0//EN');
$vCal->setAttribute('METHOD', 'PUBLISH');
// Create new vFreebusy.
$vFb = &Horde_iCalendar::newComponent('vfreebusy', $vCal);
$vFb->setAttribute('ORGANIZER', 'MAILTO:' . $access->owner);
$vFb->setAttribute('DTSTAMP', time());
$vFb->setAttribute('URL', 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']);
$mtimes = array();
foreach ($files as $file) {
if ($extended) {
$extended = $this->_allowExtended($file, $access);
}
$c_pvcal = &new FreeBusyCacheFile_pvcal($this->_cache_dir, $file);
$pvCal = $c_pvcal->loadPVcal($extended);
if (is_a($pvCal, 'PEAR_Error')) {
Horde::logMessage(sprintf(_("Ignoring partial free/busy file %s: %s)"),
$file, $pvCal->getMessage()),
__FILE__, __LINE__, PEAR_LOG_INFO);
continue;
}
$pvFb = &$pvCal->findComponent('vfreebusy');
if( !$pvFb ) {
Horde::logMessage(sprintf(_("Could not find free/busy info in file %s.)"),
$file), __FILE__, __LINE__, PEAR_LOG_INFO);
continue;
}
if ($ets = $pvFb->getAttributeDefault('DTEND', false) !== false) {
// PENDING(steffen): Make value configurable
if ($ets < time()) {
Horde::logMessage(sprintf(_("Free/busy info in file %s is too old.)"),
$file), __FILE__, __LINE__, PEAR_LOG_INFO);
$c_pvcal->purge();
continue;
}
}
$vFb->merge($pvFb);
/* Store last modification time */
$mtimes[$file] = $c_pvcal->getMtime();
}
if (!(boolean)$vFb->getBusyPeriods()) {
/* No busy periods in fb list. We have to add a
* dummy one to be standards compliant
*/
$vFb->setAttribute('COMMENT', 'This is a dummy vfreebusy that indicates an empty calendar');
$vFb->addBusyPeriod('BUSY', 0,0, null);
}
$vCal->addComponent($vFb);
$c_vcal->storeVcal($vCal, $mtimes);
return $vCal;
}
function _allowExtended($file, &$access)
{
$xaclcache = &FreeBusyCacheDB_xacl::singleton('xacl', $this->_cache_dir);
foreach ($access->groups as $id) {
if ($xaclcache->has($file, $id)) {
return true;
}
}
Horde::logMessage(sprintf(_("Extended attributes on folder %s disallowed for user %s."),
$access->folder, $access->user), __FILE__, __LINE__, PEAR_LOG_DEBUG);
return false;
}
/*************** Private API below this line *************/
function _getFilename($folder, $owner)
{
if (ereg('(.*)@(.*)', $owner, $regs)) {
$owner = $regs[2] . '/' . $regs[1];
}
if ($folder) {
if (ereg('(.*)@(.*)', $folder, $regs)) {
$folder = $regs[2] . '/' . $regs[1];
}
$filename = $owner . '/' . $folder;
}
return str_replace("\0", '', str_replace('.', '^', $filename));
}
function _getFolder($access)
{
$userdom = false;
$ownerdom = false;
if (ereg( '(.*)@(.*)', $access->user, $regs)) {
// Regular user
$user = $regs[1];
$userdom = $regs[2];
}
if(ereg( '(.*)@(.*)', $access->owner, $regs)) {
// Regular owner
$owner = $regs[1];
$ownerdom = $regs[2];
}
$fldrcomp = array();
if ($user == $owner) {
$fldrcomp[] = 'INBOX';
} else {
$fldrcomp[] = 'user';
$owner[] = 'user';
}
if (!empty($access->folder)) {
$fldrcomp[] = $access->folder;
}
$folder = join('/', $fldrcomp);
if ($ownerdom && !$userdom) {
$folder .= '@' . $ownerdom;
}
return $folder;
}
};
class FreeBusyCacheDB {
var $_cache_dir;
var $_db;
var $_dbformat;
var $_type = '';
function FreeBusyCacheDB($cache_dir) {
global $conf;
$this->_cache_dir = $cache_dir;
if (!empty($conf['fb']['dbformat'])) {
$this->_dbformat = $conf['fb']['dbformat'];
} else {
$this->_dbformat = 'db4';
}
/* make sure that a database really exists before accessing it */
if (!file_exists($this->_cache_dir . '/' . $this->_type . 'cache.db')) {
$result = $this->_open();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$this->_close();
}
}
function _open()
{
if ($this->_db) {
return;
}
$dbfile = $this->_cache_dir . '/' . $this->_type . 'cache.db';
$this->_db = @dba_open($dbfile, 'cd', $this->_dbformat);
if ($this->_db === false) {
return PEAR::raiseError(sprintf(_("Unable to open freebusy cache db %s"), $dbfile));
}
}
function _close()
{
@dba_close($this->_db);
$this->_db = null;
}
function _remove($filename, $uid)
{
$result = $this->_open();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
if (dba_exists($uid, $this->_db)) {
$lst = dba_fetch($uid, $this->_db);
$lst = split(',', $lst);
$lst = array_diff($lst, array($filename));
$result = dba_replace($uid, join(',', $lst), $this->_db);
if ($result === false) {
return PEAR::raiseError(sprintf(_("Unable to set db value for uid %s"), $uid));
}
}
}
function _add($filename, $uid)
{
$result = $this->_open();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
if (dba_exists($uid, $this->_db)) {
$lst = dba_fetch($uid, $this->_db);
$lst = split(',', $lst);
$lst[] = $filename;
$result = dba_replace($uid, join(',', array_unique($lst)), $this->_db);
if ($result === false) {
return PEAR::raiseError(sprintf(_("Unable to set db value for uid %s"), $uid));
}
} else {
$result = dba_insert($uid, $filename, $this->_db);
if ($result === false) {
return PEAR::raiseError(sprintf(_("Unable to set db value for uid %s"), $uid));
}
}
}
function has($filename, $uid)
{
$result = $this->_open();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
if (dba_exists($uid, $this->_db)) {
$lst = dba_fetch($uid, $this->_db);
$lst = split(',', $lst);
return in_array($filename, $lst);
}
return false;
}
function get($uid)
{
$result = $this->_open();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
if (dba_exists($uid, $this->_db)) {
$lst = dba_fetch($uid, $this->_db);
return split(',', $lst);
}
return array();
}
/**
* Attempts to return a reference to a concrete FreeBusyACLCache
* instance. It will only create a new instance if no
* FreeBusyACLCache instance currently exists.
*
* This method must be invoked as:
* <code>$var = &FreeBusyACLCache::singleton($cache_dir);</code>
*
* @static
*
* @param string $type The type of the cache.
* @param string $cache_dir The directory for storing the cache.
*
* @return FreeBusyACLCache The concrete FreeBusyACLCache
* reference, or false on an error.
*/
function &singleton($type, $cache_dir)
{
static $cachedb = array();
$signature = $type . $cache_dir;
if (empty($cachedb[$signature])) {
$class = 'FreeBusyCacheDB_' . $type;
$cachedb[$signature] = &new $class($cache_dir);
}
return $cachedb[$signature];
}
}
class FreeBusyCacheDB_acl extends FreeBusyCacheDB {
var $_type = 'acl';
function store($filename, $acl, $oldacl, $perm)
{
/* We remove the filename from all users listed in the old ACL first */
foreach ($oldacl as $ac) {
$result = $this->_remove($filename, $ac[0]);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
/* Now add the filename for all users with the correct permissions */
if ($perm !== false ) {
foreach ($acl as $user => $ac) {
if (strpos($ac, $perm) !== false) {
if (!empty($user)) {
$result = $this->_add($filename, $user);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
}
}
}
$this->_close();
}
}
class FreeBusyCacheDB_xacl extends FreeBusyCacheDB {
var $_type = 'xacl';
function store($filename, $xacl, $oldxacl)
{
$xacl = split(' ', $xacl);
$oldxacl = split(' ', $oldxacl);
$both = array_intersect($xacl, $oldxacl);
/* Removed access rights */
foreach (array_diff($oldxacl, $both) as $uid) {
if (!empty($uid)) {
$result = $this->_remove($filename, $uid);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
}
/* Added access rights */
foreach (array_diff($xacl, $both) as $uid) {
if (!empty($uid)) {
$result = $this->_add($filename, $uid);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
}
$this->_close();
}
}
class FreeBusyCacheFile {
var $_suffix = '';
var $_filename;
var $_file;
var $_version = 1;
function FreeBusyCacheFile($cache_dir, $filename, $suffix = null)
{
if (!empty($suffix)) {
$this->_suffix = $suffix;
}
$this->_cache_dir = $cache_dir;
$this->_filename = $filename;
$this->_file = $this->_cache_dir . '/' . $this->_filename . '.' . $this->_suffix;
}
function purge()
{
if (file_exists($this->_file)) {
$result = @unlink($this->_file);
if (!$result) {
return PEAR::raiseError(sprintf(_("Failed removing file %s"),
$this->_file));
}
}
}
function store(&$data)
{
/* Create directories if missing */
$fbdirname = dirname($this->_file);
if (!is_dir($fbdirname)) {
$result = $this->_makeTree($fbdirname);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
/* Store the cache data */
$fh = fopen($this->_file, 'w');
if (!$fh) {
return PEAR::raiseError(sprintf(_("Failed creating cache file %s!"),
$this->_file));
}
fwrite($fh, serialize(array('version' => $this->_version,
'data' => $data)));
fclose($fh);
}
function &load()
{
$file = @file_get_contents($this->_file);
if ($file === false) {
return PEAR::raiseError(sprintf(_("%s failed reading cache file %s!"),
get_class($this), $this->_file));
}
$cache = @unserialize($file);
if ($cache === false) {
return PEAR::raiseError(sprintf(_("%s failed to unserialize cache data from file %s!"),
get_class($this), $this->_file));
}
if (!isset($cache['version'])) {
return PEAR::raiseError(sprintf(_("Cache file %s lacks version data!"),
$this->_file));
}
if (!isset($cache['data'])) {
return PEAR::raiseError(sprintf(_("Cache file %s lacks data!"),
$this->_file));
}
if ($cache['version'] != $this->_version) {
return PEAR::raiseError(sprintf(_("Cache file %s has version %s while %s is required!"),
$this->_file, $cache['version'], $this->_version));
}
return $cache['data'];
}
function _maketree($dirname)
{
$base = substr($dirname, 0, strrpos($dirname, '/'));
$base = str_replace(".", "^", $base);
if (!empty($base) && !is_dir($base)) {
$result = $this->_maketree($base);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
if (!file_exists($dirname)) {
$result = @mkdir($dirname, 0755);
if (!$result) {
return PEAR::raiseError(sprintf(_("Error creating directory %s"), $dirname));
}
}
}
}
class FreeBusyCacheFile_pvcal extends FreeBusyCacheFile {
var $_suffix = 'pvc';
function storePVcal(&$pvcal)
{
return $this->store($pvcal);
}
function &loadPVcal($extended)
{
$pvcal = $this->load();
if (is_a($pvcal, 'PEAR_Error')) {
return $pvcal;
}
if (!$extended) {
$components = &$pvcal->getComponents();
foreach ($components as $component) {
if ($component->getType() == 'vFreebusy') {
$component->_extraParams = array();
}
}
}
return $pvcal;
}
function getMtime()
{
return filemtime($this->_file);
}
}
class FreeBusyCacheFile_vcal extends FreeBusyCacheFile {
var $_suffix = 'vc';
var $_data;
function storeVcal(&$vcal, &$mtimes)
{
$data = array('vcal' => $vcal,
'mtimes' => $mtimes);
return $this->store($data);
}
function &loadVcal()
{
if ($this->_data) {
return $this->_data;
}
$result = $this->load();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$this->_data = $result['vcal'];
return $this->_data;
}
function expired($files)
{
$result = $this->load();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$this->_data = $result['vcal'];
/* Files changed? */
$keys = array_keys($result['mtimes']);
$changes = array_diff($keys, $files);
if (!empty($changes)) {
return true;
}
/* Check the file ctimes */
foreach ($files as $file) {
if (filemtime($this->_cache_dir . '/' . $file) != $result['mtimes'][$file]) {
return true;
}
}
/* Older than three days? */
$components = $this->_data->getComponents();
foreach ($components as $component) {
if ($component->getType() == 'vFreebusy') {
$attr = $component->getAttribute('DTSTAMP');
if (!empty($attr) && !is_a($attr, 'PEAR_Error')) {
//Should be configurable
if (time() - (int)$attr > 259200) {
return true;
}
}
}
}
return false;
}
}
class FreeBusyCacheFile_acl extends FreeBusyCacheFile {
var $_suffix = 'acl';
var $_acls;
function FreeBusyCacheFile_acl($cache_dir, $filename)
{
$this->_acls = &FreeBusyCacheDB::singleton('acl', $cache_dir);
parent::FreeBusyCacheFile($cache_dir, $filename, 'acl');
}
function purge()
{
$oldacl = $this->load();
if (is_a($oldacl, 'PEAR_Error')) {
$oldacl = array();
}
$result = $this->_acls->store($this->_filename, array(), $oldacl, false);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
return parent::purge();
}
function storeACL(&$acl, $relevance)
{
$oldacl = $this->load();
if (is_a($oldacl, 'PEAR_Error')) {
$oldacl = array();
}
/* Handle relevance */
switch ($relevance) {
case 'readers':
$perm = 'r';
break;
case 'nobody':
$perm = false;
break;
case 'admins':
default:
$perm = 'a';
}
$result = $this->_acls->store($this->_filename, $acl, $oldacl, $perm);
if (is_a($oldacl, 'PEAR_Error')) {
return $oldacl;
}
$result = $this->store($acl);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
}
class FreeBusyCacheFile_xacl extends FreeBusyCacheFile {
var $_suffix = 'xacl';
var $_xacls;
function FreeBusyCacheFile_xacl($cache_dir, $filename)
{
$this->_xacls = &FreeBusyCacheDB::singleton('xacl', $cache_dir);
parent::FreeBusyCacheFile($cache_dir, $filename, 'xacl');
}
function purge()
{
$oldxacl = $this->load();
if (is_a($oldxacl, 'PEAR_Error')) {
$oldxacl = '';
}
$result = $this->_xacls->store($this->_filename, '', $oldxacl);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
return parent::purge();
}
function storeXACL(&$xacl)
{
$oldxacl = $this->load();
if (is_a($oldxacl, 'PEAR_Error')) {
$oldxacl = '';
}
$result = $this->_xacls->store($this->_filename, $xacl, $oldxacl);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
$result = $this->store($xacl);
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
}
?>
--- NEW FILE: Page.php ---
<?php
/*
* COPYRIGHT
* ---------
*
* See docs/AUTHORS file
*
*
* LICENSE
* -------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision: 1.1 $
*
* ABOUT
* -----
*
* This provides error pages for the Kolab free/busy system.
*
*/
/* Load the required PEAR libraries */
require_once 'PEAR.php';
/* Load the required Horde libraries */
require_once 'Horde.php';
require_once "Horde/String.php";
require_once "Horde/Util.php";
require_once "Horde/Kolab/LDAP.php";
/**
* The Kolab_Freebusy_Error:: class provides error pages for the
* Kolab free/busy system.
*
* @author Gunnar Wrobel <p at rdus.de>
* @author Steffen Hansen <steffen at klaralvdalens-datakonsult.se>
* @package Kolab_Freebusy
*/
class Kolab_Freebusy_Error {
/**
* Deliver a "Not Found" page
*
* @param PEAR_Error $error The error.
*/
function notFound($error)
{
$headers = array('HTTP/1.0 404 Not Found');
$url = htmlentities($_SERVER['REQUEST_URI']);
$message = sprintf(_("The requested URL %s was not found on this server."), $url);
Kolab_Freebusy_Error::_errorPage($error, $headers, _("404 Not Found"), _("Not found"), $message);
}
/**
* Deliver a "Unauthorized" page
*
* @param PEAR_Error $error The error.
*/
function unauthorized($error) {
global $conf;
if (!empty($conf['fb']['email_domain'])) {
$email_domain = $conf['fb']['email_domain'];
} else {
$email_domain = 'localhost';
}
$headers = array('WWW-Authenticate: Basic realm="freebusy-' . $email_domain . '"',
'HTTP/1.0 401 Unauthorized');
Kolab_Freebusy_Error::_errorPage($error, $headers, _("401 Unauthorized"), _("Unauthorized"),
_("You are not authorized to access the requested URL."));
}
/**
* Deliver a "Server Error" page
*
* @param PEAR_Error $error The error.
*/
function serverError($error) {
$headers = array('HTTP/1.0 500 Server Error');
Kolab_Freebusy_Error::_errorPage($error, $headers, _("500 Server Error"), _("Error"),
htmlentities($_SERVER['REQUEST_URI']));
}
/**
* Deliver an error page
*
* @param PEAR_Error $error The error.
* @param array $headers The HTTP headers to deliver with the response
* @param string $title The page title
* @param string $headline The headline of the page
* @param string $body The message to display on the page
*/
function _errorPage($error, $headers, $title, $headline, $body) {
/* Print the headers */
foreach ($headers as $line) {
header($line);
}
/* Print the page */
echo "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n";
echo "<html><head><title>" . $title . "</title></head>\n";
echo "<body>\n";
echo "<h1>" . $headline . "</h1>\n";
echo "<p>" . $body . "</p>\n";
if (!empty($error)) {
echo "<hr><pre>" . $error->getMessage() . "</pre>\n";
Horde::logMessage($error, __FILE__, __LINE__, PEAR_LOG_ERR);
}
echo "<hr>\n";
echo $_SERVER['SERVER_SIGNATURE'] . "\n";
echo "</body></html>\n";
exit;
}
}
/**
* The Timer:: class provides a high precision timer for calculating
* page generation time.
*
* @author Gunnar Wrobel <p at rdus.de>
* @author Steffen Hansen <steffen at klaralvdalens-datakonsult.se>
* @package Kolab_Freebusy
*/
class Timer
{
var $_start;
function Timer()
{
$this->_start = $this->_microtime_float();
}
function stop()
{
return $this->_microtime_float() - $this->_start;
}
function _microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return (float) $usec + (float) $sec;
}
}
/**
* The FolderAccess:: class provides functionality to check free/busy
* access rights for the specified folder.
*
* @author Gunnar Wrobel <p at rdus.de>
* @author Steffen Hansen <steffen at klaralvdalens-datakonsult.se>
* @package Kolab_Freebusy
*/
class FolderAccess {
/**
* The user calling the script
*
* @var string
*/
var $user;
/**
* The password of the user calling the script
*
* @var string
*/
var $pass;
/**
* The folder we try to access
*
* @var string
*/
var $folder;
/**
* The requested owner
*
* @var string
*/
var $req_owner;
/**
* The owner of that folder
*
* @var string
*/
var $owner;
/**
* The homeserver for that folder
*
* @var string
*/
var $homeserver;
/**
* The groups of the user calling the script (this includes the
* primary user id)
*
* @var string
*/
var $groups;
/**
* The number of days to calculate free/busy into the past
*
* @var int
*/
var $fbpast;
/**
* The number of days to calculate free/busy into the future
*
* @var int
*/
var $fbfuture = 60;
function FolderAccess()
{
$this->_parseUser();
}
function parseFolder($req_folder = '')
{
/* Handle the owner/folder name and make sure the owner part is in lower case */
$req_folder = String::convertCharset($req_folder, 'UTF-8', 'UTF7-IMAP');
$folder = explode('/', $req_folder);
if (count($folder) < 2) {
return PEAR::raiseError(sprintf(_("No such folder %s"), $req_folder));
}
$folder[0] = strtolower($folder[0]);
$req_folder = implode('/', $folder);
$this->req_owner = $folder[0];
unset($folder[0]);
$this->folder = join('/', $folder);
$result = $this->_process();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
function parseOwner($req_owner = '')
{
$this->req_owner = $req_owner;
$result = $this->_process();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
function fetchRemote()
{
global $conf;
if (!empty($conf['fb']['server'])) {
$server = $conf['fb']['server'];
} else {
$server = 'localhost';
}
if (!empty($conf['fb']['redirect'])) {
$do_redirect = $conf['fb']['redirect'];
} else {
$do_redirect = false;
}
/* Check if we are on the right server and redirect if appropriate */
if ($this->homeserver && $this->homeserver != $server) {
$redirect = 'https://' . $this->homeserver . $_SERVER['REQUEST_URI'];
Horde::logMessage(sprintf(_("Found remote user, redirecting to %s"),
$this->homeserver), __FILE__, __LINE__, PEAR_LOG_ERR);
if ($do_redirect) {
header("Location: $redirect");
} else {
header("X-Redirect-To: $redirect");
$redirect = 'https://' . urlencode($this->user) . ':' . urlencode($this->pass)
. '@' . $this->homeserver . $_SERVER['REQUEST_URI'];
if (!@readfile($redirect)) {
$message = sprintf(_("Unable to read free/busy information from %s"),
'https://' . urlencode($this->user) . ':XXX'
. '@' . $this->homeserver . $_SERVER['REQUEST_URI']);
return PEAR::raiseError($message);
}
}
exit;
}
}
function authenticate()
{
if (empty($this->user)) {
return PEAR::raiseError(_("Please authenticate!"));
}
/* Load the authentication libraries */
require_once "Horde/Auth.php";
require_once 'Horde/Secret.php';
$auth = &Auth::singleton('kolab');
if (!$auth->authenticate($this->user, array('password' => $this->pass), false)) {
return PEAR::raiseError(sprintf(_("Invalid Kolab authentication for user %s!"),
$this->user));
}
session_start();
$_SESSION['__auth'] = array(
'authenticated' => true,
'userId' => $this->user,
'timestamp' => time(),
'remote_addr' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null,
);
Auth::setCredential('password', $this->pass);
}
function _parseUser()
{
$this->user = isset($_SERVER['PHP_AUTH_USER'])?$_SERVER['PHP_AUTH_USER']:false;
$this->pass = isset($_SERVER['PHP_AUTH_PW'])?$_SERVER['PHP_AUTH_PW']:false;
// This part allows you to use the PHP scripts with CGI rather than as
// an apache module. This will of course slow down things but on the
// other hand it allows you to reduce the memory footprint of the
// apache server. The default is to use PHP as a module and the CGI
// version requires specific Apache configuration.
//
// The line you need to add to your configuration of the /freebusy
// location of your server looks like this:
//
// RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
//
// The complete section will probably look like this then:
//
// <IfModule mod_rewrite.c>
// RewriteEngine On
// # FreeBusy list handling
// RewriteBase /freebusy
// RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
// RewriteRule ^([^/]+)\.ifb freebusy.php?uid=$1 [L]
// RewriteRule ^([^/]+)\.vfb freebusy.php?uid=$1 [L]
// RewriteRule ^([^/]+)\.xfb freebusy.php?uid=$1&extended=1 [L]
// RewriteRule ^trigger/(.+)\.pfb pfb.php?folder=$1&cache=0 [L]
// RewriteRule ^(.+)\.pfb pfb.php?folder=$1&cache=1 [L]
// RewriteRule ^trigger/(.+)\.xpfb pfb.php?folder=$1&cache=0&extended=1 [L]
// RewriteRule ^(.+)\.xpfb pfb.php?folder=$1&cache=1&extended=1 [L]
// </IfModule>
if (empty($this->user) && isset($_ENV['REDIRECT_REDIRECT_REMOTE_USER'])) {
$a = base64_decode(substr($_ENV['REDIRECT_REDIRECT_REMOTE_USER'], 6)) ;
if ((strlen($a) != 0) && (strcasecmp($a, ":" ) == 0)) {
list($this->user, $this->pass) = explode(':', $a, 2);
}
}
}
function _process()
{
/* Bind to LDAP so that we can request user data */
$ldap = Horde_Kolab_LDAP::singleton();
if (!$ldap->is_bound) {
$result = $ldap->bind();
if (is_a($result, 'PEAR_Error')) {
return $result;
}
}
/* Does not really belong here but since we are connected now,
we should fetch that config info */
$this->fbpast = $ldap->freeBusyPast();
/* Fetch the user info of the calling user */
$userinfo = $ldap->userInfo($this->user);
if (is_a($userinfo, 'PEAR_Error')) {
Horde::logMessage($userinfo, __FILE__, __LINE__, PEAR_LOG_ERROR);
$userinfo = null;
}
/* Possibly rewrite the calling UID into the primary mail address */
if ($userinfo && isset($userinfo['MAIL']) && !empty($userinfo['MAIL'])) {
$this->user = $userinfo['MAIL'];
}
/* Fetch the user info of the requested folder owner */
$uinfo = $ldap->userInfo($this->req_owner);
if (is_a($uinfo, 'PEAR_Error')) {
Horde::logMessage($uinfo, __FILE__, __LINE__, PEAR_LOG_ERROR);
$uinfo = null;
}
/* Possibly rewrite the owner UID into the primary mail address */
if (!empty($uinfo) && isset($uinfo['MAIL']) && !empty($uinfo['MAIL'])) {
$this->owner = $userinfo['MAIL'];
}
/* If we were unable to determine the owner we will finally
* try to append the domain name of the calling user. */
if (empty($uinfo) || empty($this->owner) ||
strpos($this->owner, '@') === false) {
/* try guessing the domain */
$idx = strpos($this->user, '@');
if($idx !== false) {
$domain = substr($this->user, $idx+1);
Horde::logMessage(sprintf(_("Trying to append %s to %s"),
$domain, $this->req_owner),
__FILE__, __LINE__, PEAR_LOG_DEBUG);
$uinfo = $ldap->userInfo($this->req_owner . '@' . $domain);
if (is_a($uinfo, 'PEAR_Error')) {
Horde::logMessage($uinfo, __FILE__, __LINE__, PEAR_LOG_ERROR);
$uinfo = null;
}
}
}
/* Get the owner mail address and the home server */
if ($uinfo) {
if (!empty($uinfo['MAIL'])) {
$this->owner = $uinfo['MAIL'];
}
if (!empty($uinfo['HOMESERVER'])) {
$this->homeserver = $uinfo['HOMESERVER'];
}
if (!empty($uinfo['FBFUTURE'])) {
$this->fbfuture = $uinfo['FBFUTURE'];
}
if (!empty($uinfo['GROUPS'])) {
$this->groups = $uinfo['GROUPS'];
}
}
if (empty($this->groups)) {
$this->groups = array($this->user);
} else {
$this->groups[] = $this->user;
}
}
}
class FreeBusyView {
var $_vfb;
function FreeBusyView($vfb)
{
$this->_vfb = $vfb->exportvCalendar();
$ts = time();
$components = &$vfb->getComponents();
foreach ($components as $component) {
if ($component->getType() == 'vFreebusy') {
$attr = $component->getAttribute('DTSTAMP');
if (!empty($attr) && !is_a($attr, 'PEAR_Error')) {
$ts = $attr;
break;
}
}
}
$this->_ts = $ts;
}
function render($content = '')
{
global $conf;
if (!empty($conf['fb']['send_content_type'])) {
$send_content_type = $conf['fb']['send_content_type'];
} else {
$send_content_type = false;
}
if (!empty($conf['fb']['send_content_length'])) {
$send_content_length = $conf['fb']['send_content_length'];
} else {
$send_content_length = false;
}
if (!empty($conf['fb']['send_content_disposition'])) {
$send_content_disposition = $conf['fb']['send_content_disposition'];
} else {
$send_content_disposition = false;
}
/* Ensure that the data doesn't get cached along the way */
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $this->_ts) . ' GMT');
header('Pragma: public');
header('Content-Transfer-Encoding: none');
if ($send_content_type) {
header('Content-Type: text/calendar');
}
if ($send_content_length) {
header('Content-Length: ' . strlen($this->_vfb));
}
if ($send_content_disposition) {
header('Content-Disposition: attachment; filename="' . $content . '"');
}
echo $this->_vfb;
}
}
--- domxml-php4-to-php5.php DELETED ---
--- freebusy.class.php DELETED ---
--- freebusycache.class.php DELETED ---
--- freebusycollector.class.php DELETED ---
--- freebusyimapcache.class.php DELETED ---
--- freebusyldap.class.php DELETED ---
--- freebusyldap_dummy.class.php DELETED ---
--- misc.php DELETED ---
--- recurrence.class.php DELETED ---
More information about the commits
mailing list