TDcal(7) FreeBSD Miscellaneous Information Manual TDcal(7)

TDcal
TDcal calendar system description

TDcal is a personal calendar management system.

TDcal supports the following features:

TDcal uses RFC5545-compliant iCalendar calendar and event files for maximum interoperability with other calendar tools. There is a command-line client, td(1), a graphical user interface (GUI) client, tdg(1), a systray icon, tdt(1), and a daemon, tdd(1), that provides forthcoming-event notifications and that periodically synchronizes local calendars with remote servers.

TDcal supports multiple calendars which can each be one of several types:

Local
The calendar is stored in the user's local calendar directory and not synchronized with any remote servers.
Ical
The calendar is read from an external file or remote web server. The source is periodically checked for updates and re-fetched as needed.
CalDAV
The calendar is synchronized with a remote CalDAV server. Changes made to the calendar are sent to the server and will be visible on all devices sharing the same calendar.

All calendar data is downloaded and stored locally so that you have full access to your calendars while offline; changes are saved and synced back to servers when you are next online.

Operational parameters can be configured in the configuration file, see td(5), which is also used to configure calendars.

The TDcal tools have been designed with a global audience in mind. Calendars can be displayed with any week start day and with the weekend either at the end of the week or wrapped around the week. Dates and times are formatted according to locale settings although the use of 24-hour time can be forced if desired. Events are stored internally in UTC so that, when travelling to other time zones, the event times always show at the correct local time. Full NLS support is included so that GUI messages as well as pop-up event reminders are displayed in the user's preferred language.

All configuration information as well as all calendar data and internal caching data are stored in text files and can easily be examined and/or edited by the user.

TDcal is lightweight in that it is not integrated as part of a larger productivity suite or desktop environment. It is implemented as a set of Perl scripts and libraries. It can be installed and used without the overhead of large numbers of external libraries or other tools. Nevertheless, TDcal is very powerful and integrates well with tools such as email by virtue of its calenadar import and export features which allow calendar appointments shared by email from other users to be added to your calendar.

TDcal has been designed to be fast and efficient. Even with large calendars containing decades worth (many thousands) of appointment events, listings for what's coming next are generated very quickly with negligible CPU load or performance impact. TDcal minimizes network transfers by means of limits on synchronization frequency and by use of calendar and event change tags to avoid re-transferring things that have not changed.

Local calendars are not syncronized. They exist solely on the device on which they were created. Items added to these calendars are essentially not backed up elsewhere.

Ical calendars are read or fetched from either an external file or from a remote web server using the HTTPS or HTTP protocol.

Institutions that publish a calendar very often make use of this. Examples are services providing national holiday listings and also those providing sports, theatre and opera schedules and local meeting groups.

TDcal makes an initial copy of such calendars and then periodically checks back to see if the calendar has been updated and, if so, fetches a new copy. This ensures that your local view is up-to-date even when schedules change.

Calendars read from a file or fetched from a remote server are read-only and events cannot be edited nor new events added.

CalDAV calendars are synchronized with remote CalDAV servers such as are operated by many public cloud storage services and also software such as nextCloud and ownCloud.

A user's remote CalDAV account may store multiple calendars. TDcal automatically discovers calendars on the server and synchronizes all calendars to the local device. TDcal also automatically detects when calendars are deleted from a server and deletes them locally too. Some CalDAV servers include calendars created from external data such as calendars of contacts' birthdays created from address books also stored on the server. TDcal detects these and includes them as read-only calendars.

CalDAV allows a calendar to be accessed from multiple devices. Events added to the calendar on any device are synchronized with the server and then synchronized with other devices sharing the same calendar. Each device has its own copy of the entire calendar so that it can operate normally while offline. Events added in TDcal to a calendar while offline are stored and synchronized with the server later when the device is online again.

If the same event is changed on multiple devices while all are offline, the first device to come online will synchronize its change with the server. This change will then be synchronized with other devices as they come online, and may override any local change made to the same event on those devices.

TDcal supports the use of the OAuth authorization framework for use with services that require it.

TDcal is tested and works with many CalDAV servers. Configuration examples for popular ones are given in the td(5) configuration file manual page.

TDcal has a system tray icon provided by the tdt(1) program. It displays an icon for today's calendar date as well as a summary of forthcoming calendar events. When clicked, the tdg(1) graphical user interface is opened.

TDcal has an alert and synchronization daemon, tdd(1). Event alerts are displayed in pop-up windows on the screen or as command-line messages if no pop-ups are possible.

Note that TDcal maintains but does not use the so-called ‘alarm’ information that may be configured in an iCalendar event. Any such information in events is ignored by tdd(1) but the information is retained and will be included if the event is exported and it will be resent to the server when the event is updated. TDcal instead allows the user to configure an alert schedule that suits the user's own needs. By default, alerts are displayed at 60, 30, 15, 5 and 0 minutes before an event. This default schedule can be overridden in the configuration file either for all calendars or on a per-calendar basis.

Events created by TDcal will contain iCalendar alarms corresponding to the configured alert schedule. Changes to an event summary text are reflected into stored alarm information.

TDcal supports RFC5545 event repetition using ‘RRULE’, ‘RDATE’ and ‘EXDATE’. specifiers. It should be noted that the deprecated ‘EXRULE’ exclusion rule is also recognised in existing events but cannot be added to new events. Simple repetition can be specified with a basic repetition rule such as ‘FREQ:WEEKLY’ or ‘FREQ:MONTHLY;BYDAY=2WE’ which means monthly on the 2nd Wednesday of the month. More complex repetitions can be created by combining BYxyz repetition specifiers, adding specific repetition and exclusion dates, and set position specifiers.

The repetition syntax is the same as specified in RFC5545. Repetition details can be entered directly using the td(1) command-line interface and they can be edited into events using the ‘Alt-R’ repetition editor of the tdg(1) graphical user interface.

It should be noted that TDcal supports the full RFC5545 repetition syntax. Many other calendar applications and mobile apps, however, do not support the full syntax. It is therefore possible to write complex repetition rules that display as intended in TDcal but that do not display correctly (or even at all) in other apps.

TDcal uses the following files:

~/.td
The configuration file for all TDcal tools.

~/.td.log
The log file for event addition/deletions as well as for synchronizations. Up to four copies of old log files are kept in .td.olog, .td.oolog etc.

~/.tdcals
Storage for the calendar data and meta-data.

~/.tdcals/calendarname
 
~/.tdcals/collection/calendarname
Each calendar is stored in its own directory. The calendar directories are named in the configuration file or discovered from remote servers. Individual CalDAV calendars are stored in sub-directories under their collection directories.

~/.tdcals/[collection/]calendarname/identifier
Calendar events are stored one per file in files named by the event identifier (which is the iCalendar UID value).

~/.tdcals/[collection/]calendarname/.cache
For speed of processing, calendar event details are extracted and cached in the calendar cache file. This is a tab-separated file containing all information that is used frequently by TDcal. Note that event start and end times in this .cache file are in the UTC timezone.

~/.tdcals/[collection/]calendarname/.cachelock
To avoid multiple updates to the cache occuring at the same time, a lock file is created. If that file is present, it is a dead symbolic link to the pid and name of the process doing the update. When about to do a update, that pid is checked. If the process still exists, the update is delayed until the other process completes and then the cache is re-read before proceeding with this update. If the process no longer exists, the lock is broken and this update goes ahead.

~/.tdcals/[collection/]calendarname/.config
contains configuration data learned from remote CalDAV servers about CalDAV calendars. The format of this file is the same as for tdrc(5). The .config file is re-written every time TDcal synchronizes with the server so that latest server values are available.

~/.tdcals/[collection/]calendarname/.lastmodified
contains the timestamp or the CalDAV ‘ctag’ of the last modification to this calendar on the server. This is used to determine the time for the next re-fetch of the calendar.

~/.tdcals/[collection/]calendarname/.lastsync
The mtime of this file is the time of the last synchronization with a server. This is used together with the configured synchronization period for this calendar to determine when to perform the next synchronization with the server.

~/.tdcals/[collection/]calendarname/.local
indicates that this calendar was configured as a local calendar. Presence of a .local file prevents the calendar directory from being deleted when the calendar is removed from the configuration file. Since local calendars are not backed up on a server, this avoids inadvertent deletion of event data if the configuration is messed up. Local calendar data directories and event data in them must be deleted by hand.

~/.tdcals/[collection/]calendarname/.syncqueue/
The queue of events created or changed locally that are still to be synchronized with a remote server is in this directory. Individual events each have a file .syncqueue/identifier which contians the word: ‘put’ or ‘delete’ possibly followed by the event's ‘href’ which indicates how the change is to be sent. These queue files are removed when TDcal next synchronizes with the server.

~/.tdcals/[collection/]calendarname/.synclock
To avoid multiple synchronizers running at the same time, a lock file is created. If that file is present, it is a dead symbolic link to the pid and name of the process doing the synchronization. When about to do a synchronization, that pid is checked. If the process still exists, a simultaneous sync is not started. If the process no longer exists, the lock is broken and a new sync is started.

As documented above, TDcal stores all calendar event data as text files in the directory hierarchy shown. The top-level directory is created mode 0700 so that events are private. The use of text files in a directory hierarchy is a deliberate design choice to allow for easy manipulation of data by poking around under the hood.

If you end up doing this, be aware that for any change to calendar event data, several things must be done:

It is not recommended to make such changes by hand. Events can be changed, moved, deleted, etc using the td(1) command-line interface, which uses the TDcal(3) libraries to take care of all of these things while also doing appropriate locking to make sure that other running processes don't also make updates at the same time. If changes need to be made that are not easily done using td(1), better would be to write a new tool that uses the TDcal(3) library to do the job. Examples of some simple tools can be found in the src/tools directory in the source code.

TDcal was influenced by the design of Sanjay Ghemawat's ical(1) calendar tool (not related to Apple's iCal tool). The author of TDcal was a happy user of ical(1) for several decades before eventually needing a tool that supported network synchronization. The look and feel of the graphical user-interface as well as the default alarm schedule and the "No more alerts" button were all borrowed from ical(1). Thank you Sanjay Ghemawat for a tool that lasted a good couple of decades.

The -x flag that eXplains each utility's usage as well as the idea for the .olog, .oolog etc extending file names for old logs and the name of the internal upd() function that produces them comes from David Tilbrook's ‘DTree’.

ical(1), td(1), tdd(1), tdg(1), tdoauth(1), tdt(1), vi(1), TDcal(3), td(5), WWW: http://opal.com/src/tdcal/

TDcal is compliant with the RFC5545 iCalendar specification.

TDcal supports CalDAV synchronization according to RFC4791.

TDcal supports access authorization using both basic username/password and according to the RFC6749 OAuth 2.0 authorization framework.

TDcal(7) calendar manager, its Perl libraries and the associated command-line and GUI interfaces and the alert and synchronization daemon were developed by J.R. Oldroyd ⟨tdcal@opal.com⟩ at Open Advisors Limited in July and August 2013 with improvements in 2017, 2018 and 2020-2023.
July 22, 2013 FreeBSD 13.1-RELEASE-p3