From c6ad6d2caaa1e5491b50a89dc12b230c492ee60a Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 30 Sep 2015 03:27:29 +0000 Subject: [PATCH] allow to reuse managed-id of existing attachment in PUT request by symlinking it, return correct xml-error for invalid mananaged-id --- calendar/inc/class.calendar_ical.inc.php | 6 ++-- phpgwapi/inc/class.groupdav.inc.php | 41 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 96e20a3c4b..f61c085d39 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -1099,7 +1099,7 @@ class calendar_ical extends calendar_boupdate * @param string $charset The encoding charset for $text. Defaults to * utf-8 for new format, iso-8859-1 for old format. * @param string $caldav_name=null name from CalDAV client or null (to use default) - * @return int|boolean cal_id > 0 on success, false on failure or 0 for a failed etag|permission denied + * @return int|boolean|null cal_id > 0 on success, false on failure or 0 for a failed etag|permission denied or null for "403 Forbidden" */ function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='', $user=null, $charset=null, $caldav_name=null,$skip_notification=false) { @@ -1743,9 +1743,9 @@ class calendar_ical extends calendar_boupdate } // handle ATTACH attribute for managed attachments - if ($updated_id) + if ($updated_id && groupdav::handle_attach('calendar', $updated_id, $event['attach'], $event['attach-delete-by-put']) === false) { - groupdav::handle_attach('calendar', $updated_id, $event['attach'], $event['attach-delete-by-put']); + $return_id = null; } if ($this->log) diff --git a/phpgwapi/inc/class.groupdav.inc.php b/phpgwapi/inc/class.groupdav.inc.php index 445c6a7bea..67849067c0 100644 --- a/phpgwapi/inc/class.groupdav.inc.php +++ b/phpgwapi/inc/class.groupdav.inc.php @@ -216,6 +216,9 @@ class groupdav extends HTTP_WebDAV_Server function __construct() { + // log which CalDAVTester test is currently running, set as User-Agent header + if (substr($_SERVER['HTTP_USER_AGENT'], 0, 14) == 'scripts/tests/') error_log('****** '.$_SERVER['HTTP_USER_AGENT']); + if (!$this->debug) $this->debug = (int)$GLOBALS['egw_info']['user']['preferences']['groupdav']['debug_level']; if ($this->debug > 2) error_log('groupdav: $_SERVER='.array2string($_SERVER)); @@ -1359,6 +1362,7 @@ class groupdav extends HTTP_WebDAV_Server * @param int|string $id * @param array $attach array of array with values for keys 'name', 'params', 'value' * @param boolean $delete_via_put + * @return boolean false on error, eg. invalid managed id, for false an xml-error body has been send */ public static function handle_attach($app, $id, $attach, $delete_via_put=false) { @@ -1397,6 +1401,32 @@ class groupdav extends HTTP_WebDAV_Server { if (!empty($attr['params']['FMTTYPE'])) { + if (isset($attr['params']['MANAGED-ID'])) + { + // invalid managed-id + if (!($path = self::managed_id2path($attr['params']['MANAGED-ID'])) || !egw_vfs::is_readable($path)) + { + error_log(__METHOD__."('$app', $id, ...) invalid MANAGED-ID ".array2string($attr)); + self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id', '')); + return false; + } + if($path == ($link = egw_link::vfs_path($app, $id, egw_vfs::basename($path)))) + { + error_log(__METHOD__."('$app', $id, ...) trying to modify existing MANAGED-ID --> ignored! ".array2string($attr)); + continue; + } + // reuse valid managed-id --> symlink attachment + if (egw_vfs::file_exists($link)) + { + if (egw_vfs::readlink($link) === $path) continue; // no need to recreate identical link + egw_vfs::unlink($link); // symlink will fail, if $link exists + } + if (!egw_vfs::symlink($path, $link)) + { + error_log(__METHOD__."('$app', $id, ...) failed to symlink($path, $link) --> ignored!"); + } + continue; + } if (!($to = self::fopen_attachment($app, $id, $filename=$attr['params']['FILENAME'], $attr['params']['FMTTYPE'], $path)) || // Horde Icalendar does NOT decode automatic ($copied=fwrite($to, $attr['params']['ENCODING'] == 'BASE64' ? base64_decode($attr['value']) : $attr['value'])) === false) @@ -1494,6 +1524,17 @@ class groupdav extends HTTP_WebDAV_Server 'need_mime' => true, ), true) as $path => $stat) { + // handle symlinks --> return target size and mime-type + if (($target = readlink($path))) + { + if (!($stat = egw_vfs::stat($target))) continue; // broken or inaccessible symlink + + // check if target is in /apps, probably reused MANAGED-ID --> return it + if (substr($target, 0, 6) == '/apps/') + { + $path = $target; + } + } $attributes['ATTACH'][] = self::path2location($path); $parameters['ATTACH'][] = array( 'MANAGED-ID' => groupdav::path2managed_id($path),