NAME

Net::CalDAVTalk - Module to talk CalDAV and give a JSON interface to the data

VERSION

Version 0.12

SYNOPSIS

This module is the initial release of the code used at FastMail for talking to CalDAV servers. It's quite specific to an early version of our API, so while it might be useful to others, it's being pushed to CPAN more because the Cassandane test suite needs it.

See Net::DAVTalk for details on how to specify hosts and paths.

    my $CalDAV = Net::CalDAVTalk->new(
        user => $service->user(),
        password => $service->pass(),
        host => $service->host(),
        port => $service->port(),
        scheme => 'http',
        url => '/',
        expandurl => 1,
    );

or using DNS:

    my $domain = $user;
    $domain =~ s/.*\@//;

    my $url;
    my ($reply) = $Resolver->search("_caldavs._tcp.$domain", "srv");
    if ($reply) {
      my @d = $reply->answer;
      if (@d) {
        my $host = $d[0]->target();
        my $port = $d[0]->port();
        $url = "https://$host";
        $url .= ":$port" unless $port eq 443;
      }
    }

This will use the '/.well-known/caldav' address to find the actual current user principal, and from there the calendar-home-set for further operations.

    my $foo = Net::CalDAVTalk->new(
       user => $user,
       password => $password,
       url => $url,
       expandurl => 1,
    );

SUBROUTINES/METHODS

new(%args)

Takes the same arguments as Net::DAVTalk and adds the caldav namespaces and some Cyrus specific namespaces for all XML requests.

  A => 'http://apple.com/ns/ical/'
  C => 'urn:ietf:params:xml:ns:caldav'
  CY => 'http://cyrusimap.org/ns/'
  UF => 'http://cyrusimap.org/ns/userflag/'
  SF => 'http://cyrusimap.org/ns/sysflag/'

$self->tz($name)

Returns a DateTime::TimeZone object for the given name, but caches the result for speed.

$self->logger(sub { })

Sets a function to receive all log messages. Gets called with the first argument being a level name, and then a list of items to log:

e.g.

   $CalDAV->logger(sub {
      my $level = shift;
      return if ($level eq 'debug' and not $ENV{DEBUG_CALDAV});
      warn "LOG $level: $_\n" for @_;
   });

$self->DeleteCalendar($calendarId)

Delete the named calendar from the server (shorturl - see Net::DAVTalk)

$Cal->DeleteCalendar($calendarId)

Delete the calendar with collection name $calendarId (full or relative path)

e.g.

    $Cal->DeleteCalendar('Default');

$self->GetCalendar($calendarId)

Get a single calendar from the server by calendarId (currently implemented very inefficiently as a get of all calendars. Returns undef if the calendar doesn't exist.

e.g my $Calendar = $CalDAV->GetCalendar('Default');

$self->GetCalendars(Properties => [])

Fetch all the calendars on the server. You can request additional properties, but they aren't parsed well yet.

e.g

   my $Calendars = $CalDAV->GetCalendars();
   foreach my $Cal (@$Calendars) {
      # do stuff
   }

$self->NewCalendar($Args)

Create a new calendar. The Args are the as the things returned by GetCalendars, except that if you don't provide 'id' (same as shorturl), then a UUID will be generated for you. It's recommended to not provide 'id' unless you need to create a specific path for compatibility with other things, and to use 'name' to identify the calendar for users. 'name' is stored as DAV:displayname.

e.g.

   my $Id = $CalDAV->NewCalendar({name => 'My Calendar', color => 'aqua'});

(Color names will be translated based on the CSS name list)

$self->UpdateCalendar($Args)

Like 'NewCalendar', but updates an existing calendar, and 'id' is required. Returns the id, just like NewCalendar.

$self->DeleteEvent($Event|$href)

Given a single event or the href to the event, delete that event, delete it from the server.

Returns true.

$self->GetEvents($calendarId, %Args)

Fetches some or all of the events in a calendar.

Supported args:

  href => [] - perform a multi-get on just these fullpath urls.
  after+before => ISO8601 - date range to query

In scalar context returns an arrayref of events. In list context returns both an arrayref of events and an arrayref of errors:

e.g.

    my ($Events, $Errors) = $CalDAV->GetEvents('Default');

$self->GetEventsMulti($calendarId, $Urls, %Args)

Fetches the events in Urs from the calendar

Supported args:

  * ContentType
  * Version

For the calendar-data response

In scalar context returns an arrayref of events. In list context returns an array of:

* arrayref of events * arrayref of errors: * hash of href to getetag

$self->GetEventLinks($calendarId, %Args)

Fetches the URLs of calendar events in a calendar.

Supported args:

  after+before => ISO8601 - date range to query

returns a hash of href to etag

$self->GetEvent($href)

Just get a single event (calls GetEvents with that href)

$self->GetFreeBusy($calendarId, %Args)

Like 'GetEvents' but uses a free-busy-query and then generates synthetic events out of the result.

Doesn't have a 'href' parameter, just the before/after range.

$self->SyncEvents($calendarId, %Args)

Like GetEvents, but if you pass a syncToken argument, then it will fetch changes since that token (obtained from an earlier GetCalendars call).

In scalar context still just returns new events, in list context returns Events, Removed and Errors.

e.g.

   my ($Events, $Removed, $Errors) = $CalDAV->SyncEvents('Default', syncToken => '...');

$self->SyncEventLinks($calendarId, %Args)

Like GetEventLinks, but if you pass a syncToken argument, then it will fetch changes since that token (obtained from an earlier GetCalendars or SyncEvent* call).

In scalar context still just returns Added, in list context returns Added, Removed, Errors and new token:

* Added: hash of href to etag - added or changed * Removed: array of href * Errors: array of descritive string * NewToken: scalar opaque DAV:sync-token

e.g.

   my ($Added, $Removed, $Errors, $NewToken)
      = $CalDAV->SyncEventLinks('Default', syncToken => '...');

$self->NewEvent($calendarId, $Args)

Create a new event in the named calendar. If you don't specify 'uid' then a UUID will be created. You should only specify the UID if you need to for syncing purposes - it's better to auto-generate otherwise.

Returns the href, but also updates 'uid' in $Args.

Also updates 'sequence'.

e.g.

    my $href = $CalDAV->NewEvent('Default', $Args);
    my $newuid = $Args->{uid};

$self->UpdateEvent($href, $Args)

Like NewEvent, but you only need to specify keys that you want to change, and it takes the full href to the card instead of the containing calendar.

$self->AnnotateEvent($href, $Args)

Instead of actually changing an event itself, use proppatch to add or remove properties on the event.

$self->MoveEvent($href, $newCalendarId)

Move an event into a new calendar. Returns the new href.

$NewEvent = Net::CalDAVTalk->NormaliseEvent($Event);

Doesn't change the original event, but removes any keys which are the same as their default value

Net::CalDAVTalk->CompareEvents($Event1, $Event2);

Returns true if the events are identical

$self->vcalendarToEvents($Data)

Convert a text vcalendar (either a single event or an entire ical file) into an array of events.

Returns an array (not arrayref) of Events in UID order.

e.g.

    foreach my $Event ($CalDAV->vcalendarToEvents($Data)) {
        # ...
    }

$self->UpdateAddressSet($DisplayName, $EmailAddress)

Set the address set and display name for the calendar user (if supported)

$self->GetICal($calendarId, $isFreeBusy)

Given a calender, fetch all the events and generate an ical format file suitable for import into a client.

AUTHOR

Bron Gondwana, <brong at cpan.org>

BUGS

Please report any bugs or feature requests to bug-net-caldavtalk at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-CalDAVTalk. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Net::CalDAVTalk

You can also look for information at:

ACKNOWLEDGEMENTS

LICENSE AND COPYRIGHT

Copyright 2015 FastMail Pty Ltd.

This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0

Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.