--- webdav.php.dist	2005-11-24 11:01:16.000000000 +0100
+++ webdav.php	2005-11-24 10:55:45.000000000 +0100
@@ -0,0 +1,13 @@
+<?php
+
+@define('AUTH_HANDLER', true);
+@define('KRONOLITH_BASE', dirname(__FILE__));
+require_once KRONOLITH_BASE . '/lib/base.php';
+require_once 'Horde/Cache.php';
+require_once 'Horde/iCalendar.php';
+require_once KRONOLITH_BASE . '/lib/WebDAViCAL.php';
+
+$ical_webdav = new HTTP_WebDAV_iCal();
+$ical_webdav->ServeRequest();
+
+?>
--- lib/WebDAViCAL.php.dist	2005-11-24 11:01:25.000000000 +0100
+++ lib/WebDAViCAL.php	2005-11-24 10:57:02.000000000 +0100
@@ -0,0 +1,168 @@
+<?php
+
+include_once "Horde/RPC.php";
+include_once "Horde/RPC/webdav.php";
+
+/**
+ * WebDAV extension of the base HTTP_WebDAV_Server_Horde class.
+ *
+ * @author Dirkjan Bussink <d.bussink@student.utwente.nl>
+ * @package Kronolith
+ */
+class HTTP_WebDAV_iCal extends HTTP_WebDAV_Server_Horde {
+
+
+    /**
+     * The current calendar during the session
+     * @var     string
+     * @access  private
+     */
+    var $calendar;
+    
+    /**
+     * GET implementation.
+     *
+     * @param array &$params  Array of input and output parameters.
+     * <br><b>input</b><ul>
+     * <li> calendar - 
+     * </ul>
+     *
+     * @return integer  HTTP-Statuscode.
+     */
+    function GET(&$params)
+    {
+        global $registry, $browser;
+        
+        $this->calendar = $this->getCalendar($params);
+        $auth = $this->check_auth_calendar(PERMS_READ);
+        if(is_a($auth,'PEAR_Error')) {
+            return 400;
+        }
+        $ics = $registry->call('calendar/exportCalendar',array($this->calendar,'text/x-icalendar'));
+        $browser->downloadHeaders($this->calendar . '.ics', 'text/x-icalendar', true, strlen($ics));
+        print $ics;
+        return true;
+    }
+
+    /**
+     * PUT implementation.
+     *
+     * @param array &$params  Array of input and output parameters.
+     * <br><b>input</b><ul>
+     * <li> content_length - length of the iCal file
+     * <li> stream         - resource identifier to the iCal file
+     * </ul>
+     *
+     * @return integer  HTTP-Statuscode.
+     */
+    function PUT(&$params) 
+    {
+        global $registry, $browser;
+        
+        $this->calendar = $this->getCalendar($params);
+        $auth = $this->check_auth_calendar(PERMS_EDIT);
+        if (is_a($auth, 'PEAR_Error')) {
+            return 400;
+        }
+
+        $file = fread($params['stream'],$params['content_length']);
+        $registry->call('calendar/importCalendar',array($this->calendar,'text/x-icalendar',$file,true));
+        return true;
+    }
+    
+    /**
+     *
+     * Check which calendar is requested by the user. 
+     * 
+     * The user can specify a different calendar then the default by giving 
+     * the calendar name as a parameter (webdav.php/calendar_name). If
+     * no calendar is specified, null will be returned.
+     *
+     * @param   array   &$params The GET/PUT parameters from the request
+     * @return  string  The requested calendar or null if none
+     */
+    function getCalendar($params) 
+    {
+        if (!empty($params['path'])) {
+            $calendar = basename($params['path']);
+        }
+        if(empty($calendar) || $calendar == "") {
+            $calendar = null;
+        }
+        return $calendar;
+    }
+
+    /**
+     *
+     * Function that checks the access rights to the currently 
+     * active calendar. 
+     *
+     * @param   $type The type of access to check (PERMS_READ, PERMS_EDIT etc.)
+     * @return  true Returns true when successfully authenticated against
+     *               a calendar. After this call, it is guaranteed that
+     *               $this->calendar holds the appropriate calendar
+     */
+    function check_auth_calendar($type) 
+    {
+        global $kronolith_shares;
+        
+        // Retrieve the (possibly) requested calendar
+        
+        // If a calendar is given, this is the calendar
+        // to work with. 
+        if(!is_null($this->calendar)) {
+            $share = $kronolith_shares->getShare($this->calendar);
+        }
+
+        // If a calendar is given, first check anonymous access
+        if(isset($share) && $share->hasPermission('', $type)) {
+            return $this->calendar;
+        }
+        
+        // No anonymous access, so get authentification details
+        if($this->get_auth()) {
+            // If there is no calendar given, the calendar will
+            // be the same as the username
+            if(is_null($this->calendar)) {
+                $this->calendar = Auth::getAuth();
+            }
+    
+            if(!isset($share)) {
+                $share = $kronolith_shares->getShare($this->calendar);
+            }
+            
+            // Check permissions on calendar, if no permissions, give
+            // the authentification dialog again.
+            if(!$share->hasPermission(Auth::getAuth(), $type)) {
+                header('WWW-Authenticate: Basic realm="Kronolith iCalendar Interface"');
+                header('HTTP/1.0 401 Unauthorized');
+                exit;
+            }
+        }
+        return true;
+    }
+
+    /**
+     *
+     * Displays the authentification window and tries to authenticate
+     * against the Horde authentication
+     *
+     * @return  boolean Returns true when successfully authenticated
+     */
+    function get_auth() {
+        $auth = &Auth::singleton($GLOBALS['conf']['auth']['driver']);
+
+        if (!isset($_SERVER['PHP_AUTH_USER'])
+            || !$auth->authenticate($_SERVER['PHP_AUTH_USER'],
+                                    array('password' => isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : null))) {
+            header('WWW-Authenticate: Basic realm="Kronolith iCalendar Interface"');
+            header('HTTP/1.0 401 Unauthorized');
+            exit;
+        }
+        return true;
+    }
+
+}
+
+
+?>
--- lib/api.php.dist	2005-11-24 11:02:09.000000000 +0100
+++ lib/api.php	2005-11-24 10:55:45.000000000 +0100
@@ -69,6 +69,10 @@
     'type' => 'string'
 );
 
+$_services['importCalendar'] = array(
+    'args' => array('content' => 'string', 'calendar' => 'string', 'contentType' => 'string', 'delete' => 'boolean'),
+    'type' => 'object'
+);
 
 $_services['delete'] = array(
     'args' => array('uid' => 'string'),
@@ -499,7 +503,9 @@
         require_once 'Horde/iCalendar.php';
 
         $iCal = &new Horde_iCalendar();
-        $identity = &$kronolith_shares->getIdentityByShare($kronolith_shares->getShare($calendar));
+        $share = $kronolith_shares->getShare($calendar);
+        $iCal->setAttribute('X-WR-CALNAME', $share->get('name'));
+        $identity = &$kronolith_shares->getIdentityByShare($share);
 
         foreach ($events as $id) {
             $event = &$kronolith->getEvent($id);
@@ -518,6 +524,74 @@
 }
 
 /**
+ * Imports a calendar in the requested content type.
+ *
+ * @param string $calendar    The name of the calendar where the content is to be saved
+ * @param mixed $contentType  What format is the data in?
+ *                            Either a string with one of:
+ *                            <pre>
+ *                            text/x-icalendar
+ *                            text/x-vcalendar
+ *                            </pre>
+ *                            or an array with options:
+ *                            <pre>
+ *                            'ContentType': as above
+ *                            'ENCODING':    (optional) character encoding for
+ *                                           strings fields.
+ *                            'CHARSET':     (optional) charset (ex. UTF-8).
+ *                            </pre>
+ * @param string $content     The iCalendar representation of the calendar
+ * @param boolean $delete     Whether to overwrite an existing calendar
+ *
+ * @return Horde_iCalendar    The Horde_iCalendar representation of the calendar.
+ */
+function _kronolith_importCalendar($calendar, $contentType, $content, $delete = false) 
+{
+    require_once dirname(__FILE__) . '/base.php';
+    global $kronolith, $kronolith_shares;
+    if (!array_key_exists($calendar,
+                          Kronolith::listCalendars(false, PERMS_EDIT))) {
+        return PEAR::raiseError(_("Permission Denied"));
+    }
+
+    if (is_array($contentType)) {
+        $options = $contentType;
+        $contentType = $options['ContentType'];
+        unset($options['ContentType']);
+    } else {
+        $options = array();
+    }
+
+    $kronolith->open($calendar);
+
+    switch ($contentType) {
+    case 'text/calendar':
+    case 'text/x-icalendar':
+    case 'text/x-vcalendar':
+        require_once 'Horde/iCalendar.php';
+
+        if($delete) {
+            $kronolith->delete($calendar);
+        }
+    
+        $iCal = &new Horde_iCalendar();
+        $iCal->parsevCalendar($content);
+    
+        foreach ($iCal->getComponents() as $row) {
+            $event = &$kronolith->getEvent();
+            if (is_a($row, 'Horde_iCalendar_vevent')) {
+                $event->fromiCalendar($row);
+                $event->save();
+            }
+        }
+        return $iCal;
+    
+    default:
+        return PEAR::raiseError(sprintf(_("Unsupported Content-Type: %s"), $contentType));
+    }
+}
+
+/**
  * Deletes an event identified by UID.
  *
  * @param string|array $uid  A single UID or an array identifying the event(s)