TDcal is a set of command-line tools and a GUI program for editing calendar events as well as a synchronization daemon, a systray icon and a programming library.
TDcal is fully compliant with internet calendar standards (iCalendar, RFC5545) as well as the calendar sharing protocol (CalDAV, RFC4791) and also the authorization framework (OAuth, RFC6749).
TDcal's user interface is modeled on that of the ical(1) program written by Sanjay Ghemawat in 1993 which the TDcal author used for 20 years before needing a standards-based calendaring tool.
TDcal maintains many similar user-interface features found in ical(1) but replaces the internal calendar storage with a standards-based one, and adds support for remote iCalendar downloads as well as server-based CalDAV calendar synchronization.
TDcal downloads all calendar data and stores it 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.
TDcal is implemented in Perl and uses the Gtk graphics libraries. It has been designed to be lightweight, fast and independent of window-manager. It does not use a database management system, instead storing all calendar data as files in a sub-directory of your home directory.
In addition to the graphical interface shown above, TDcal includes a command-line calendar manipulation tool as well as a notification daemon and a systray icon. The Perl programming API is also fully documented allowing additional applications to be developed.
The code for the GUI program tdg is now Gtk3-based using only non-deprecated features.
TDcal can be installed from the ports system either as a binary package or by installing from the source. To install from binary package, do this:
# pkg install tdcal
To deinstall:
# pkg delete tdcalTo install from the port, do this:
# cd /usr/ports # portsnap extract deskutils/tdcal # cd deskutils/tdcal # make # make install clean
To deinstall:
# cd /usr/ports/deskutuls/tdcal # make deinstall
If you are installing without using the FreeBSD ports framework, you will need to manually add the following dependencies:
# pkg install www/p5-Browser-Open # pkg install x11-toolkits/p5-Gtk3 # pkg install net/p5-IO-Socket-INET6 # pkg install security/p5-IO-Socket-SSL # pkg install converters/p5-JSON # pkg install devel/p5-Locale-gettext # pkg install net/p5-Net-Interface # pkg install textproc/p5-XML-Simple
TDcal has been tested on Linux (specifically on MX Linux-21 and XUbuntu 21.04) and it works well.
Download the latest distribution file, below, and extract using:
$ tar xvf tdcal-N.M.tar.xz
The Makefiles use FreeBSD make(1) syntax. They can be used on Linux using bmake(1).
Use the installation command:
$ cd tdcal-N.M $ sudo PREFIX=/usr bmake install
The following package dependencies should be installed:
bmake gettext libbrowser-open-perl libgtk3-perl libio-socket-inet6-perl libio-socket-ssl-perl libjson-perl liblocale-gettext-perl libmime-base64-urlsafe-perl libnet-interface-perl libxml-simple-perl
To deinstall:
$ sudo PREFIX=/usr bmake deinstall
To start, a configuration file must be created which is done using any text editor. An example of a configuration file is shown below.
If you are configuring calendars on CalDAV services that require OAuth authorization, you will first have to go through a series of steps to register TDcal as an application that can access your account, obtain client credentials for it, add them to the configuration file, then run the tdoauth command to obtain an authorization code and access tokens in order to access your data on the server. See the tdoauth manual page for details of how to set things up.
Any of the tools can be run to check the syntax of the configuration file. Running the command-line tool td is the simplest way to see any error messages.
The notification and synchronization daemon tdd as well as the systray icon tdt are typically started at login or in the window-manager startup configuration and these are left running the whole time you are logged in.
The next step is to import calendar event data. If your calendar is already on a remote server, the tdd daemon will fetch the calendar events and store copies of them locally on your computer. If your calendar is in a file, you can import it using the td command-line tool. If you are migrating from ical(1) you will need to convert the events in ical's .calendar file to iCalendar .ics format and then import it using the td command-line tool. See below for a tool to help do this.
To edit events in TDcal, the tdg graphical interface is typically used. This displays your calendars in a window and allows navigation through the events, editing them and adding new ones. Also, the td command-line tool can be used to add, edit and delete events from a terminal window, and it can also be used from shell scripts.
All changes to your calendars are stored locally on your computer. The changes are synchronized back to their CalDAV servers on a periodic basis by the tdd daemon which you started earlier. If desired, both the event editors, td and tdg can be told to start an immediate synchronization run whenever an event is changed.
The first manual to read is the general overview in TDcal(7).
The configuration file syntax is documented in td(5).
OAuth set-up is documented in the tdoauth(1) manual page.
Each of the commands are documented in their manual pages: td(1), tdg(1), tdd(1) and tdt(1).
The Perl programming API is documented in the TDcal(3) manual page; there are additional man pages for each of the TDcal support libraries: TDcal::CalDAV(3), TDcal::Fetch(3), TDcal::OAuth(3), TDcal::cache(3), TDcal::const(3), TDcal::hkl(3), TDcal::http(3), TDcal::iCalendar(3), TDcal::lock(3), TDcal::misc(3), TDcal::nls(3), TDcal::timezone(3) and TDcal::version(3).
The configuration file is named: ~/.td
This configuration file must be created using your favorite editor and should be mode 600 (because it contains passwords).
An example that configures a local private calendar, one shared on your own nextCloud server, your Google Calendar and a downloaded public holidays calendar, would look like this:
# TDcal configuration file alerts 60 30 15 5 0 lperiod 14 logsize 1000000 cal Local color #ffdd00 cal MyNextCloud color #00a0fa url https://example.com/nextcloud/remote.php/dav/ user username pass yadda-yadda-yadda-yadda-yadda alerts 90 60 45 30 15 10 5 0 cal MyNextCloud/contact_birthdays adalrts 17:00 10:00 oaprv google cli_id 123456789012-yaddayaddayadda.apps.googleusercontent.com cli_sec 123yadda456yadda789yadda cal MyGoogleCalendar url https://apidata.googleusercontent.com/caldav/v2/ user myname@gmail.com cal US Holidays color #04a004 url https://www.thunderbird.net/media/caldata/USHolidays.ics updfreq 10080
Full details of the configuration file syntax can be found in the manual page td(5).
tdd fetches full calendars from the remote servers and then periodically synchronizes changed events back to the remote servers.
If you have calendar events in a local .ics file and wish to import these into a TDcal calendar, you can do this using the td command-line tool:
td -c calendar -i file.ics
Once synchonized or imported, the calendar events can be viewed and manipulated using the tdg GUI interface or by the td command-line program which can also be used for scripted manipulations.
If you are migrating from ical(1) and you don't relish the idea of re-entering years (decades?) worth of calendar events, you could try the ical2icalendar(1) conversion tool offered here. This tool converts ical's .calendar data into standard .ics format. Use it something like this:
perl ical2icalendar.pl ~/.calendar | td -c calendar -i -
This tool is not guaranteed to accurately convert everything: especially entries with complex repetition rules may not be properly converted. So, after use, you should go through all events and check their repetition rules are as desired.
tdd connects to each calendar's server and performs synchronization uploads and/or downloads.
tdd also provides the pop-up event notification alerts.
The frequency of the synchronization runs as well as the timing of the alerts are all configured in the configuration file. Note that TDcal does not use alert times given in event VALARM properties; those are stored but ignored! You configure your own desired alert schedules both globally and on a per-calendar basis in the configuration file.
The icon can be hovered over to see a pop-up showing forthcoming calendar events. Clicking on the icon opens the TDcal GUI program, tdg.
tdt is usually also started by running it from your login or window-manager startup scripts and leaving it running the whole time you are logged in.
tdg provides a user-interface displaying a calendar, navigation buttons to change dates, and shows events for the day in an all-day panel and a 15-minute timeslot panel. Events can be edited, moved, resized, copied, moved to other days, deleted and even moved to other calendars from this interface.
The interface is intuitive to use, supporting Xorg mouse select/paste, ICCCM-style Ctrl-C/Ctrl-X/Ctrl-V copy/cut/paste, as well as its own Alt-C/Alt-X/Alt-V event manipulation copy/cut/paste.
Events can be moved using Shift-Button1 dragging and they can be resized using Alt-Button1 dragging.
All changes to events are done in the local copy of the calendar stored on your computer. Default behavior is that changes are synchronized to CalDAV servers on a periodic basis by the tdd synchronization daemon. tdg can be configured to send changes to servers immeidately if so desired.
td can import and export whole calendars in iCalendar .ics format, search for and display events and events can be extracted from the calendar into a file for manual or scripted editing and then put back into the calendar.
td has numerous options to control its behaviour. Run it with the -x flag for an explanation of the options and read its manual page for full details.
OAuth is a multi-stage authorization framework that is intended to be more secure than a simple username and password. It is, however, a good bit more complex.
Normally, developers of applications that wish to access private data on such cloud services would create an application client account on the service provider, register the application, obtain client credentials for the application, and then distribute the application containing those credentials ready for users to use. Then when you, the user, use the application, the service first requests that you approve the application's request to access your private data. After that, the application receives access tokens to access that data and it can then proceed to do so.
TDcal does fully support registration as an OAuth client application with OAuth service providers. However, the process of creating and maintaining an OAuth application project with each such service provider involves setting up the client account, registering the application, generating its credentials and then going through application validation and web site validation. Doing that, and repeating it all with each service provider that requires OAuth, is not something that the TDcal developer has any interest in nor the time for.
There is also the issue of it being unclear if open-source software such as this is supposed to distribute an OAuth client_id and a client_secret since, by doing so, anyone could copy those credientials and use them in another app and masquerade as TDcal.
Therefore, the steps to register the application and obtain client credentials are left to you, the user, to do for yourself!
See the notes for the various services, below, for how to proceed, and also read the tdoauth manual page for additional information and the parameters you will need to complete the registration.
Once you have your own application credentials for TDcal, these are put in your ~/.td configuration file.
Then, the OAuth authorization setup tool, tdoauth is run in order to go through the steps to grant access to your account.
All this is a bit of a hassle, yes. But it is arguably better this way because you have total control of access grants to your account and there is no worry at all about privacy because the TDcal developer isn't involved in accessing your account in any way at all.
The good thing is that it works well once you have gone though all the steps.
The library consists of the main TDcal.pm library as well as several additional packages, such as TDcal/CalDAV.pm, TDcal/Fetch.pm, TDcal/iCalendar.pm, etc, that implement specific functionality. Interested developers can start by reading the TDcal(3) manual page which then refers to additional manual pages for the other packages.
The translation files are in the tdcal/po directory. Simply copy the TDcal.pot template to LL.po and edit it with translations of all messages. Also copy the help file en.help to LL.help and translate that too. Then send them to the author at the email address below.
Use of UTF-8 encoding is strongly preferred and requested.
For more information, see the GNU gettext manual.
It should be noted, however, that many other calendar programs and mobile applications do not have full RRULE support. Often they cannot handle multiple BYxyz specifiers at the same time or they do not handle BYSETPOS at all, or they approximate it. This can mean that events with complex repetition specifications display fine in TDcal but display on incorrect dates, or even not at all, on other calendar apps.
As an example, if you wish to pay a bill two weekdays before a specific day of the month, you would need a rule similar to this, which works if your bill's due date is the 23rd:
FREQ=MONTHLY;BYMONTHDAY=19,20,21,22;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2meaning the 2nd-last weekday between the 19th-22nd. This displays correctly in TDcal and also on several tested CalDAV servers. But, oddly, it displays as "the last weekday of the month" on the calendar app on the author's phone app so it appears there, incorrectly, anywhere between the 26th-31st, depending on the month. (And that's the stock calendar app from one of the major phone vendors.)
Similarly, a simpler rule for the 2nd-last weekday of the month:
FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2which, again, displays correctly in TDcal and on the author's CalDAV server, but does not display at all on the calendar app on the author's phone! (Again, the stock calendar app from one of the major phone vendors.)
The point here is that one should avoid complex rules and rules that use BYSETPOS in particular, if you are concerned that events display correctly on other apps too.
This is because TDcal has to match the system's installed timezone definition with those in the zoneinfo database to determine the timezone names. On FreeBSD and Linux systems, the system timezone information (the zoneinfo database) is imported from Olson timezone sources. During 2022, the maintainers of the Olson timezone sources updated many zone definitions that share a common set of rules with the definition being given for one zone which is installed first. The other common zones are then installed by copying the first. (In the Olson sources, the subsequent zones have ‘Link’ directives.) When attempting to determine the zone name, TDcal's timezone.pm library searches the zoneinfo database for the first file (in directory order) matching the installed zone file in /etc/localtime and it returns the name of first matched file found.
E.g., as of late 2022, the following zones are copies:
Europe/Brussels Europe/Amsterdam Europe/LuxembourgThe name of all three zones will display as the first.
Note that the directory order is not necessarily the first file installed. On UFS filesystems it likely will be. But on ZFS filesystems, directory ordering is based on a name hash algorithm. So the tzdata zone definition for the following:
Asia/Bangkok Asia/Phnom_Penh Asia/Vientiane Indian/Christmasactually returns Indian/Christmas for any of the other three when on a ZFS filesystem.
Note that your zone names may be fine now, but may change after updating the system zoneinfo database because the new version links zones together wheras the older version did not.
It is important that your timezone name reflects the closest country or region applicable to you. Your timezone may share a common definition with a neighboring country now but this could change in the future, for example as governments update daylight savings time rules.
If you need to override the timezone name, the good news is that the TDcal timezone.pm library does also know about the file /etc/timezone so if the name that is returned is not as you wish, you can override it by specifying a name in this file. E.g.:
echo Europe/Amsterdam >/etc/timezone or: echo Asia/Bangkok >/etc/timezoneRemember then, that if you travel and change timezones, you will have to update both the /etc/localtime file and the /etc/timezone file. The script tzchange.sh may be of use to you when updating your system's timezone files after travelling.
The timezone can also be overridden by setting the environment variable TZ or by defining a variable TZ= in /etc/TIMEZONE.
Versions of TDcal prior to 0.98 used to use the CPAN DateTime::TimeZone library. It does the same lookup and it also allowed the zone name to be overridden in /etc/timezone. However in late 2022, this library was itself updated to validate timezone names and is incorrectly returning the first installed zoneinfo name even when it is overriden in /etc/timezone.
Server | URL |
---|---|
Notes | |
Baïkal | https://yourserver.example.com/baikal/dav.php/ |
Works well.
Calendars containing non-ASCII characters in their display names such as ‘My Baïkal Calendar’ are likely to be displayed like ‘My Ba�kal Calendar’ due to the server substituting such characters with the UTF-8 Replacement Character. This is a |
|
Fruux | https://dav.fruux.com/ |
Works well.
You must log on to the web site and create an application-specific password. |
|
https://apidata.googleusercontent.com/caldav/v2/ | |
Works well.
Google requires the use of the OAuth authorization framework in order to access private data in your account. On Google, to register the application and obtain application client credentials, this involves creating a project on your Google Cloud Console, enabling the CalDAV API for the project, creating an OAuth client registration with access scope to your calendar, and obtaining client credentials which you then put into your ~/.td configuration file. Since you are registering a client app for your own use, you do not need to go through the steps of client validation or website validation. After storing your client credentials, you will need to run tdoauth to actually grant authorization to TDcal to access your calendar data. Read the tdoauth manual page for details of the parameters you will need for registering the app and obtaining client credentials. You can control which of your Google calendars are enabled for syncing using CalDAV by logging on to your Google account and then visiting this URL: https://calendar.google.com/calendar/u/0/syncselect | |
nextCloud | https://yourserver.example.com/nextcloud/remote.php/dav/ |
Works well.
If 2-factor-authentication is enabled, you must log on to the web site and create an application-specific password. nextCloud v22 implemented a calendar trashbin feature that retains deleted events in a trashbin for a default period of 30 days. A bug in this feature causes nextCloud to reject an update to an event in the trashbin. This can cause Alt-X/Alt-V moves to fail if the Alt-X deletion was sent to the server before the Alt-V update happened. The error message in .td.log is: http error example.com 400 on PUT URL: Deleted calendar object with uid already exists in this calendar collection.As a work-around to avoid this, the nextCloud calendar trashbin feature can be disabled by the nextCloud administrator by running this command: php occ config:app:set dav calendarRetentionObligation --value=0A problem report exists (nextCloud issue #30096) for nextCloud to change the trashbin behavior so that CalDAV updates to deleted events restore the event from the trashbin rather than failing. |
|
ownCloud | https://yourserver.example.com/owncloud/remote.php/dav/ |
Works well.
If 2-factor-authentication is enabled, you must log on to the web site and create an application-specific password. |
|
Radicale | https://yourserver.example.com/radicale/ |
Works well. | |
Yahoo! | https://caldav.calendar.yahoo.com/ |
You must log on to the web site and create an application-specific password.
Yahoo! Calendar's CalDAV implementation has some significant unusual aspects:
|
The lastest development version of the source can be downloaded from the Opal Git server:
git://opal.com/src/tdcal/
STABLE VERSIONS
BETA TESTERS WANTED
The current version is tdcal-0.120.tar.xz 2024/10/17 17:05 UTC.
If you are interested in giving it an early try-out and are willing to send feedback, please contact the developer by email at tdcal@opal.com. Thanks!