CalSub reads an iCalendar (ics
) source and writes the events into a CalDAV calendar. Use CalSub to add calendar subscriptions to CalDAV servers.
Using calsub
To get started with Miln CalSub, download and expand the executable file onto your computer.
CalSub is a single executable file. It does not need to be installed, can be run from any directory, and can be removed by deleting the file.
Let’s walk through an example use of calsub
and then consider other options. Consider this command line call:
./calsub -ics https://localhost/work.ics -caldav https://example.com/caldav/you -cal work -netrc ~/.netrc
The flags for this call to calsub
are:
-ics https://work.intranet/work.ics
- The URI to read an
ics
formatted calendar from. In this example, the calendar is on another server. -caldav https://example.com/caldav/you
- The CalDAV destination server. This the CalDAV service that the events will be written to.
-cal work
- The display name of an existing calendar on the CalDAV service specified with
-caldav
. -netrc ~/.netrc
- The path to a netrc formatted credentials file. This file contains any username and password needed to access the CalDAV service specified with
-caldav
.
What Happens
So what happens when this command is issued?
calsub
does the following:
- Reads the source calendar file’s events
- Reads the destination calendar server’s events
- Compares the two sets of events and produces three lists:
- events that need to be added;
- events that need to be removed;
- events that are unchanged.
- Events that need to be removed are removed
- Events that need to be added are added
The interesting part is the comparison of the two sets of events. What determines if an event needs to be added, removed, or ignored as unchanged?
Comparing Events
CalSub uses two CalDAV properties to compare calendar events:
- Unique Identifier /
UID
; - Last Modified /
LAST-MODIFIED
.
If an event with no matching Unique Identifier is read from the ics
source, it is added.
If an event exists in the destination calendar with no matching Unique Identifier, the event is noted as removed. What happens to these events is controlled by CalSub’s removal behaviour.
If Last Modified is missing or differs between events with the same Unique Identifier, then the event is deemed as changed. The source event is added and the destination event is removed.
If Last Modified matches an existing events with the same Unique Identifier, then the event is noted as unchanged.
Removal Behaviour
How existing and removed events are treated depends on the -remove
flag. The flag can be:
all
- Remove all the existing events and write all the events. This behaviour makes no attempt to determine if an event already exists. All existing events are removed from the destination calendar, before attempting to write the source calendar’s events.
unknown
- Remove only the unknown events. This behaviour removes events that do not appear in the source calendar. Unchanged events that exist in both the source and destination are skipped. This is best behaviour when you want to synchronise a calendar because it reduces the number of removals and writes.
error
- Remove nothing but events that were created when
calsub
encountered an error. This behaviour accumulates events in the destination. This can be useful if you never want to remove old events but want to append new ones. Existing but unchanged events are left untouched.
The default behaviour is error
. This is the default because non-CalSub events are left unchanged in destination calendar. This behaviour is the least risky.
Dry Run and Testing
CalSub includes a -dry-run
flag. When the -dry-run
flag is set, calsub
will not make any changes to the destination calendar. Dry run is designed for checking settings and testing the expected behaviour.
./calsub -ics work.ics -caldav https://example.com/caldav/you -cal work -netrc ~/.netrc -dry-run
Intended Use
CalSub was written to overcome the lack of subscription calendar support in Synology Calendar. While Calendar supports importing one-time ics
files, it does not support subscriptions to external calendars.
CalSub fulfils this missing feature by effectively managing a single calendar for us. This calendar is marked as read only in our client applications and is regularly updated by CalSub.
To run CalSub regularly and automatically, I added an entry to DiskStation Manager’s Task Scheduler:
- Control Panel > Task Scheduler > User-defined script
I could have also used a tool like cron
, launchd
, or systemd
.
Examples
Below are examples of common uses of CalSub.
Remote iCalendar to CalDAV
Read a web hosted ics file at https://example.com/work.ics
and import the events in the work
calendar on https://example.com/caldav
. Authenticate with example.com
using a netrc
file.
./calsub -ics https://example.com/work.ics -caldav https://example.com/caldav/you -cal work -netrc ~/.netrc
Local File to CalDAV
Read a local work.ics
file and import the events in the work
calendar on https://example.com/caldav
. Authenticate with example.com
using a netrc
file.
./calsub -ics ~/work.ics -caldav https://example.com/caldav/you -cal work -netrc ~/.netrc
Standard Input (piped) to CalDAV
Read a calendar file from standard input (stdin
) and import the events in the work
calendar on https://example.com/caldav
. Authenticate with example.com
using a netrc
file.
./calsub -caldav https://example.com/caldav/you -cal work -netrc ~/.netrc
Flags
calsub
accepts the following command line flags:
Usage of ./calsub:
-cal string
Name of CalDAV calendar to overwrite. (required)
-caldav string
URL to CalDAV server. (required)
-config string
File path to configuration.
-dry-run
Read and triage but make no changes.
-h Show this help message and exit. (shorthand)
-help
Show this help message and exit.
-ics string
Path or URL to iCalendar (.ics) file to import; stdin if empty.
-l string
Directory path to licence certificate files (PEM encoded) (shorthand) (default "~/.miln/")
-legal
Show legal notices and exit.
-licence string
Directory path to licence certificate files (PEM encoded) (default "~/.miln/")
-netrc string
Path to netrc file for CalDAV authentication.
-quiet
Quieten non-critical output.
-remove string
(all|unknown|error) events before writing. (default "error")
-show-licence
Show licence details and exit.
-v Show version details and exit. (shorthand)
-version
Show version details and exit.
Sample Output
calsub
prints progress as it runs. Below is a sample output from a run of the tool. The output shows a calendar with a malformed event. calsub
encounters a problem writing one of the events and falls back to writing an error event. Where possible, calsub
reports problems through events in the destination calendar – where the impact of the error is most important.
2023/10/03 15:46:42 calsub: Reading netrc: "/Users/miln/.netrc"
2023/10/03 15:46:42 calsub: Reading source calendar (ics): "https://example.com/ical/"
2023/10/03 15:46:42 calsub: …read events: 40
2023/10/03 15:46:42 calsub: Connecting to destination CalDAV server: "https://localhost/caldav/miln"
2023/10/03 15:46:42 calsub: …finding user
2023/10/03 15:46:43 calsub: …finding home: "/caldav.php/miln/"
2023/10/03 15:46:43 calsub: …finding calendars: "/caldav.php/miln/"
2023/10/03 15:46:43 calsub: …finding named calendar: "Work"
2023/10/03 15:46:43 calsub: …found calendar: "Work"
2023/10/03 15:46:43 calsub: …getting existing events: "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/"
2023/10/03 15:46:43 calsub: …existing events: 49
2023/10/03 15:46:43 calsub: …triaged events: 1 to add, 10 to remove, 39 unchanged
2023/10/03 15:46:43 calsub: …removing events: 10 to remove from "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/"
2023/10/03 15:46:43 calsub: …removing: 1 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-03T15:30:02+02:00-10981-0-error"
2023/10/03 15:46:44 calsub: …removing: 2 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T17:03:46+02:00-7710-5"
2023/10/03 15:46:44 calsub: …removing: 3 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T22:30:01+02:00-8945-0"
2023/10/03 15:46:44 calsub: …removing: 4 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T17:03:46+02:00-7710-1"
2023/10/03 15:46:44 calsub: …removing: 5 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T17:03:46+02:00-7710-6"
2023/10/03 15:46:45 calsub: …removing: 6 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T17:03:46+02:00-7710-2"
2023/10/03 15:46:45 calsub: …removing: 7 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T17:03:46+02:00-7710-4"
2023/10/03 15:46:45 calsub: …removing: 8 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T17:03:46+02:00-7710-3"
2023/10/03 15:46:45 calsub: …removing: 9 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T17:03:46+02:00-7710-20"
2023/10/03 15:46:46 calsub: …removing: 10 of 10 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-02T17:03:46+02:00-7710-0"
2023/10/03 15:46:46 calsub: …writing events: 1 to write to "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/"
2023/10/03 15:46:47 calsub: …wrote error event: 1 at "/caldav.php/miln/DE590F3B-1234-459E-EFEF-3A2655BD558F/eu.miln.calsub-2023-10-03T15:46:42+02:00-5596-0-error"
2023/10/03 15:46:47 calsub: Finished
Verbose progress helps explain what is happening and why but you can always silence it using the -quiet
flag.