2. • Let you generate iCalendar files, à la ERCalendar
• Let you connect to groupware solutions
• CalDAV
• MS Exchange 2007/2010
• Zimbra
• Many Bothans have died to provide this framework
What is ERGroupware?
4. iCalendar
• iCalendar is a standard (RFC 2445, written in 1998).
• A iCalendar object can have multiple components (VEVENT,
VTODO, etc.)
• Text file, with Base64 encoding for binary
• Key value
• You can add your own keys
5. iCalendar example
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
TRANSP:OPAQUE
DTEND:20130623T101500
UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4
DTSTAMP:20130514T135551Z
LOCATION:Verdun/Lachine/Lasalle
X-MOZ-GENERATION:1
URL;VALUE=URI:http://www.wocommunity.org/wowodc13/cayenne.html
SEQUENCE:10
SUMMARY:Cayenne Training Day
LAST-MODIFIED:20130509T165550Z
DTSTART:20130623T091500
CREATED:20130505T001152Z
END:VEVENT
END:VCALENDAR
6. UID
• Each component must have a UID
• UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4
• And it must be unique!
7. Attendees
• Attendees are invitees.
• Can be a individual, group, resource or room. (CUType)
• Also have status: needs action, accepted, etc. (Partstat)
• If you have attendees, you also need an organizer!
8. iCalendar in ERGroupware
• Similar to ERCalendar, but more modern and better validation.
• Using iCal4j, a solid iCalendar library for Java.
• Component to generate the file.
• Will generate a text/calendar response
10. CalDAV/CardDAV
• Both based on WebDAV
• Will store iCalendar objects (CalDAV) or vCard objects
(CardDAV)
• Many many server implementations
• But some of them are really basic (Google Calendar...)
• iCal Server is the best implementation
• Many clients too
11. CalDAV
• Open standard, defined in RFC 4791
• Servers must implements this RFC
• Many extensions
• Scheduling
• Delegations
• Sharing
• etc.
12. CalDAV
• Calendars are DAV collections.
• DAV collections have properties (ACL, owner, etc.).
• Can create as many collections as you want.
• Other DAV collections exists too.
13. Features/extensions
• CalDAV servers must send the supported features set in the
response.
• Can do a OPTIONS request to see them.
• Check the DAV header in the response.
15. CalDAV and HTTP
• Almost REST-like
• Use HTTP verbs
• GET: fetch a object
• PUT: create OR update a object
• DELETE: delete a object
• MKCALENDAR: create a calendar collection
• Use headers, HTTP authentication (Basic, Digest, Kerberos...)
16. iCalendar objects
• You store iCalendar objects in calendar collections.
• But you can only store ONE component (VTODO,VEVENT,
etc.) per object.
17. PUT
• CalDAV don't use POST to create objects.
• Must use PUT
• If URL and UID already exists, will update the object.
• If URL and UID don't exists, will create the object.
• If URL don't exist but UID exist, will conflict.
• Creating a object will return a 201 status code.
• If you copy an object, don't forget to change the UID.
18. Example of creating event
PUT /calendars/__uids__/AD04C60B-3704-447B-8997-24F5ACF589C7/calendar/C440-473C-8FAD-D3E606159F40.ics HTTP/1.1
If-None-Match: 1f9e6e30-dfdb-4e5c-baf6-6dd107126a68
Content-Type: text/calendar
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
ATTENDEE;CN="probert@macti.ca";CUTYPE=INDIVIDUAL:mailto:probert@macti.ca
ATTENDEE;CN="Pascal Robert";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7
DTEND;VALUE=DATE:20130616
TRANSP:TRANSPARENT
ORGANIZER;CN="Pascal Robert":urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7
UID:B54100D2-C440-473C-8FAD-D3E606159F40
DTSTAMP:20130615T123551Z
LOCATION:Hilton Montréal Bonaventure
SEQUENCE:9
SUMMARY:Test for presentation
DTSTART;VALUE=DATE:20130615
CREATED:20130615T123241Z
END:VEVENT
END:VCALENDAR
19. CalDAV support in ERGroupware
• Based on iCal4j-connector, which I contributed to.
• Support for most CalDAV operations.
• Get calendars (collections)
• Create calendars
• Fetch/delete/update calendar objects
• Delete collections
• Fetch events by time-range
21. Fetching calendar collections and objects
NSArray<CalDAVCollection> collections = store.getCollections();
for (CalDAVCollection collection: collections) {
NSLog.out.appendln(collection.displayName());
// Fetch all events (e.g, VEVENT objects)
NSArray<ERGWCalendar> events = collection.events();
// Fetch all tasks (e.g, VTOTO objects)
NSArray<ERGWCalendar> tasks = collection.tasks();
}
22. Manipuling calendar objects
// Create a new event and send it to the server
ERGWCalendar aCalendar = new ERGWCalendar();
ERGWEvent event = new ERGWEvent(aCalendar);
java.util.Calendar startTime = GregorianCalendar.getInstance();
event.setStartTime(new NSTimestamp(startTime.getTimeInMillis()));
java.util.Calendar endTime = GregorianCalendar.getInstance();
endTime.add(java.util.Calendar.HOUR, 2);
event.setEndTime(new NSTimestamp(endTime.getTimeInMillis()));
event.setSummary("WOWODC 2013");
collection.addCalendarObject(aCalendar);
// Update the event and send it to the server
aCalendar.events().objectAtIndex(0).setSummary("WOWODC 2014");
collection.updateCalendarObject(aCalendar);
// Delete the event
collection.removeCalendarObject(aCalendar.events().objectAtIndex(0));
23. Queries
• REPORT request is the same idea as a SQL SELECT query.
• Let's you find calendar objects with a qualifier.
• "Find all todos that are completed"
• "Find events from June 22 to June 24"
• "Find all rooms"
• Won't work for custom properties
26. Queries support in ERGroupware
• Query by time range
• CalDavCollection.eventsForTimePeriod(java.util.Date startTime,
java.util.Date endTime)
• Find all individuals
• store.getIndividuals(String name);
• Find rooms or resources
• store.getAllRooms()
• store.getAllResources()
28. MS Exchange
• Exchange Web Service (EWS)
• Based on SOAP
• Same protocol that Outlook 2011 uses
• Most EWS attributes are similar to iCalendar and DAV
collections attributes
31. EWS support in ERGroupware
• Generated with JAXB.
• Very basic support outside the generated classes:
• Open connection
• Create folders
• Create task
• Create contact
• Create event
32. Opening a connection and fetch folders
URL urlToWSDL = ERXApplication.application().resourceManager().pathURLForResourceNamed("Services.wsdl",
"ERGroupware", null);
ExchangeStore store = new ExchangeStore(urlToWSDL, "https://myserver/EWS/Exchange.asmx", "aUser",
"aPassword", "AD.DOMAIN");
store.setServerVersionForRequest(ExchangeVersionType.EXCHANGE_2010_SP_1);
store.setTimeZone(TimeZone.getDefault());
NSArray<ExchangeBaseFolder> folders = store.folders();
for (ExchangeBaseFolder folder: folders) {
NSLog.out.appendln(folder.displayName());
}
33. Adding an event
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Calendar")) {
ERGWCalendar calendar = new ERGWCalendar();
calendar.setCalendarName("Test");
calendar.setTimeZone(TimeZone.getDefault());
Calendar later = GregorianCalendar.getInstance();
later.add(Calendar.HOUR_OF_DAY, 1);
event.setEndTime(new NSTimestamp(later.getTime()));
UidGenerator uidGen = new UidGenerator("allo");
event.setUid(uidGen.generateUid().getValue());
ERGWEvent event = new ERGWEvent(calendar);
event.setIsFullDay(false);
event.setStartTime(new NSTimestamp());
event.setSummary("WOWODC 2013");
event.setLastModifiedDate(new NSTimestamp());
calendar.addEvent(event);
exchangeStore.createCalendarEvent(calendar, (ExchangeCalendarFolder) folder);
}
}
34. Adding an event
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Tasks")) {
ERGWCalendar calendar = new ERGWCalendar();
calendar.setCalendarName("Test");
calendar.setTimeZone(TimeZone.getDefault());
Calendar later = GregorianCalendar.getInstance();
later.add(Calendar.HOUR_OF_DAY, 1);
task.setDueDate(new NSTimestamp(later.getTime()));
UidGenerator uidGen = new UidGenerator("allo");
event.setUid(uidGen.generateUid().getValue());
ERGWTask task = new ERGWTask(calendar);
task.setSummary("Finish that presentation");
task.setLastModifiedDate(new NSTimestamp());
calendar.addEvent(event);
exchangeStore.createTask(calendar, (ExchangeCalendarFolder) folder);
}
}
35. Adding a contact
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Contacts")) {
ERGWContact contact = new ERGWContact();
contact.setGivenName("Pascal");
contact.setFamilyName("Robert");
ERGWContactEmail personalEmail = new ERGWContactEmail();
personalEmail.setEmail("probert@macti.ca");
personalEmail.isPrefered(true);
personalEmail.setTypes(new NSArray<ERGWContactEmailType>(new ERGWContactEmailType[]
{ ERGWContactEmailType.HOME }));
contact.setEmails(new NSArray<ERGWContactEmail>(new ERGWContactEmail[] { personalEmail }));
exchangeStore.createContact(contact, (ExchangeCalendarFolder) folder);
}
}
36. Create folders
// Create a folder of a specific type
// ERGWFolderType values are: CALENDAR, CONTACTS, TASKS, SEARCH, PLAIN, etc.
store.createFolder("New calendar folder", ERGWFolderType.CALENDAR);
store.createFolder("New contacts folder", ERGWFolderType.CONTACTS);
// Shortcut to create a calendar folder
store.createCalendarFolder(String displayName)
// Shortcut to create a contacts folder
store.createContactsFolder(String displayName)
37. Zimbra
• SOAP and REST-based API.
• Have API for everything: management, data and Web client
(Zimlets).
• Very basic support in ERGroupware (need to migrate a lot of
code)
• Connect to store
• Add folder
38. Example of request
POST /service/soap/CreateAppointmentRequest HTTP/1.1
Content-Type: text/xml; charset=utf-8
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<context xmlns="urn:zimbra"><authToken>0_b6e206e6c3eee19a7e89f717d5972d9d6b9db224</authToken>...</context>
</soap:Header>
<soap:Body>
<CreateAppointmentRequest xmlns="urn:zimbraMail">
<m l="10">
<inv>
<comp status="CONF" allDay="0" name="Titre de la rencontre" loc="Montr[0xc3][0xa9]al" class="PUB" transp="O" fb="B">
<s d="20130619T050858" tz="America/Montreal"/>
<e d="20130619T070858" tz="America/Montreal"/>
<or d="Pascal Robert" a="root@zimbra.macti.lan"/>
<at d="Pascal Robert" cutype="IND" a="probert@macti.ca"/>
<at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan"/>
<xprop name="X-RELATED-TO" value="281-280"/>
</comp>
</inv>
<su>Titre de la rencontre</su>
<mp ct="multipart/mixed"><mp ct="text/plain">
<content>Une plus long description</content>
</mp>
<mp ct="text/html">
<content><html><body> Une plus long description</body></html></content>
</mp>
</m>
</CreateAppointmentRequest>
</soap:Body>
</soap:Envelope>
40. TODO
• Move away from ical4j-connector
• Complete CalDAV and CardDAV support
• Complete calendar, contacts and email support for Zimbra
• Management API for Kerio, CGP and Zimbra