Top Banner
ERGroupware Pascal Robert Druide informatique
42

ERGroupware

May 15, 2015

Download

Technology

WO Community

Learn about how you can connect to CalDAV, MS Exchange and Zimbra servers with his upcoming Project Wonder framework.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: ERGroupware

ERGroupwarePascal RobertDruide informatique

Page 2: ERGroupware

• 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?

Page 3: ERGroupware

iCalendar generation

Page 4: ERGroupware

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

Page 5: ERGroupware

iCalendar example

BEGIN:VCALENDARVERSION:2.0PRODID:-//Apple Inc.//Mac OS X 10.8.4//ENCALSCALE:GREGORIANBEGIN:VEVENTTRANSP:OPAQUEDTEND:20130623T101500UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4DTSTAMP:20130514T135551ZLOCATION:Verdun/Lachine/LasalleX-MOZ-GENERATION:1URL;VALUE=URI:http://www.wocommunity.org/wowodc13/cayenne.htmlSEQUENCE:10SUMMARY:Cayenne Training DayLAST-MODIFIED:20130509T165550ZDTSTART:20130623T091500CREATED:20130505T001152ZEND:VEVENTEND:VCALENDAR

Page 6: ERGroupware

UID

• Each component must have a UID

• UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4

• And it must be unique!

Page 7: ERGroupware

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!

Page 8: ERGroupware

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

Page 9: ERGroupware

iCalendar file generation

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.setClassification(ERGWClassification.PUBLIC); event.setFreeBusyStatus(ERGWFreeBusyStatus.BUSY_TENTATIVE); event.setLocation("Montreal"); event.setCategories(new NSArray<String>(new String[] { "Category 1", "Category 2" })); event.setPriority(ERGWPriority.HIGH); event.setSummary("WOWODC 2013"); event.setTransparency(ERGWTransparency.TRANSPARENT); Calendar calendarData = ERGWCalendar.transformToICalObject(aCalendar); ERGWPublishCalendarPage nextPage = (ERGWPublishCalendarPage)pageWithName(ERGWPublishCalendarPage.class); nextPage.setCalendar(calendarData); return nextPage;

Page 10: ERGroupware

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

Page 11: ERGroupware

CalDAV

• Open standard, defined in RFC 4791

• Servers must implements this RFC

• Many extensions

• Scheduling

• Delegations

• Sharing

• etc.

Page 12: ERGroupware

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.

Page 13: ERGroupware

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.

Page 14: ERGroupware

OPTIONS request

$ curl --digest --user probert -X OPTIONS -v http://localhost:8008

< DAV: 1, access-control, calendar-access, calendar-schedule, calendar-auto-schedule, calendar-availability, inbox-availability, calendar-proxy, calendarserver-private-events, calendarserver-private-comments, calendarserver-sharing, calendarserver-sharing-no-scheduling, calendar-query-extended, calendar-default-alarms, addressbook, extended-mkcol, calendarserver-principal-property-search, calendarserver-principal-search

Page 15: ERGroupware

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...)

Page 16: ERGroupware

iCalendar objects

• You store iCalendar objects in calendar collections.

• But you can only store ONE component (VTODO, VEVENT, etc.) per object.

Page 17: ERGroupware

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.

Page 18: ERGroupware

Example of creating event

PUT /calendars/__uids__/AD04C60B-3704-447B-8997-24F5ACF589C7/calendar/C440-473C-8FAD-D3E606159F40.ics HTTP/1.1If-None-Match: 1f9e6e30-dfdb-4e5c-baf6-6dd107126a68Content-Type: text/calendar

BEGIN:VCALENDARVERSION:2.0PRODID:-//Apple Inc.//Mac OS X 10.8.4//ENCALSCALE:GREGORIANBEGIN:VEVENTATTENDEE;CN="[email protected]";CUTYPE=INDIVIDUAL:mailto:[email protected];CN="Pascal Robert";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7DTEND;VALUE=DATE:20130616TRANSP:TRANSPARENTORGANIZER;CN="Pascal Robert":urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7UID:B54100D2-C440-473C-8FAD-D3E606159F40DTSTAMP:20130615T123551ZLOCATION:Hilton Montréal BonaventureSEQUENCE:9SUMMARY:Test for presentationDTSTART;VALUE=DATE:20130615CREATED:20130615T123241ZEND:VEVENTEND:VCALENDAR

Page 19: ERGroupware

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

Page 20: ERGroupware

Connecting

import net.fortuna.ical4j.connector.ObjectStoreException;import net.fortuna.ical4j.connector.dav.PathResolver;import er.groupware.caldav.CalDAVStore;import java.net.URL;

CalDAVStore store = null;try { store = new CalDAVStore("probert", "somepassword", new URL("http://127.0.0.1"), PathResolver.ICAL_SERVER);}catch (MalformedURLException e) { e.printStackTrace();}catch (ObjectStoreException e) { e.printStackTrace();}

Page 21: ERGroupware

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(); }

Page 22: ERGroupware

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));

Page 23: ERGroupware

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

Page 24: ERGroupware

Find events by time range

REPORT /bernard/work/ HTTP/1.1 Depth: 1 Content-Type: application/xml; charset="utf-8"

<?xml version="1.0" encoding="utf-8" ?> <C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <D:prop> <C:calendar-data> <C:limit-recurrence-set start="20060103T000000Z" end="20060105T000000Z"/> </C:calendar-data> </D:prop> <C:filter> <C:comp-filter name="VCALENDAR"> <C:comp-filter name="VEVENT"> <C:time-range start="20060103T000000Z" end="20060105T000000Z"/> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>

Page 25: ERGroupware

Find participants that didn't not accept invitations

REPORT /bernard/work/ HTTP/1.1 Depth: 1 Content-Type: application/xml; charset="utf-8"

<?xml version="1.0" encoding="utf-8" ?> <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav"> <D:prop xmlns:D="DAV:"> <D:getetag/> <C:calendar-data/> </D:prop> <C:filter> <C:comp-filter name="VCALENDAR"> <C:comp-filter name="VEVENT"> <C:prop-filter name="ATTENDEE"> <C:param-filter name="PARTSTAT"> <C:text-match collation="i;ascii-casemap">NEEDS-ACTION</C:text-match> </C:param-filter> </C:prop-filter> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>

Page 26: ERGroupware

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()

Page 27: ERGroupware

DEMO

Page 28: ERGroupware

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

Page 29: ERGroupware

Example of request

---[HTTP request - https://webmail.sherweb2010.com/EWS/Exchange.asmx]---Content-type: text/xml;charset="utf-8"Soapaction: "http://schemas.microsoft.com/exchange/services/2006/messages/SyncFolderHierarchy"Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header> <MailboxCulture xmlns="..." xmlns:ns2="...">en-US</MailboxCulture> <RequestServerVersion xmlns="..." xmlns:ns2="..." Version="Exchange2007_SP1"/> </S:Header> <S:Body> <ns2:SyncFolderHierarchy xmlns="..." xmlns:ns2="..."> <ns2:FolderShape> <BaseShape>IdOnly</BaseShape> <AdditionalProperties> <FieldURI FieldURI="folder:DisplayName"/> <FieldURI FieldURI="folder:FolderClass"/> <ExtendedFieldURI PropertyType="Boolean" PropertyTag="0x10F4"/> </AdditionalProperties> </ns2:FolderShape> </ns2:SyncFolderHierarchy> </S:Body></S:Envelope>

Page 30: ERGroupware

Example of response

<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <h:ServerVersionInfo ... Version="Exchange2010_SP2" /> </s:Header> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <m:SyncFolderHierarchyResponse xmlns:m="..." xmlns:t="..."><m:ResponseMessages> <m:SyncFolderHierarchyResponseMessage ResponseClass="Success"> <m:ResponseCode>NoError</m:ResponseCode> <m:SyncState>H4sIAAAAAAAEAO29B2AcSZYlJi9tynt...</m:SyncState> <m:Changes> <t:Create> <t:Folder> <t:FolderId Id="AAMkAGEw...=" ChangeKey="AQAAABYAAACT3PaCL/2ASLnqcq9Sv0/DAAAAp5Bv"/> <t:FolderClass>IPF.Note</t:FolderClass> <t:DisplayName>INBOX</t:DisplayName> <t:ExtendedProperty> <t:ExtendedFieldURI PropertyTag="0x10f4" PropertyType="Boolean"/> <t:Value>false</t:Value> </t:ExtendedProperty> </t:Folder> </t:Create> </m:Changes>...

Page 31: ERGroupware

EWS support in ERGroupware

• Generated with JAXB.

• Very basic support outside the generated classes:

• Open connection

• Create folders

• Create task

• Create contact

• Create event

Page 32: ERGroupware

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()); }

Page 33: ERGroupware

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); }}

Page 34: ERGroupware

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); }}

Page 35: ERGroupware

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("[email protected]"); 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); }}

Page 36: ERGroupware

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 folderstore.createCalendarFolder(String displayName)

// Shortcut to create a contacts folderstore.createContactsFolder(String displayName)

Page 37: ERGroupware

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

Page 38: ERGroupware

Example of request

POST /service/soap/CreateAppointmentRequest HTTP/1.1Content-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="[email protected]"/> <at d="Pascal Robert" cutype="IND" a="[email protected]"/> <at d="Salle 1" cutype="ROO" a="[email protected]"/> <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>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></content> </mp> </m> </CreateAppointmentRequest> </soap:Body></soap:Envelope>

Page 39: ERGroupware

Example response

HTTP/1.1 200 OKContent-Type: text/xml;charset=UTF-8

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Header> <context xmlns="urn:zimbra"><session id="11">11</session><change token="602"/> <notify seq="2"> <created> <appt id="283" uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" rev="602" s="0" l="10"> <inv id="282" seq="0" compNum="0" type="appt"> <tz id="America/Montreal" stdoff="-300" dayname="EDT" dayoff="-240" stdname="EST">...</tz> <comp uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" status="CONF" ...> <at d="Pascal Robert" cutype="IND" a="[email protected]" url="[email protected]"/> <at d="Salle 1" cutype="ROO" a="[email protected]" url="[email protected]"/> <xprop name="X-RELATED-TO" value="281-280"/> <desc>Une plus long description</desc> <descHtml>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></descHtml> <or d="Pascal Robert" a="[email protected]" url="[email protected]"/> <s u="1371632938000" d="20130619T050858" tz="America/Montreal"/> <e d="20130619T070858" u="1371640138000" tz="America/Montreal"/> </comp> </inv> </appt> </created> <modified><folder id="10" i4next="284" s="0" i4ms="602" n="3" uuid="6630b004-40cd-49b4-af4b-eca7bac45be6"/></modified> </notify> </context> </soap:Header> <soap:Body> <CreateAppointmentResponse rev="602" ms="602" invId="283-282" apptId="283" calItemId="283" xmlns="urn:zimbraMail"/> </soap:Body></soap:Envelope>

Page 40: ERGroupware

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

Page 42: ERGroupware

Q&A