diff --git a/htdocs/rss.php b/htdocs/rss.php new file mode 100644 index 00000000..f8616d7a --- /dev/null +++ b/htdocs/rss.php @@ -0,0 +1,167 @@ +$1', $text ); +} + +function caldav_get_rss( $request ) { + dbg_error_log("rss", "GET method handler"); + + require_once("iCalendar.php"); + require_once("DAVResource.php"); + + $dav_resource = new DAVResource($request->path); + $dav_resource->NeedPrivilege( array('urn:ietf:params:xml:ns:caldav:read-free-busy','DAV::read') ); + + if ( ! $dav_resource->Exists() ) { + $request->DoResponse( 404, translate("Resource Not Found.") ); + } + + if ( $dav_resource->IsCollection() ) { + if ( ! $dav_resource->IsCalendar() && !(isset($c->get_includes_subcollections) && $c->get_includes_subcollections) ) { + /** RFC2616 says we must send an Allow header if we send a 405 */ + header("Allow: PROPFIND,PROPPATCH,OPTIONS,MKCOL,REPORT,DELETE"); + $request->DoResponse( 405, translate("GET requests on collections are only supported for calendars.") ); + } + + /** + * The CalDAV specification does not define GET on a collection, but typically this is + * used as a .ics download for the whole collection, which is what we do also. + */ + $sql = 'SELECT caldav_data, class, caldav_type, calendar_item.user_no, logged_user '; + $sql .= 'FROM collection INNER JOIN caldav_data USING(collection_id) INNER JOIN calendar_item USING ( dav_id ) WHERE '; + if ( isset($c->get_includes_subcollections) && $c->get_includes_subcollections ) { + $sql .= '(collection.dav_name ~ :path_match '; + $sql .= 'OR collection.collection_id IN (SELECT bound_source_id FROM dav_binding WHERE dav_binding.dav_name ~ :path_match)) '; + $params = array( ':path_match' => '^'.$request->path ); + } + else { + $sql .= 'caldav_data.collection_id = :collection_id '; + $params = array( ':collection_id' => $dav_resource->resource_id() ); + } + if ( isset($c->strict_result_ordering) && $c->strict_result_ordering ) $sql .= ' ORDER BY dav_id'; + $qry = new AwlQuery( $sql, $params ); + if ( !$qry->Exec("GET",__LINE__,__FILE__) ) { + $request->DoResponse( 500, translate("Database Error") ); + } + + /** + * Here we are constructing the RSS feed response for this collection, including + * the timezones that are referred to by the events we have selected. + * Library used: http://framework.zend.com/manual/en/zend.feed.writer.html + */ + require_once('Zend/Feed/Writer/Feed.php'); + $feed = new Zend_Feed_Writer_Feed; + + $feed->setTitle('CalDAV RSS Feed: '. $dav_resource->GetProperty('displayname')); + $feed->setLink('http://www.google.com'); + $feed->setDescription('This is test of creating a Zend Feed.'); + + require_once('RRule-v2.php'); + + $need_zones = array(); + $timezones = array(); + while( $event = $qry->Fetch() ) { + $is_todo = false; + $ical = new iCalComponent( $event->caldav_data ); + $event_data = $ical->GetComponents( 'VEVENT', true ); + if ( !count($event_data) ) { + $event_data = $ical->GetComponents( 'VTODO', true ); + if ( !count($event_data) ) { + echo "wack event_data found"; + print_r($ical); + } + else { + $is_todo = true; + } + } + + $item = $feed->createEntry(); + $item->setId( $event_data[0]->GetPValue('UID') ); + + $dt_created = new RepeatRuleDateTime( $event_data[0]->GetPValue('CREATED') ); + $dt_modified = new RepeatRuleDateTime( $event_data[0]->GetPValue('LAST-MODIFIED') ); + if ( $dt_created->isDate() ) $item->setDateCreated( $dt_created->epoch() ); + if ( $dt_modified->isDate() ) $item->setDateModified( $dt_modified->epoch() ); + + // According to karora, there are cases where we get multiple VEVENTs (repeats). I'll just stick this (1/x) notifier in here until I get to repeat event processing. + $p_title = $event_data[0]->GetPValue('SUMMARY') . ' (1/' . (string)count($event_data) . ')'; + $is_todo ? $p_title = "TODO: " . $p_title : $p_title; + $item->setTitle($p_title); + + $description = ""; + + $dt_start = $event_data[0]->GetPValue('DTSTART'); + if ( $dt_start != null ) { + $dt_start = new RepeatRuleDateTime($dt_start); + $p_time = '' . translate('Time') . ': ' . $dt_start->format(translate('Y-m-d H:i:s')); + + $dt_end = $event_data[0]->GetPValue('DTEND'); + if ( $dt_end != null ) { + $dt_end = new RepeatRuleDateTime($dt_end); + $p_time .= ' - '; + $dt_end->AsDate() == $dt_start->AsDate() ? $p_time .= $dt_end->format(translate('H:i:s')) : $p_time .= $dt_end->format(translate('Y-m-d H:i:s')); + } + $description .= $p_time; + } + + $p_location = $event_data[0]->GetPValue('LOCATION'); + if ( $p_location != null ) + $description .= '
' + .'' . translate('Location') . ': ' . hyperlink($p_location); + + $p_attach = $event_data[0]->GetPValue('ATTACH'); + if ( $p_attach != null ) + $description .= '
' + .'' . translate('Attachment') . ': ' . hyperlink($p_attach); + + $p_url = $event_data[0]->GetPValue('URL'); + if ( $p_url != null ) + $description .= '
' + .'' . translate('URL') . ': ' . hyperlink($p_url); + + $p_description = $event_data[0]->GetPValue('DESCRIPTION'); + if ( $p_description != null ) { + $description .= '
' + .'
' + .'' . translate('Description') . ':
' . ( nl2br(hyperlink($p_description)) ) + ; + } + + $item->setDescription($description); + $feed->addEntry($item); + //break; + } + + $response = $feed->export('rss'); + header( 'Content-Length: '.strlen($response) ); + header( 'Etag: '.$dav_resource->unique_tag() ); + $request->DoResponse( 200, ($request->method == 'HEAD' ? '' : $response), 'text/xml; charset="utf-8"' ); + } +} + +if ( $request->method == 'GET' ) { + caldav_get_rss( $request ); +} +else { + dbg_error_log( 'rss', 'Unhandled request method >>%s<<', $request->method ); + dbg_log_array( 'rss', '_SERVER', $_SERVER, true ); + dbg_error_log( 'rss', 'RAW: %s', str_replace("\n", '',str_replace("\r", '', $request->raw_post)) ); +} + +$request->DoResponse( 500, translate('The application program does not understand that request.') ); + +/* vim: set ts=2 sw=2 tw=0 :*/ diff --git a/issues/i_54a5f811.cil b/issues/i_54a5f811.cil new file mode 100644 index 00000000..7b7bab91 --- /dev/null +++ b/issues/i_54a5f811.cil @@ -0,0 +1,9 @@ +Summary: add rss/atom feed support for collections +Status: New +CreatedBy: leho +AssignedTo: +DueDate: +Inserted: 2010-12-25T13:53:22 +Updated: 2010-12-25T13:53:22 + +It is usually not possible to easily or reliably notice newly created events in multi-user multi-calendar scenarios, especially if some events are created further in future or past i.e. far out of current (monthly, multi-week) views. RSS/Atom feeds provide a solution to this.