martin: server/kolab-resource-handlers freebusy-imap-caching.patch, NONE, 1.1
cvs at intevation.de
cvs at intevation.de
Sun Jun 19 17:25:31 CEST 2005
Author: martin
Update of /kolabrepository/server/kolab-resource-handlers
In directory doto:/tmp/cvs-serv14350
Added Files:
freebusy-imap-caching.patch
Log Message:
Martin Konold: Post 2.0 code change! Basically this adds the the imap/uid mapping with a persistent cache for the result.
- add imapcache and imapuid parameters to function FreeBusyRecurrance()
- add cachedir parameter to function FreeBusy()
- change from PEAR/IMAP to c-client in imapConnect()
- change from PEAR/IMAP to c-client in imapDisconnect()
- change from PEAR/IMAP to c-client in imapOpenMailbox()
- change from PEAR/IMAP to c-client in imap_reopen()
- change from PEAR/IMAP to c-client in getACL()
- change from PEAR/IMAP to c-client in getRelevance()
- change from PEAR/IMAP to c-client in class FreeBusy
- add caching to class FreeBusy
Kudos to Thomas Jarosch for contributing the nice and clean implementation!
--- NEW FILE: freebusy-imap-caching.patch ---
diff -u -r -p --new-file freebusy.clean/freebusy.class.php freebusy/freebusy.class.php
--- freebusy.clean/freebusy.class.php Wed Jan 26 05:49:33 2005
+++ freebusy/freebusy.class.php Mon Jun 13 14:28:31 2005
@@ -1,8 +1,9 @@
<?php
/*
- * Copyright (c) 2004 Klaraelvdalens Datakonsult AB
+ * Copyright (c) 2004-2005 Klaraelvdalens Datakonsult AB, Intra2net AG
*
* Written by Steffen Hansen <steffen at klaralvdalens-datakonsult.se>
+ * Thomas Jarosch <thomas.jarosch at intra2net.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -18,75 +19,104 @@
* Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.
*/
+ /*
+ TODO: Looks like we don't get called for deleted folders.
+ Best thing would be to have a cron script which deletes
+ unmodified pfbs/caches after 2 months.
+ */
+
+
+require_once 'freebusy/freebusycache.class.php';
+require_once 'freebusy/freebusyimapcache.class.php';
require_once 'freebusy/recurrence.class.php';
class FreeBusyRecurrence extends Recurrence {
- function FreeBusyRecurrence( &$vfb, &$extra ) {
+ function FreeBusyRecurrence( &$imapcache, &$imapuid, &$vfb, &$extra ) {
+ $this->imapcache =& $imapcache;
+ $this->imapuid =& $imapuid;
$this->vfb =& $vfb;
$this->extra =& $extra;
}
function setBusy( $start, $end, $duration ) {
- $this->vfb->addBusyPeriod('BUSY', $start, null, $duration, $this->extra);
+ $this->imapcache->add_imap2fb($this->imapuid, $start, null, $duration, $this->extra);
}
+ var $imapcache;
var $vfb;
var $extra;
};
class FreeBusy {
- function FreeBusy( $username,
+ function FreeBusy( $cache_dir,
+ $username,
$password,
$imaphost,
+ $imapoptions,
$fbfuture=60,
$fbpast=0 ) {
+ $this->cache_dir = $cache_dir;
$this->username = $username;
$this->password = $password;
$this->imaphost = $imaphost;
+ $this->imapoptions = $imapoptions;
$this->fbfuture = $fbfuture;
$this->fbpast = $fbpast;
+
+ $this->relevance = null;
}
function imapConnect() {
- require_once('Net/IMAP.php');
- $this->imap = &new Net_IMAP( $this->imaphost, $this->imapport );
- #$this->imap->setDebug(true);
+ $this->imap_serverstring = "{".$this->imaphost.":".$this->imapport.$this->imapoptions."}";
+ $this->imap = imap_open( $this->imap_serverstring, $this->username, $this->password );
return $this->imap;
}
function imapDisconnect() {
- return $this->imap->disconnect();
- }
-
- function imapLogin() {
- return $this->imap->login($this->username,$this->password, true, false);
+ return imap_close($this->imap);
}
function imapOpenMailbox($foldername = 'INBOX') {
$this->foldername = $foldername;
- $rc = $this->imap->selectMailbox( $foldername );
- $a = $this->imap->getAnnotation( '/vendor/kolab/folder-type', '*' );
+
+ $rc = imap_reopen($this->imap, $this->imap_serverstring . $this->foldername);
+ // PHP only returns false for imap_reopen() if we use an HALF_OPEN connection. doh!
+ if (imap_last_error() !== false)
+ $rc = false;
+
+ // $a = $this->imap->getAnnotation( '/vendor/kolab/folder-type', '*' );
//myLog( "$folder has annotation: ".print_r($a,true), RM_LOG_DEBUG);
+
return $rc;
}
function getACL() {
- return $this->imap->getACL();
+ $imap_acls = imap_getacl($this->imap, $this->foldername);
+
+ $rtn = array();
+ while (list($user, $rights) = each($imap_acls))
+ $rtn[] = array("USER" => $user, "RIGHTS" => $rights);
+
+ return $rtn;
}
function getRelevance() {
- $val = $this->imap->getAnnotation( '/vendor/kolab/incidences-for', 'value.shared' );
- if( PEAR::isError($val) || empty($val) ) {
+ // cached?
+ if (isset($this->relevance))
+ return $this->relevance;
+
+ $val = imap_getannotation( $this->imap, $this->foldername, '/vendor/kolab/incidences-for', 'value.shared' );
+ if( $val === false || empty($val) ) {
myLog("No /vendor/kolab/incidences-for found for ".$this->foldername, RM_LOG_DEBUG);
- return 'admins';
+ $this->relevance = "admins";
} else {
myLog("/vendor/kolab/incidences-for = ".print_r($val,true)." for ".$this->foldername, RM_LOG_DEBUG);
- return $val;
}
+
+ return $this->relevance;
}
function &generateFreeBusy($startstamp = NULL, $endstamp = NULL ) {
-
require_once 'PEAR.php';
require_once 'Horde/iCalendar.php';
require_once 'Horde/MIME.php';
@@ -102,7 +132,7 @@ class FreeBusy {
$startstamp = strtotime( '-'.$this->fbpast.' days', mktime(0, 0, 0, $month, $day, $year) );
}
- // Default the end date to the start date + freebusy_days.
+ // Default the end date to the start date + fbfuture.
if (is_null($endstamp) || $endstamp < $startstamp) {
$endstamp = strtotime( '+'.$this->fbfuture.' days', $startstamp );
}
@@ -124,7 +154,9 @@ class FreeBusy {
// URL is not required, so out it goes...
//$vFb->setAttribute('URL', 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']);
- if( $this->imap->getNumberOfMessages() == 0 ) {
+ $status = imap_status_current($this->imap, SA_MESSAGES | SA_UIDVALIDITY | SA_UIDNEXT);
+
+ if( $status->messages == 0 ) {
$vFb->setAttribute('DTSTART', 0, array(), false );
$vFb->setAttribute('DTEND', 0, array(), false );
$vFb->setAttribute('COMMENT', 'This is a dummy vfreebusy that indicates an empty calendar');
@@ -137,13 +169,50 @@ class FreeBusy {
$vCal->addComponent($vFb);
return array($vCal->exportvCalendar(),$vCal->exportvCalendar());
}
- $messages = $this->imap->getMessages();
- if( PEAR::isError( $messages ) ) return array( $messages, null);
- foreach ($messages as $textmsg) {
+
+ // This only happens in php standalone mode and is needed
+ // to make the debug log quiet
+ if (!isset($_SERVER["SERVER_NAME"]))
+ $_SERVER["SERVER_NAME"] = "localhost";
+
+ $imapcache = new FreeBusyIMAPCache($this->cache_dir."/", $this->username, $this->foldername);
+ $imapcache->cache_load();
+
+ $uids = imap_search($this->imap, "UNDELETED", SE_UID);
+
+ if ($imapcache->check_folder_changed($status->uidvalidity, $status->uidnext, $this->getRelevance(), $uids)) {
+ reset ($uids);
+ while(list($key, $uid) = each($uids))
+ if (!$imapcache->check_uid_exists($uid))
+ $this->process_imap_message($imapcache, $uid, $startstamp, $endstamp);
+ }
+
+ // store cache and output free busy list
+ $imapcache->cache_store();
+ $imapcache->output_fb($vFb);
+
+ $xvCal = $vCal;
+ $xvCal->addComponent($vFb);
+ $vCal->addComponent($this->clearExtra($vFb));
+
+ // Generate the vCal file.
+ return array( $vCal->exportvCalendar(), $xvCal->exportvCalendar() );
+ }
+
+ /********************** Private API below this line ********************/
+
+ function process_imap_message(&$imapcache, &$imapuid, &$startstamp, &$endstamp)
+ {
+ myLog("Processing new message $imapuid", RM_LOG_DEBUG);
+ $imapcache->add_empty_imap2fb($imapuid);
+
+ $textmsg = imap_fetchheader($this->imap, $imapuid, FT_UID).imap_body($this->imap, $imapuid, FT_UID);
+
$mimemsg = &MIME_Structure::parseTextMIMEMessage($textmsg);
// Read in a Kolab event object, if one exists
$parts = $mimemsg->contentTypeMap();
+
$event = false;
foreach ($parts as $mimeid => $conttype) {
if ($conttype == 'application/x-vnd.kolab.event') {
@@ -159,23 +228,16 @@ class FreeBusy {
if ($event === false) {
myLog("No x-vnd.kolab.events at all ", RM_LOG_DEBUG);
- continue;
+ return;
}
-
+
$uid = $event['uid'];
- /*
- // See if we need to ignore this event
- if (isset($params['ignore'][$uid])) {
- trigger_error("Ignoring event with uid=$uid", E_USER_NOTICE);
- continue;
- }
- */
if( array_key_exists( 'show-time-as', $event ) &&
strtolower(trim($event['show-time-as'])) == 'free' ) {
- continue;
+ return;
}
-
+
$summary = ($event['sensitivity'] == 'public' ? $event['summary'] : '');
//myLog("Looking at message with uid=$uid and summary=$summary", RM_LOG_DEBUG);
@@ -194,11 +256,11 @@ class FreeBusy {
if( !empty($event['scheduling-id']) ) {
$extra['X-SID'] = base64_encode($event['scheduling-id']);
}
-
+
if( array_key_exists( 'recurrence', $event ) ) {
myLog("Detected recurring event $uid", RM_LOG_DEBUG);
$rec = $event['recurrence'];
- $recurrence =& new FreeBusyRecurrence( $vFb, $extra );
+ $recurrence =& new FreeBusyRecurrence( $imapcache, $imapuid, $vFb, $extra );
$recurrence->setStartDate( $initial_start );
$recurrence->setEndDate( $initial_end );
$recurrence->setCycletype( $rec['cycle'] );
@@ -224,24 +286,14 @@ class FreeBusy {
// Don't bother adding the initial event if it's outside our free/busy window
if ($initial_start < $startstamp || $initial_end > $endstamp) {
- continue;
+ return;
}
-
- $vFb->addBusyPeriod('BUSY', $initial_start/* + FreeBusy::tzOffset($initial_start)*/,
- $initial_end/* + FreeBusy::tzOffset($initial_end)*/, null, $extra);
+
+ // $initial_start/* + FreeBusy::tzOffset($initial_start)
+ $imapcache->add_imap2fb($imapuid, $initial_start, $initial_end, null, $extra);
}
- }
-
- $xvCal = $vCal;
- $xvCal->addComponent($vFb);
- $vCal->addComponent($this->clearExtra($vFb));
-
- // Generate the vCal file.
- return array( $vCal->exportvCalendar(), $xvCal->exportvCalendar() );
}
-
- /********************** Private API below this line ********************/
-
+
function tzOffset( $ts ) {
$dstr = date('O',$ts);
return 3600 * substr( $dstr, 0, 3) + 60 * substr( $dstr, 3, 2);
@@ -401,11 +453,14 @@ class FreeBusy {
return $vFb;
}
+ var $cache_dir;
var $username;
var $password;
var $imaphost;
var $imapport = 143;
+ var $imapoptions;
var $foldername;
+ var $relevance;
// Settings
var $fbfuture;
@@ -414,6 +469,7 @@ class FreeBusy {
var $week_starts_on_sunday = false;
var $imap;
+ var $imap_serverstring;
};
-?>
\ No newline at end of file
+?>
diff -u -r -p --new-file freebusy.clean/freebusy.conf freebusy/freebusy.conf
--- freebusy.clean/freebusy.conf Mon May 30 17:13:44 2005
+++ freebusy/freebusy.conf Mon Jun 6 15:32:40 2005
@@ -51,3 +51,20 @@ $params['send_content_length'] = false;
// Should we send a Content-Disposition header, indicating what the name of the
// resulting VFB file should be?
$params['send_content_disposition'] = false;
+
+// Logging
+$params['log'] = "syslog:";
+$params['log_level'] = 2;
+
+// IMAP options passed to imap_open
+$params['imap_options'] = "/notls/secure/readonly";
+
+// Directory prefixes
+$params['kolab_prefix'] = "";
+$params['cache_dir'] = "/datastore/freebusy"; // default: /var/kolab/www/freebusy/cache
+
+$params['pfb_dbformat'] = ""; // default: gdbm
+
+// don't change this if you don't have to
+$params['ldap_uri'] = "";
+$params['ldap_classname_suffix'] = "_dummy";
diff -u -r -p --new-file freebusy.clean/freebusy.php freebusy/freebusy.php
--- freebusy.clean/freebusy.php Thu Dec 16 21:53:55 2004
+++ freebusy/freebusy.php Mon Jun 6 13:11:12 2005
@@ -1,8 +1,9 @@
<?php
/*
- * Copyright (c) 2004 Klaraelvdalens Datakonsult AB
+ * Copyright (c) 2004-2005 Klaraelvdalens Datakonsult AB, Intra2net AG
*
* Written by Steffen Hansen <steffen at klaralvdalens-datakonsult.se>
+ * Thomas Jarosch <thomas.jarosch at intra2net.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -18,13 +19,13 @@
* Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.
*/
+require_once('freebusy.conf');
+
require_once('freebusy/freebusycache.class.php');
require_once('freebusy/freebusycollector.class.php');
-require_once('freebusy/freebusyldap.class.php');
+require_once('freebusy/freebusyldap'.$params['ldap_classname_suffix'].'.class.php');
require_once('freebusy/misc.php');
-require_once('@l_prefix@/etc/resmgr/freebusy.conf');
-
logInit( 'freebusy' );
$user = trim($_REQUEST['uid']);
@@ -32,6 +33,14 @@ $imapuser = $_SERVER['PHP_AUTH_USER'
$imappw = $_SERVER['PHP_AUTH_PW'];
$req_cache = (bool)$_REQUEST['cache'];
$req_extended = (bool)$_REQUEST['extended'];
+/*
+// Debug test values
+$user = "groupware";
+$imapuser = "groupware";
+$imappw = "groupware";
+$req_cache = 0;
+$req_extended = 0;
+*/
myLog("---FreeBusy Script starting (".$_SERVER['REQUEST_URI'].")---", RM_LOG_DEBUG );
myLog("user=$user, imapuser=$imapuser, req_cache=$req_cache, req_extended=$req_extended", RM_LOG_DEBUG );
@@ -66,8 +75,8 @@ if( $homeserver != $params['server'] ) {
exit;
}
-
-$cache =& new FreeBusyCache( $params['kolab_prefix'].'/var/kolab/www/freebusy/cache', $req_extended );
+$full_cache_dir = $params['kolab_prefix'].$params['cache_dir'];
+$cache =& new FreeBusyCache( $full_cache_dir, $params['pfb_dbformat'], $req_extended );
$collector =& new FreeBusyCollector( $user );
$groups = $ldap->distlists( $ldap->dn( $user ) );
@@ -126,4 +135,4 @@ if ($params['send_content_disposition'])
}
echo $vfb;
-?>
\ No newline at end of file
+?>
diff -u -r -p --new-file freebusy.clean/freebusycache.class.php freebusy/freebusycache.class.php
--- freebusy.clean/freebusycache.class.php Tue Feb 22 17:38:28 2005
+++ freebusy/freebusycache.class.php Tue Jun 14 13:49:57 2005
@@ -1,8 +1,9 @@
<?php
/*
- * Copyright (c) 2004 Klaraelvdalens Datakonsult AB
+ * Copyright (c) 2004-2005 Klaraelvdalens Datakonsult AB, Intra2net AG
*
* Written by Steffen Hansen <steffen at klaralvdalens-datakonsult.se>
+ * Thomas Jarosch <thomas.jarosch at intra2net.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -21,17 +22,13 @@
/*! To load/store partial freebusy lists
and their ACLs */
class FreeBusyCache {
- function FreeBusyCache( $basedir, $extended = false ) {
+ function FreeBusyCache( $basedir, $dbformat, $extended = false ) {
$this->basedir = $basedir;
+ $this->dbformat = $dbformat;
$this->extended = $extended;
}
function store( $filename, $fbdata, $acl, $relevance ) {
- if( ereg( '\.\.', $filename ) ) {
- $this->error = $filename._(' is not absolute');
- return false;
- }
-
$fbfilename = $this->mkfbfilename($filename);
myLog("FreeBusyCache::store( file=$fbfilename, acl=[ "
.str_replace("\n",", ",$this->aclToString($acl))
@@ -40,7 +37,7 @@ class FreeBusyCache {
// false data means delete the pfb
unlink($fbfilename);
$oldacl = $this->loadACL( $filename );
- $db = dba_open( $this->basedir.'/pfbcache.db', 'cd', 'gdbm' );
+ $db = dba_open( $this->basedir.'/pfbcache.db', 'cd', $this->dbformat );
if( $db === false ) return false;
foreach( $oldacl as $ac ) {
if( dba_exists( $ac['USER'], $db ) ) {
@@ -87,7 +84,7 @@ class FreeBusyCache {
default: $perm = 'a';
}
- $db = dba_open( $this->basedir.'/pfbcache.db', 'cd', 'gdbm' );
+ $db = dba_open( $this->basedir.'/pfbcache.db', 'cd', $this->dbformat );
if( $db === false ) {
myLog('Unable to open freebusy cache db '.$this->basedir.'/pfbcache.db',
RM_LOG_ERROR );
@@ -139,7 +136,7 @@ class FreeBusyCache {
$fbfilename = $this->mkfbfilename($filename);
unlink($fbfilename);
unlink($this->mkaclfilename($filename));
- $db = dba_open( $this->basedir.'/pfbcache.db', 'cd', 'gdbm' );
+ $db = dba_open( $this->basedir.'/pfbcache.db', 'cd', $this->dbformat );
if( $db === false ) return false;
for( $uid = dba_firstkey($db); $uid !== false; $uid = dba_nextkey($db)) {
$lst = dba_fetch( $uid, $db );
@@ -153,7 +150,7 @@ class FreeBusyCache {
function findAll( $uid, $groups ) {
$lst = array();
- $db = dba_open( $this->basedir.'/pfbcache.db', 'rd', 'gdbm' );
+ $db = dba_open( $this->basedir.'/pfbcache.db', 'rd', $this->dbformat );
if( $db === false ) return false;
$uids = $groups;
for( $i = 0; $i < count($uids); $i++ ) $uids[$i] = 'group:'.$uids[$i];
@@ -169,14 +166,17 @@ class FreeBusyCache {
}
dba_close($db);
$lst = array_unique($lst);
+
myLog( "FreeBusyCache::findAll( $uid, [".join(', ', $groups).'] ) = ['.join(', ',$lst).']',
RM_LOG_DEBUG );
return $lst;
}
/*************** Private API below this line *************/
+ // a copy of this function exists in freebusyimapcache.class.php
function mkdirhier( $dirname ) {
$base = substr($dirname,0,strrpos($dirname,'/'));
+ $base = str_replace(".", "^", $base);
if( !empty( $base ) && !is_dir( $base ) ) {
if( !$this->mkdirhier( $base ) ) return false;
}
@@ -185,13 +185,13 @@ class FreeBusyCache {
}
function mkfbfilename( $fbfilename ) {
- $fbfilename = str_replace( '..', '', $fbfilename );
+ $fbfilename = str_replace( '.', '^', $fbfilename );
$fbfilename = str_replace( "\0", '', $fbfilename );
return $this->basedir.'/'.$fbfilename.($this->extended?'.xpfb':'.pfb');
}
function mkaclfilename( $fbfilename ) {
- $fbfilename = str_replace( '..', '', $fbfilename );
+ $fbfilename = str_replace( '.', '^', $fbfilename );
$fbfilename = str_replace( "\0", '', $fbfilename );
return $this->basedir.'/'.$fbfilename.($this->extended?'.xpfb':'.pfb').'.acl';
}
@@ -311,6 +311,7 @@ class FreeBusyCache {
}
var $basedir;
+ var $dbformat;
var $error;
};
diff -u -r -p --new-file freebusy.clean/freebusyimapcache.class.php freebusy/freebusyimapcache.class.php
--- freebusy.clean/freebusyimapcache.class.php Thu Jan 1 01:00:00 1970
+++ freebusy/freebusyimapcache.class.php Tue Jun 14 13:49:26 2005
@@ -0,0 +1,229 @@
+<?php
+/*
+ * Copyright (c) 2005 Intra2net AG
+ *
+ * Written by Thomas Jarosch <thomas.jarosch at intra2net.com>
+ *
+ * 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, 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 can view the GNU General Public License, online, at the GNU
+ * Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.
+ */
+
+ /* Class to efficently cache kolab events stored on an IMAP server */
+
+class FreeBusyIMAPCache
+{
+ var $version; // internal version of format
+
+ var $store_prefix; // prefix to prepend to all file operations
+ var $owner; // folder owner
+ var $foldername; // folder name
+
+ var $cache_modified; // indicates if we have to writeout the cache
+ var $cache; // cache data
+
+ function FreeBusyIMAPCache($store_prefix, &$owner, &$foldername)
+ {
+ $this->store_prefix = $store_prefix;
+ $this->owner = $owner;
+ $this->foldername = $foldername;
+
+ $this->version = 1;
+ $this->reset_cache();
+ }
+
+ function reset_cache()
+ {
+ $this->cache = array();
+
+ $this->cache["version"] = $this->version;
+ $this->cache["uidvalidity"] = -1;
+ $this->cache["uidnext"] = -1;
+ $this->cache["incidences-for"] = "";
+ $this->cache["imap2fb"] = array();
+
+ $this->cache_modified = true;
+ }
+
+ function check_folder_changed($uidvalidity, $uidnext, $incidences_for, &$new_uids)
+ {
+ $changed = false;
+
+ // uidvalidity changed?
+ if ($uidvalidity != $this->cache["uidvalidity"]) {
+ myLog("uidvalidity changed (old: ".$this->cache["uidvalidity"].", new: $uidvalidity), clearing cache", RM_LOG_DEBUG);
+ $this->reset_cache();
+ $changed = true;
+ }
+
+ // uidnext changed?
+ if ($uidnext != $this->cache["uidnext"]) {
+ myLog("uidnext on folder changed (old: ".$this->cache["uidnext"].", new: ".$uidnext.")", RM_LOG_DEBUG);
+ $changed = true;
+ }
+
+ // incidences-for changed?
+ if ($incidences_for != $this->cache["incidences-for"]) {
+ myLog("incidences-for changed (old: ".$this->cache["incidences-for"].", new: $incidences_for), clearing cache", RM_LOG_DEBUG);
+ $this->reset_cache();
+ $changed = true;
+ }
+
+ $this->cache["uidvalidity"] = $uidvalidity;
+ $this->cache["uidnext"] = $uidnext;
+ $this->cache["incidences-for"] = $incidences_for;
+
+ // deleted a message?
+ $old_uids = array_keys($this->cache["imap2fb"]);
+ while(list($key, $old_uid) = each($old_uids)) {
+ if (!in_array($old_uid, $new_uids)) {
+ unset($this->cache["imap2fb"][$old_uid]);
+ $this->cache_modified = true;
+ $changed = true;
+ }
+ }
+
+ if (!$changed)
+ myLog("check_changed: folder didn't change", RM_LOG_DEBUG);
+
+ return $changed;
+ }
+
+ function check_uid_exists($uid)
+ {
+ return array_key_exists($uid, $this->cache["imap2fb"]);
+ }
+
+ function add_empty_imap2fb(&$imap_uid)
+ {
+ $this->cache["imap2fb"][$imap_uid] = array();
+ $this->cache_modified = true;
+ }
+
+ function add_imap2fb(&$imap_uid, $fb_start, $fb_end, $fb_duration, $fb_extra)
+ {
+ /*
+ Internal imap2fb array structure:
+ 0..n IMAP uid
+ |----------- 0..n free/busy periods
+ |----------- start
+ |----------- end
+ |----------- duration
+ |----------- extra
+ */
+ myLog("added event to store: uid: $imap_uid, start: $fb_start, end: $fb_end, duration: $fb_duration", RM_LOG_DEBUG);
+
+ $store = array();
+
+ $store["start"] = $fb_start;
+ $store["end"] = $fb_end;
+ $store["duration"] = $fb_duration;
+ $store["extra"] = $fb_extra;
+
+ $this->cache["imap2fb"][$imap_uid][] = $store;
+ $this->cache_modified = true;
+ }
+
+ function output_fb(&$vFb)
+ {
+ reset($this->cache["imap2fb"]);
+ while(list($uid, $periods) = each($this->cache["imap2fb"]))
+ while(list($key, $period) = each($periods))
+ $vFb->addBusyPeriod('BUSY', $period["start"], $period["end"], $period["duration"], $period["extra"]);
+ }
+
+
+ function compute_filename()
+ {
+ $folder_parts = explode('/', $this->foldername);
+ unset($folder_parts[0]);
+ $folder_storename = join('/', $folder_parts);
+
+ $folder_storename = str_replace(".", "^", $folder_storename);
+ $folder_storename = str_replace("\0", "", $folder_storename);
+
+ $full_path = $this->store_prefix.$folder_storename.".imapcache";
+ return $full_path;
+ }
+
+ function cache_load()
+ {
+ $filename = $this->compute_filename();
+
+ myLog("Trying to load file: $filename", RM_LOG_DEBUG);
+
+ if (!is_readable($filename))
+ return false;
+
+ $this->cache = unserialize(file_get_contents($filename));
+
+ // Delete disc cache if it's from an old version
+ if ($this->cache["version"] != $this->version) {
+ myLog("Version mismatch (got: ".$this->cache["version"].", current: ".$this->version.", dropping cache", RM_LOG_WARN);
+ $this->reset_cache();
+ } else
+ $this->cache_modified = false;
+
+ return true;
+ }
+
+ function cache_store($force=false)
+ {
+ if ($this->cache_modified || $force) {
+ $filename = $this->compute_filename();
+ myLog("Trying to save cache to file: $filename", RM_LOG_DEBUG);
+
+ if (!$this->mkdirhier(dirname($filename))) {
+ myLog("can't create director hierachy: ".dirname($filename), RM_LOG_ERROR);
+ return;
+ }
+
+ $tmpname = tempnam(dirname($this->store_prefix), 'imapcache');
+ $fp = fopen($tmpname, 'w');
+ if(!$fp)
+ return false;
+
+ if (fwrite($fp, serialize($this->cache)) === false) {
+ fclose ($fp);
+ myLog("can't write to file: $tmpname. Out of discspace?", RM_LOG_ERROR);
+ return;
+ }
+
+ if(!rename($tmpname, $filename)) {
+ myLog("can't rename $tmpname to $filename", RM_LOG_ERROR);
+ return false;
+ }
+ fclose($fp);
+
+ $this->cache_modified = false;
+ } else
+ myLog("IMAPcache unmodified, not saving", RM_LOG_DEBUG);
+ }
+
+ function cache_delete()
+ {
+ unlink($this->compute_filename());
+ $this->reset_cache();
+ }
+
+ function mkdirhier( $dirname ) {
+ $base = substr($dirname,0,strrpos($dirname,'/'));
+ $base = str_replace(".", "^", $base);
+ if( !empty( $base ) && !is_dir( $base ) ) {
+ if( !$this->mkdirhier( $base ) ) return false;
+ }
+ if( !file_exists( $dirname ) ) return mkdir( $dirname, 0755 );
+ return true;
+ }
+};
+
+?>
diff -u -r -p --new-file freebusy.clean/freebusyldap_dummy.class.php freebusy/freebusyldap_dummy.class.php
--- freebusy.clean/freebusyldap_dummy.class.php Thu Jan 1 01:00:00 1970
+++ freebusy/freebusyldap_dummy.class.php Thu Jun 2 15:33:35 2005
@@ -0,0 +1,70 @@
+<?php
+/*
+ * Copyright (c) 2005 Intra2net AG
+ *
+ * Written by Thomas Jarosch <thomas.jarosch at intra2net.com>
+ *
+ * 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, 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 can view the GNU General Public License, online, at the GNU
+ * Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.
+ */
+
+class FreeBusyLDAP {
+ function FreeBusyLDAP( $uri, $base ) {
+ return true;
+ }
+
+ function error() {
+ return "LDAP::error not implemented";
+ }
+
+ function close() {
+ return true;
+ }
+
+ function bind( $dn = false , $pw = '' ) {
+ return true;
+ }
+
+ function freeBusyPast() {
+ return 0; // Default
+ }
+
+ // Return a hash of info about a user
+ function userInfo( $uid ) {
+ $rtn = array();
+
+ $rtn["MAIL"] = $uid;
+ $rtn["HOMESERVER"] = "";
+ $rtn["FBFUTURE"] = 60;
+
+ return $rtn;
+ }
+
+ function mailForUid( $uid ) {
+ return $uid;
+ }
+
+ function homeServer( $uid ) {
+ return "localhost";
+ }
+
+ function dn( $uid ) {
+ return "";
+ }
+
+ function distlists( $dn ) {
+ return array();
+ }
+};
+
+?>
diff -u -r -p --new-file freebusy.clean/pfb.php freebusy/pfb.php
--- freebusy.clean/pfb.php Tue Feb 22 17:57:15 2005
+++ freebusy/pfb.php Mon Jun 13 17:18:51 2005
@@ -1,8 +1,9 @@
<?php
/*
- * Copyright (c) 2004 Klaraelvdalens Datakonsult AB
+ * Copyright (c) 2004-2005 Klaraelvdalens Datakonsult AB, Intra2net AG
*
* Written by Steffen Hansen <steffen at klaralvdalens-datakonsult.se>
+ * Thomas Jarosch <thomas.jarosch at intra2net.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -20,12 +21,12 @@
error_reporting(E_ALL);
-require_once('freebusy/freebusyldap.class.php');
+require_once('freebusy/freebusy.conf');
+
+require_once('freebusy/freebusyldap'.$params['ldap_classname_suffix'].'.class.php');
require_once('freebusy/freebusycache.class.php');
require_once('freebusy/misc.php');
-require_once('@l_prefix@/etc/resmgr/freebusy.conf');
-
logInit('pfb');
$imapuser = isset($_SERVER['PHP_AUTH_USER'])?$_SERVER['PHP_AUTH_USER']:false;
@@ -33,7 +34,18 @@ $imappw = isset($_SERVER['PHP_AUTH
$req_cache = isset($_REQUEST['cache'])?(bool)$_REQUEST['cache']:false;
$req_folder = isset($_REQUEST['folder'])?$_REQUEST['folder']:false;
$req_extended = isset($_REQUEST['extended'])?(bool)$_REQUEST['extended']:false;
-
+// convert character encoding (stores utf7 folder names also on disc)
+require_once "Horde/Util.php";
+require_once "Horde/String.php";
+$req_folder = String::convertCharset($req_folder, "UTF-8", "UTF7-IMAP");
+/*
+// Debug test values
+$imapuser = "groupware";
+$imappw = "groupware";
+$req_cache = 0;
+$req_folder = "groupware/Kalender";
+$req_extended = 0;
+*/
myLog("pfb.php starting up: user=$imapuser, folder=$req_folder, extended=$req_extended",
RM_LOG_DEBUG);
@@ -49,7 +61,7 @@ if( $userinfo ) {
//$homeserver = $userinfo['HOMESERVER'];
}
-$folder = array_values(array_filter(explode('/', $req_folder )));
+$folder = explode('/', $req_folder);
if( count($folder) < 1 ) {
// error
notFound( _('No such folder ').htmlentities($req_folder) );
@@ -86,9 +98,11 @@ if( $homeserver && $homeserver != $param
exit;
}
-$cache =& new FreeBusyCache( $params['kolab_prefix'].'/var/kolab/www/freebusy/cache',
+$full_cache_dir = $params['kolab_prefix'] . $params['cache_dir'];
+
+$cache =& new FreeBusyCache( $full_cache_dir, $params['pfb_dbformat'],
false );
-$xcache =& new FreeBusyCache( $params['kolab_prefix'].'/var/kolab/www/freebusy/cache',
+$xcache =& new FreeBusyCache( $full_cache_dir, $params['pfb_dbformat'],
true );
if( $req_cache ) {
@@ -128,23 +142,17 @@ if( $req_cache ) {
unset($folder[0]);
$folder = join('/', $folder);
$fbpast = $ldap->freeBusyPast();
- $fb =& new FreeBusy( $imapuser, $imappw, 'localhost', $uinfo['FBFUTURE'], $fbpast );
- $fb->freebusy_days = $params['freebusy_days'];
+ $fb =& new FreeBusy( $full_cache_dir, $imapuser, $imappw, 'localhost', $params['imap_options'], $uinfo['FBFUTURE'], $fbpast );
$fb->default_domain = $params['email_domain'];
$rc = $fb->imapConnect();
- if( PEAR::isError( $rc ) ) {
- unauthorized($rc->toString());
- return false;
- }
- $rc = $fb->imapLogin();
- if( PEAR::isError( $rc ) ) {
- unauthorized("Access denied for user $imapuser: ".$rc->toString());
+ if( $rc === false ) {
+ unauthorized(imap_last_error());
return false;
}
$rc = $fb->imapOpenMailbox(FreeBusy::imapFolderName( $imapuser, $owner,
$folder, $params['email_domain']));
- if( PEAR::isError( $rc ) ) {
- notfound( "Folder: ".$fb->foldername.', '.$rc->toString());
+ if( $rc === false ) {
+ notfound( "Folder: ".$fb->foldername.', '.imap_last_error());
return false;
}
$relevance = $fb->getRelevance();
@@ -156,6 +164,7 @@ if( $req_cache ) {
}
$acl = $fb->getACL();
+
if( !$cache->store( $owner.'/'.$folder, $vfb, $acl, $relevance ) ) {
trigger_error('Could not store pfb in cache file '.$owner.'/'.$folder
.'.pfb: '.$cache->error, E_USER_WARNING);
More information about the commits
mailing list