Skip to content

CardDAV Integration

mikedeboer edited this page Feb 24, 2013 · 1 revision

CardDAV Integration

Introduction

If you are looking at jsDAV to add CalDAV or CarDAV functionality to your existing application, you'll need to roll your own Backend classes. This guide explains how and where to do this.

A simple CalDAV server

The following example illustrates how you can setup a CalDAV server. This is also how you'd want to build up your own server.

// Database driver to use. 'redis' is the default, but feel free to use anything 
// else supported by jsDAV
var DB_DRIVER = "redis";

var jsDAV = require("./../lib/jsdav");
var jsDAV_Auth_Backend = require("./../lib/DAV/plugins/auth/" + DB_DRIVER);
var jsDAVACL_PrincipalBackend = require("./../lib/DAVACL/backends/" + DB_DRIVER);
var jsCardDAV_Backend = require("./../lib/CardDAV/backends/" + DB_DRIVER);
// node classes:
var jsDAVACL_PrincipalCollection = require("./../lib/DAVACL/principalCollection");
var jsCardDAV_AddressBookRoot = require("./../lib/CardDAV/addressBookRoot");
// plugins:
var jsDAV_Auth_Plugin = require("./../lib/DAV/plugins/auth");
var jsDAV_Browser_Plugin = require("./../lib/DAV/plugins/browser");
var jsCardDAV_Plugin = require("./../lib/CardDAV/plugin");
var jsDAVACL_Plugin = require("./../lib/DAVACL/plugin");

var Db = require("./../lib/shared/backends/" + DB_DRIVER);

var DB_INIT = require("./data/addressbook/" + DB_DRIVER);
// Arguments to be passed to the function that establishes a connection with the db
var DB_ARGS = [];

// Database connection
var db = Db.getConnection.apply(Db, DB_ARGS);

// Make sure this setting is turned on and reflect the root url for your WebDAV server.
// This can be for example the root / or a complete path to your server script
var baseUri = "/";

// set it up for demo use:
DB_INIT.init(db, function(err) {
    if (err)
        throw(err);
    
    // Backends
    var authBackend = jsDAV_Auth_Backend.new(db);
    var principalBackend = jsDAVACL_PrincipalBackend.new(db);
    var carddavBackend = jsCardDAV_Backend.new(db);
    
    // Setting up the directory tree
    var nodes = [
        jsDAVACL_PrincipalCollection.new(principalBackend),
        jsCardDAV_AddressBookRoot.new(principalBackend, carddavBackend)
    ];
    
    jsDAV.createServer({
        node: nodes,
        baseUri: baseUri,
        authBackend: authBackend,
        realm: "jsDAV",
        plugins: [jsDAV_Auth_Plugin, jsDAV_Browser_Plugin, jsCardDAV_Plugin, jsDAVACL_Plugin]
    }, 8000);
});

To setup the Redis database (or mongo, if you prefer), follow the instructions on the CardDAV page.

Setting up a CardDAV server is extremely similar. For examples you can also head over to the CardDAV page or check the examples/ directory in the standard jsDAV distribution.

Backends

If you want to integrate CardDAV into your existing infrastructure, you can do so by creating your own Authentication, Principal and Calendar backends. Depending on your needs you may want to replace all of them, or just the ones that make sense for your application.

Your Authentication class needs to implement the jsDAV_Auth_iBackend interface. If you want to use basic or digest authentication (the only widely supported authentication methods) you can also extend jsDAV_Auth_Backend_AbstractDigest or jsDAV_Auth_Backend_AbstractBasic. jsDAV_Auth_Backend_Redis is a decent example for digest authentication.

Lastly, the principal backend must implement jsDAVACL_PrincipalBackend_iBackend. Principals are in the context of WebDAV either users or groups (or both).

For CardDAV, you may also want to extend jsCardDAV_Backend_AbstractBackend, check jsCardDAV_Backend_Redis for an example.

Datamodel in a nutshell

Users are called 'principals' in WebDAV terminology. Principals are associated to a url. If your username is homer, the url could be /principals/homer or /principals/homer@example.org

CalDAV and CardDAV clients may use this url to gather more information about the user. You must return this url from the Auth backend, and it will be used in the Addressbook backend to return all the calendars from a specific user.

Calendars are stored under for example:

/calendars/homer@example.org/

A user has multiple calendars. An example of a calendar could for example be:

/calendars/homer@example.org/work

Calendar objects (events, todo's, journals) are stored as resources under this url:

/calendars/homer@example.org/work/meeting.ics

Similarly, by default addressbooks will be stored under

/addressbooks/homer@example.org

Specific addressbooks under there:

/addressbooks/homer@example.org/book1

and vcards under there:

/addressbooks/homer@example.org/book1/marge.vcf

UUIDS, id's and urls

There's a bunch of id's you will need to keep track off.

When CalDAV clients create new calendar objects, they will store them using a url. This url can look like for example /calendars/user@example.org/1b520550-d7ca-11df-937b-0800200c9a66/22bad740-d7ca-11df-937b-0800200c9a66.ics

The last part of this url is the calendar object. You must make sure that when a CalDAV client stores a new object under a url, the client must be able to access the object using that url.

This could mean you need to make a new database field for this url. Even though most clients use the uuid.ics format, you can't rely on the url to e an uuid. Any string could be sent, and upper/lowercase can vary. Therefore it's not a true uuid field.

The jsCalDAV_Backend_AbstractBackend class also uses a generic 'id' field. This id is never sent to the client. It can hold any content, but it's specifically added to allow you to store for example a database id.

Calendar objects

Calendar objects are 'iCalendar' formatted files. They can hold events, todo's or journals (although the latter is extremely uncommon). Generally they only hold one event each, but in the case of a recurring event with exceptions, they can hold multiple.

Now, there's a good chance you want to map Calendar objects to an existing datamodel. If you do have to do this, you can do this with the VObject library, which is included with jsDAV.

The VObject library provides a parser and interface to iCalendar objects very similar to what the jsdom module does for xml.

Although it must be said that the iCalendar standard can be difficult, especially when dealing with timezone and recurrence. If you need to parse out data from the events and todo's to store them in separate fields, I would still recommend keeping the actual full object around in a BLOB. This will ensure that you can easily parse out the data you need, while ensuring all the users' data is kept intact.

VCards

VCards' structure are very similarly structured as iCalendars. You can also use the VObject library to work with them.

You still need a basic understanding how vcards are structured. The VObject library just helps with parsing, traversing and manipulating them.

Based on the original document at http://code.google.com/p/sabredav/wiki/