Net::CalDAVTalk(3)
π NAME π
Okay bestie, welcome to Net::CalDAVTalk(3) β yep, the one from the User Contributed Perl Documentation section, you're in exactly the right place π«Ά
Net::CalDAVTalk β a module that talks CalDAV and gives you back a JSON interface to all that data. It's giving calendar-whisperer main character energy, no cap β¨
πΈ VERSION πΈ
Version 0.12 π
π¦ SYNOPSIS π¦
so like, real talk: this module is the initial release of the code they use at FastMail for talking to CalDAV servers. It's quite specific to an early version of their API, so while it might be useful to other people, honestly it got pushed to CPAN more because the Cassandane test suite needs it π
For the deets on how to specify hosts and paths, go read Net::DAVTalk, okay?
my $CalDAV = Net::CalDAVTalk->new(
user => $service->user(),
password => $service->pass(),
host => $service->host(),
port => $service->port(),
scheme => 'http',
url => '/',
expandurl => 1,
);
or, if you're doing the DNS girly thing:
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 one uses the '/.well-known/caldav' address to find the actual current user principal, and from there the calendar-home-set for all your further operations. iconic tbh π
my $foo = Net::CalDAVTalk->new(
user => $user,
password => $password,
url => $url,
expandurl => 1,
);
π SUBROUTINES/METHODS π
π« new(%args) π«
Takes the exact same arguments as Net::DAVTalk, and then adds the caldav namespaces plus some Cyrus specific namespaces to all the XML requests. slay.
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) π«
Hands you back a DateTime::TimeZone object for the name you passed in β but it caches the result, because speed matters, bestie ποΈ
π« $self->logger(sub { }) π«
Sets a function that receives all the log messages. It gets called with the first argument being a level name, and then a list of items to log. like:
$CalDAV->logger(sub {
my $level = shift;
return if ($level eq 'debug' and not $ENV{DEBUG_CALDAV});
warn "LOG $level: $_\n" for @_;
});
π« $self->DeleteCalendar($calendarId) π«
Deletes the named calendar from the server (shorturl β go see Net::DAVTalk).
π« $Cal->DeleteCalendar($calendarId) π«
Deletes the calendar with collection name $calendarId (full or relative path, your call).
e.g.
$Cal->DeleteCalendar('Default');
π« $self->GetCalendar($calendarId) π«
Grabs a single calendar from the server by calendarId. Heads up though: it's currently implemented very inefficiently as a get of all the calendars π Returns undef if the calendar doesn't exist.
e.g
my $Calendar = $CalDAV->GetCalendar('Default');
π« $self->GetCalendars(Properties => []) π«
Fetches all the calendars on the server. You can request additional properties, but ngl they aren't parsed well yet.
e.g
my $Calendars = $CalDAV->GetCalendars();
foreach my $Cal (@$Calendars) {
# do stuff
}
π« $self->NewCalendar($Args) π«
Creates a shiny new calendar β¨ The $Args are the same 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 genuinely need to create a specific path for compatibility with other things β instead 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 it updates an existing calendar, and 'id' is required. Returns the id, just like NewCalendar does.
π« $self->DeleteEvent($Event|$href) π«
Give it a single event, or the href to the event, and it deletes that event β deletes it from the server, fr fr.
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 it returns an arrayref of events. In list context it 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 (yes, that's the $Urls you handed it π).
Supported args:
ContentTypeVersion
For the calendar-data response.
In scalar context it returns an arrayref of events. In list context it 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 gets a single event (it calls GetEvents with that href under the hood).
π« $self->GetFreeBusy($calendarId, %Args) π«
Like 'GetEvents' but it uses a free-busy-query and then generates synthetic events out of the result. Cute, right?
It 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 fetches changes since that token (obtained from an earlier GetCalendars call).
In scalar context it still just returns new events. In list context it 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 fetches changes since that token (obtained from an earlier GetCalendars or SyncEvent* call).
In scalar context it still just returns Added. In list context it 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) π«
Creates a new event in the named calendar ποΈ If you don't specify 'uid' then a UUID will be created for you. You should only specify the UID if you need to for syncing purposes β it's better to auto-generate otherwise, trust.
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 the keys you actually 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, it uses proppatch to add or remove properties on the event. sneaky but valid π
π« $self->MoveEvent($href, $newCalendarId) π«
Moves an event into a new calendar. Returns the new href.
π« $NewEvent = Net::CalDAVTalk->NormaliseEvent($Event); π«
Doesn't change the original event, but it removes any keys which are the same as their default value. so tidy π§Ή
π« Net::CalDAVTalk->CompareEvents($Event1, $Event2); π«
Returns true if the events are identical.
π« $self->vcalendarToEvents($Data) π«
Converts 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) π«
Sets the address set and display name for the calendar user (if it's supported, that is π).
π« $self->GetICal($calendarId, $isFreeBusy) π«
Given a calender, it fetches all the events and generates an ical format file suitable for import into a client. very export-core π
π 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. bestie, that's the full circle of bug life π¦
π SUPPORT π
You can find documentation for this module with the perldoc command.
perldoc Net::CalDAVTalk
You can also look for information at:
- RT: CPAN's request tracker (report bugs here)
<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Net-CalDAVTalk>
- AnnoCPAN: Annotated CPAN documentation
<http://annocpan.org/dist/Net-CalDAVTalk>
- CPAN Ratings
<http://cpanratings.perl.org/d/Net-CalDAVTalk>
- Search CPAN
<http://search.cpan.org/dist/Net-CalDAVTalk/>
β¨ ACKNOWLEDGEMENTS β¨
(okay so this section is literally empty in the original β nothing here, bestie, moving on ππ)
π LICENSE AND COPYRIGHT π
Okay bestie, legal era incoming β but it's actually not that scary, promise. π«Ά
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. Like, fr fr β that's the vibe check you gotta pass. π
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. No skipping that step, babe. β¨
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. So no borrowing the fit, only the code. π
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. Yeah. Start a patent fight over it and the license ghosts you immediately β that's the deal. π
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.
That whole block up there is in caps for a reason bestie β it's giving serious, and it means exactly what it says. π
And that's a wrap on the whole page, my love! π¦ This lil' masterpiece is documented for perl v5.42.0 and dated 2025-07-25 β iconic, timeless, no notes. Go forth and talk some CalDAV, you absolute main character. βππΈ
π¦ where this page comes from
- fedora 43: perl-Net-CalDAVTalk 0.12-24.fc43 Β· Artistic-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms