summaryrefslogtreecommitdiffstats
path: root/tderesources/newexchange/exchangeconvertercalendar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tderesources/newexchange/exchangeconvertercalendar.cpp')
-rw-r--r--tderesources/newexchange/exchangeconvertercalendar.cpp820
1 files changed, 820 insertions, 0 deletions
diff --git a/tderesources/newexchange/exchangeconvertercalendar.cpp b/tderesources/newexchange/exchangeconvertercalendar.cpp
new file mode 100644
index 000000000..bf2a66db9
--- /dev/null
+++ b/tderesources/newexchange/exchangeconvertercalendar.cpp
@@ -0,0 +1,820 @@
+/*
+ This file is part of the exchange resource.
+ Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
+ Parts are derived from the old libkpimexchange library:
+ Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "exchangeconvertercalendar.h"
+#include <webdavhandler.h>
+#include <libkcal/incidence.h>
+#include <libkcal/event.h>
+#include <libkcal/journal.h>
+#include <libkcal/todo.h>
+#include <libkcal/icalformat.h>
+#include <libemailfunctions/email.h>
+
+#include <kdebug.h>
+
+using namespace KCal;
+
+#define TaskNamespace1 "http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-C000-000000000046}/"
+#define TaskProp_Status "0x00008101"
+#define TaskProp_PercentCompleted "0x00008102"
+#define TaskProp_DtStart "0x00008104"
+#define TaskProp_DtDue "0x00008105"
+#define TaskProp_Duration "0x00008106"
+#define TaskProp_CompletionDate "0x0000810f"
+#define TaskProp_IsCompleted "0x0000811C"
+#define TaskProp_Owner "0x0000811F"
+#define TaskProp_DoesRecur "0x00008126"
+
+#define TaskNamespace2 "http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/"
+#define TaskProp_ReminderTime "0x00008502"
+#define TaskProp_ReminderSet "0x00008503"
+#define TaskProp_ReminderPlaySound "0x0000851E"
+#define TaskProp_ReminderSoundFile "0x0000851F"
+#define TaskProp_ContactNames "0x0000853A"
+
+
+ExchangeConverterCalendar::ExchangeConverterCalendar()
+{
+}
+
+void ExchangeConverterCalendar::setTimeZone( const TQString &id )
+{
+ // kdDebug() << "Setting timezone to: " << id << endl;
+ mFormat.setTimeZone( id, true );
+}
+
+#define propertyDAV( prop ) \
+ WebdavHandler::addElement( doc, root, "d:"prop )
+#define propertyNS( ns, prop ) \
+ WebdavHandler::addElementNS( doc, root, ns, prop )
+#define propertyCalendar( prop ) \
+ WebdavHandler::addElement( doc, root, "c:"prop )
+#define propertyHTTPMail( prop ) \
+ WebdavHandler::addElement( doc, root, "m:"prop )
+#define propertyMailHeader( prop ) \
+ WebdavHandler::addElement( doc, root, "h:"prop )
+#define property( prop ) \
+ WebdavHandler::addElement( doc, root, prop )
+
+void ExchangeConverterCalendar::createRequestIncidence( TQDomDocument &doc, TQDomElement &root )
+{
+ propertyDAV( "contentclass" );
+ propertyDAV( "getcontenttype" );
+ propertyNS( "http://schemas.microsoft.com/exchange/", "outlookmessageclass" );
+ propertyDAV( "getetag" );
+ propertyDAV( "href" );
+ propertyDAV( "isreadonly" );
+ propertyNS( "http://schemas.microsoft.com/repl/", "repl-uid" );
+ propertyHTTPMail( "subject" );
+ propertyHTTPMail( "textdescription" );
+ propertyHTTPMail( "date" );
+ propertyDAV( "comment" );
+ propertyNS( "urn:schemas-microsoft-com:office:office", "Keywords" );
+ propertyNS( "http://schemas.microsoft.com/exchange/", "sensitivity" );
+ propertyHTTPMail( "priority" );
+ propertyHTTPMail( "from" );
+ propertyHTTPMail( "to" );
+ propertyHTTPMail( "cc" );
+ propertyHTTPMail( "bcc" );
+ propertyHTTPMail( "hasattachment" );
+}
+
+void ExchangeConverterCalendar::createRequestAppointment( TQDomDocument &doc, TQDomElement &root )
+{
+ createRequestIncidence( doc, root );
+ TQDomAttr att_c = doc.createAttribute( "xmlns:c" );
+ att_c.setValue( "urn:schemas:calendar:" );
+ doc.documentElement().setAttributeNode( att_c );
+ propertyCalendar( "uid" );
+ propertyCalendar( "created" );
+ propertyCalendar( "lastmodified" );
+ propertyCalendar( "dtstamp" );
+ propertyCalendar( "sequence" );
+ propertyCalendar( "location" );
+ propertyCalendar( "busystatus" );
+ propertyCalendar( "transparent" );
+ propertyCalendar( "timezone" );
+ propertyCalendar( "alldayevent" );
+ propertyCalendar( "dtstart" );
+ propertyCalendar( "dtend" );
+ propertyCalendar( "duration" );
+ propertyCalendar( "rrule" );
+ propertyCalendar( "rdate" );
+ propertyCalendar( "exrule" );
+ propertyCalendar( "exdate" );
+ propertyCalendar( "recurrenceid" );
+ propertyCalendar( "instancetype" );
+ propertyCalendar( "reminderoffset" );
+ propertyCalendar( "resources" );
+}
+
+#define propertyTask1( prop ) \
+ WebdavHandler::addElement( doc, props, "t1:"prop )
+#define propertyTask2( prop ) \
+ WebdavHandler::addElement( doc, props, "t2:"prop )
+
+void ExchangeConverterCalendar::createRequestTask( TQDomDocument &doc, TQDomElement &props )
+{
+ createRequestIncidence( doc, props );
+
+ TQDomElement root = doc.documentElement();
+
+ TQDomAttr att_t1 = doc.createAttribute( "xmlns:t1" );
+ att_t1.setValue( TaskNamespace1 );
+ root.setAttributeNode( att_t1 );
+
+ TQDomAttr att_t2 = doc.createAttribute( "xmlns:t2" );
+ att_t2.setValue( TaskNamespace2 );
+ root.setAttributeNode( att_t2 );
+
+ // TODO: Insert the correct namespaces here:
+// propertyTask1( TaskProp_UID );
+ propertyDAV( "creationdate" );
+ propertyDAV( "getlastmodified" );
+ propertyTask1( TaskProp_Owner );
+ propertyTask2( TaskProp_ContactNames );
+ propertyTask1( TaskProp_DtStart );
+ propertyTask1( TaskProp_DtDue );
+ propertyTask1( TaskProp_Duration );
+ propertyTask1( TaskProp_IsCompleted );
+ propertyTask1( TaskProp_PercentCompleted );
+ propertyTask1( TaskProp_CompletionDate );
+ propertyTask1( TaskProp_DoesRecur );
+ // What to do about recurrence rules?
+ propertyTask2( TaskProp_ReminderSet );
+ propertyTask2( TaskProp_ReminderTime );
+ propertyTask2( TaskProp_ReminderPlaySound );
+ propertyTask2( TaskProp_ReminderSoundFile );
+ propertyTask1( TaskProp_Status );
+}
+#undef propertyTask1
+#undef propertyTask2
+
+void ExchangeConverterCalendar::createRequestJournal( TQDomDocument &doc, TQDomElement &root )
+{
+ createRequestIncidence( doc, root );
+ propertyDAV( "uid" );
+ propertyDAV( "creationdate" );
+ propertyDAV( "getlastmodified" );
+}
+#undef propertyDAV
+#undef propertyNS
+#undef propertyCalendar
+#undef propertyHTTPMail
+#undef propertyMailHeader
+#undef property
+
+bool ExchangeConverterCalendar::readTZ( const TQDomElement &node, Incidence */*incidence*/ )
+{
+ TQString timezoneid;
+ if ( WebdavHandler::extractString( node, "timezoneid", timezoneid ) ) {
+ // kdDebug() << "DEBUG: timezoneid = " << timezoneid << endl;
+ }
+
+ TQString timezone;
+ if ( WebdavHandler::extractString( node, "timezone", timezone ) ) {
+ // kdDebug() << "DEBUG: timezone = " << timezone << endl;
+ }
+
+ // TODO:
+/* // mFormat is used for parsing recurrence rules.
+ TQString localTimeZoneId;
+ if ( mCalendar ) {
+ mFormat.setTimeZone( mCalendar->timeZoneId(), !mCalendar->isLocalTime() );
+ localTimeZoneId = mCalendar->timeZoneId();
+ } else {
+ localTimeZoneId = "UTC";
+ // If no mCalendar, stay in UTC
+ }
+*/
+ return true;
+}
+
+bool ExchangeConverterCalendar::readIncidence( const TQDomElement &node, Incidence *incidence )
+{
+kdDebug()<<"ExchangeConverterCalendar::readIncidencd"<<endl;
+ TQDateTime tmpdt;
+ bool tmpbool;
+ TQString tmpstr;
+ long tmplng;
+ TQStringList tmplst;
+
+ readTZ( node, incidence );
+
+ if ( WebdavHandler::extractString( node, "getetag", tmpstr ) )
+ incidence->setCustomProperty( "TDEPIM-Exchange-Resource", "fingerprint", tmpstr );
+ if ( WebdavHandler::extractString( node, "href", tmpstr ) )
+ incidence->setCustomProperty( "TDEPIM-Exchange-Resource", "href", tmpstr );
+
+ // FIXME: use repl-uid as scheduling id?
+ if ( WebdavHandler::extractString( node, "textdescription", tmpstr ) )
+ incidence->setDescription( tmpstr );
+ if ( WebdavHandler::extractString( node, "subject", tmpstr ) )
+ incidence->setSummary( tmpstr );
+ if ( WebdavHandler::extractStringList( node, "Keywords", tmplst ) )
+ incidence->setCategories( tmplst );
+
+ // Use "created" or "creationdate"?
+ if ( WebdavHandler::extractBool( node, "isreadonly" , tmpbool ) )
+ incidence->setReadOnly( tmpbool );
+
+ // FIXME: Ignore the comment for now
+
+ // Exchange sentitivity values:
+ // 0 None, 1 Personal, 2 Private, 3 Company Confidential
+ if ( WebdavHandler::extractLong( node, "sensitivity", tmplng ) ) {
+ switch( tmplng ) {
+ case 0: incidence->setSecrecy( KCal::Incidence::SecrecyPublic ); break;
+ case 1:
+ case 2: incidence->setSecrecy( KCal::Incidence::SecrecyPrivate ); break;
+ case 3: incidence->setSecrecy( KCal::Incidence::SecrecyConfidential ); break;
+ default: kdWarning() << "Unknown sensitivity: " << tmplng << endl;
+ }
+ }
+
+ if ( WebdavHandler::extractBool( node, "hasattachment", tmpbool ) && tmpbool ) {
+ // FIXME: Extract attachments...
+ }
+
+ if ( WebdavHandler::extractLong( node, "priority", tmplng ) )
+ incidence->setPriority( tmplng );
+
+ // FIXME: Use the urn:schemes:httpmail:date property for what?
+
+ // Organizer, required and optional Attendees:
+ if ( WebdavHandler::extractString( node, "from", tmpstr ) )
+ incidence->setOrganizer( tmpstr );
+ if ( WebdavHandler::extractString( node, "to", tmpstr ) ) {
+ TQStringList atts( KPIM::splitEmailAddrList( tmpstr ) );
+ for ( TQStringList::Iterator it = atts.begin(); it != atts.end(); ++it ) {
+ TQString name, email;
+ KPIM::getNameAndMail( *it, name, email );
+ Attendee *att = new Attendee( name, email );
+ att->setRole( KCal::Attendee::ReqParticipant );
+ // FIXME: Retrieve the other attendee properties somehow...
+ // urn:schemas:calendar:method
+ // urn:schemas:calendar:responserequested
+ // urn:schemas:calendar:meetingstatus
+ // urn:schemas:calendar:replytime
+ incidence->addAttendee( att );
+ }
+ }
+ if ( WebdavHandler::extractString( node, "cc", tmpstr ) ) {
+ TQStringList atts( KPIM::splitEmailAddrList( tmpstr ) );
+ for ( TQStringList::Iterator it = atts.begin(); it != atts.end(); ++it ) {
+ TQString name, email;
+ KPIM::getNameAndMail( *it, name, email );
+ Attendee *att = new Attendee( name, email );
+ att->setRole( KCal::Attendee::OptParticipant );
+ // FIXME: Retrieve the other attendee properties somehow...
+ // urn:schemas:calendar:method
+ // urn:schemas:calendar:responserequested
+ // urn:schemas:calendar:meetingstatus
+ // urn:schemas:calendar:replytime
+ incidence->addAttendee( att );
+ }
+ }
+
+ return true;
+}
+
+/* FIXME: Handle recurrences
+void ExchangeDownload::handleRecurrence( TQString uid )
+{
+ // kdDebug() << "Handling recurrence info for uid=" << uid << endl;
+ TQString query =
+ "SELECT \"DAV:href\", \"urn:schemas:calendar:instancetype\"\r\n"
+ "FROM Scope('shallow traversal of \"\"')\r\n"
+ "WHERE \"urn:schemas:calendar:uid\" = '" + uid + "'\r\n"
+ " AND (\"urn:schemas:calendar:instancetype\" = 1)\r\n";
+// " OR \"urn:schemas:calendar:instancetype\" = 3)\r\n" // FIXME: exception are not handled
+
+ // kdDebug() << "Exchange master query: " << endl << query << endl;
+
+ TDEIO::DavJob* job = TDEIO::davSearch( mAccount->calendarURL(), "DAV:", "sql",
+ query, false );
+ TDEIO::Scheduler::scheduleJob( job );
+ job->setWindow( mWindow );
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ TQT_SLOT( slotMasterResult( TDEIO::Job * ) ) );
+}
+*/
+
+bool ExchangeConverterCalendar::readEvent( const TQDomElement &node, Event *event )
+{
+ if ( !readIncidence( node, event ) ) return false;
+kdDebug()<<"ExchangeConverterCalendar::readEvent"<<endl;
+
+ TQDateTime tmpdt;
+ TQString tmpstr;
+ long tmplng;
+ bool tmpbool;
+
+ // The UID is absolutely required!
+ if ( WebdavHandler::extractString( node, "uid", tmpstr ) ) {
+ event->setUid( tmpstr );
+ } else {
+kdDebug()<<"ExchangeConverterCalendar::readIncidence: ERROR: No UID given"<<endl;
+ return false;
+ }
+ if ( WebdavHandler::extractDateTime( node, "created", tmpdt ) )
+ event->setCreated( WebdavHandler::utcAsZone( tmpdt, mFormat.timeZoneId() ) );
+ if ( WebdavHandler::extractDateTime( node, "lastmodified", tmpdt ) )
+ event->setLastModified( WebdavHandler::utcAsZone( tmpdt, mFormat.timeZoneId() ) );
+ // FIXME: Retrieve time zone: "timezone"
+ // FIXME: Use the "recurrenceid" prop for the recurrenceId of the event (which is protected!)
+
+ // FIXME: Retrieve MICROSOFT-CDO-* tags first
+
+ if ( WebdavHandler::extractLong( node, "sequence", tmplng ) )
+ event->setRevision( tmplng );
+
+ if ( WebdavHandler::extractString( node, "location", tmpstr ) )
+ event->setLocation( tmpstr );
+
+ // FIXME: Use "organizer" here instead of the From: person?
+/* if ( WebdavHandler::extractString( node, "organizer", tmpstr ) )
+ incidence->setOrganizer( tmpstr );*/
+
+ if ( WebdavHandler::extractDateTime( node, "dtstart", tmpdt ) ) {
+ event->setDtStart( WebdavHandler::utcAsZone( tmpdt, mFormat.timeZoneId() ) );
+ }
+
+ bool allDay = false;
+ if ( WebdavHandler::extractBool( node, "alldayevent", allDay ) )
+ event->setFloats( allDay );
+
+ if ( WebdavHandler::extractLong( node, "duration", tmplng ) ) {
+ if (allDay)
+ tmplng--; // Otherwise event extends into next day
+ event->setDuration( tmplng );
+ // kdDebug() << "DURATION " << tmplng << "\n";
+ } else if ( WebdavHandler::extractDateTime( node, "dtend", tmpdt ) ) {
+ event->setDtEnd( WebdavHandler::utcAsZone( tmpdt, mFormat.timeZoneId() ) );
+ }
+
+ // FIXME: Here we have two different props for the same thing?!?!?
+ if ( WebdavHandler::extractLong( node, "transparent", tmplng ) )
+ event->setTransparency( tmplng>0 ? Event::Transparent : Event::Opaque );
+ if ( WebdavHandler::extractString( node, "busystatus", tmpstr ) ) {
+ if ( tmpstr == "FREE" )
+ event->setTransparency( KCal::Event::Transparent );
+ if ( tmpstr == "BUSY" )
+ event->setTransparency( KCal::Event::Opaque );
+ }
+
+ if ( WebdavHandler::extractLong( node, "reminderoffset", tmplng ) ) {
+ // Duration before event in seconds
+ KCal::Duration offset( -tmplng );
+ KCal::Alarm *alarm = event->newAlarm();
+ alarm->setStartOffset( offset );
+ alarm->setEnabled( true );
+ alarm->setType( KCal::Alarm::Display);
+ // TODO: multiple alarms;
+ }
+
+
+ if ( WebdavHandler::extractString( node, "rrule", tmpstr ) && !tmpstr.isEmpty() ) {
+ kdDebug() << "Got rrule: " << tmpstr << endl;
+ // Timezone should be handled automatically
+ // because we used mFormat.setTimeZone() earlier
+ // FIXME: Implement this using the format!
+ RecurrenceRule *rrule = event->recurrence()->defaultRRule( true );
+ if ( ! mFormat.fromString( rrule, tmpstr ) ) {
+ kdError() << "ERROR parsing rrule " << tmpstr << endl;
+ event->recurrence()->addRRule( rrule );
+ }
+ }
+
+ TQStringList tmplst;
+ if ( WebdavHandler::extractStringList( node, "exdate", tmplst ) ) {
+ TQStringList::Iterator it = tmplst.begin();
+ KCal::DateList exdates;
+ for ( ; it != tmplst.end(); ++it ) {
+ exdates.append( /*utcAsZone(*/ TQDateTime::fromString( *it, Qt::ISODate )/*,
+ localTimeZoneId )*/.date() );
+ }
+ event->recurrence()->setExDates( exdates );
+ }
+ // FIXME: use rdate and exrule!
+/* FIXME: Recurring events, they are split up
+ TQDomElement instancetypeElement = prop.namedItem( "instancetype" ).toElement();
+ if ( instancetypeElement.isNull() ) {
+ kdError() << "Error: no instance type in Exchange server reply" << endl;
+ continue;
+ }
+ int instanceType = instancetypeElement.text().toInt();
+ //kdDebug() << "Instance type: " << instanceType << endl;
+
+ if ( recurrence && instanceType > 0 ) {
+ TQDomElement uidElement = prop.namedItem( "uid" ).toElement();
+ if ( uidElement.isNull() ) {
+ kdError() << "Error: no uid in Exchange server reply" << endl;
+ continue;
+ }
+ TQString uid = uidElement.text();
+ if ( ! m_uids.contains( uid ) ) {
+ m_uids[uid] = 1;
+ handleRecurrence(uid);
+ successCount++;
+ }
+ continue;
+ }
+*/
+
+
+ // FIXME: read the resources from the "resources" tag
+
+ // FIXME: Custom fields not yet implemented
+ return true;
+}
+
+bool ExchangeConverterCalendar::readTodo( const TQDomElement &node, Todo *todo )
+{
+ if ( !readIncidence( node, todo ) ) return false;
+kdDebug()<<"ExchangeConverterCalendar::readTodo"<<endl;
+
+ // FIXME: Retrieve time zone: "timezone"
+ // FIXME: What to with TaskProp_Owner and TaskProp_ContactNames?
+
+ TQDateTime tmpdt;
+ float tmpfloat;
+ long tmplong;
+ bool tmpbool;
+ TQString tmpstr;
+
+ // The UID is absolutely required!
+ // FIXME: Which field shall be used as uid???
+/* if ( WebdavHandler::extractString( node, "uid", tmpstr ) ) {
+ todo->setUid( tmpstr );
+ } else {
+kdDebug()<<"ExchangeConverterCalendar::readIncidence: ERROR: No UID given"<<endl;
+ return false;
+ }*/
+// if ( WebdavHandler::extractDateTime( node, "created", tmpdt ) )
+/* FIXME: creation and last modification dates:
+ if ( WebdavHandler::extractDateTime( node, "creationdate", tmpdt ) )
+ incidence->setCreated( tmpdt );
+ if ( WebdavHandler::extractDateTime( node, "getlastmodified", tmpdt ) )
+ incidence->setLastModified( tmpdt );*/
+
+ if ( WebdavHandler::extractDateTime( node, TaskProp_DtStart, tmpdt ) )
+ todo->setDtStart( WebdavHandler::utcAsZone( tmpdt, mFormat.timeZoneId() ) );
+ if ( WebdavHandler::extractDateTime( node, TaskProp_DtDue, tmpdt ) )
+ todo->setDtDue( WebdavHandler::utcAsZone( tmpdt, mFormat.timeZoneId() ) );
+ if ( WebdavHandler::extractLong( node, TaskProp_Duration, tmplong ) )
+ todo->setDuration( tmplong );
+
+ if ( WebdavHandler::extractBool( node, TaskProp_IsCompleted, tmpbool ) && tmpbool ) {
+ todo->setCompleted( tmpbool );
+ if ( tmpbool && WebdavHandler::extractDateTime( node, TaskProp_CompletionDate, tmpdt ) ) {
+ todo->setCompleted( WebdavHandler::utcAsZone( tmpdt, mFormat.timeZoneId() ) );
+ }
+ }
+ if ( WebdavHandler::extractFloat( node, TaskProp_PercentCompleted, tmpfloat ) )
+ todo->setPercentComplete( (int)(tmpfloat*100) );
+
+ // FIXME: Recurrence, using TaskProp_DoesRecur
+ // What to do about recurrence rules?
+
+ // FIXME: Reminders, use TaskProp_ReminderSet, TaskProp_ReminderTime,
+ // TaskProp_ReminderPlaySound, TaskProp_ReminderSoundFile, TaskProp_Status
+ // But how do I get the offset?
+
+ return true;
+}
+
+bool ExchangeConverterCalendar::readJournal( const TQDomElement &node, Journal *journal )
+{
+ if ( !readIncidence( node, journal ) ) return false;
+kdDebug()<<"ExchangeConverterCalendar::readJournal"<<endl;
+ TQDateTime tmpdt;
+ TQString tmpstr;
+ // The UID is absolutely required!
+ // FIXME: Which field shall be used as UID?
+ if ( WebdavHandler::extractString( node, "uid", tmpstr ) ) {
+ journal->setUid( tmpstr );
+ } else {
+kdDebug()<<"ExchangeConverterCalendar::readJournal: ERROR: No UID given"<<endl;
+ return false;
+ }
+/* FIXME: creation and last modification times:
+ if ( WebdavHandler::extractDateTime( node, "created", tmpdt ) )
+ incidence->setCreated( tmpdt );
+ if ( WebdavHandler::extractDateTime( node, "lastmodified", tmpdt ) )
+ incidence->setLastModified( tmpdt );*/
+
+ if ( WebdavHandler::extractDateTime( node, "date", tmpdt ) )
+ journal->setDtStart( tmpdt );
+ return true;
+}
+
+Incidence::List ExchangeConverterCalendar::parseWebDAV( const TQDomDocument& davdata )
+{
+ TQDomElement prop = davdata.documentElement().namedItem( "response" )
+ .namedItem( "propstat" ).namedItem( "prop" ).toElement();
+ if ( prop.isNull() ) return Incidence::List();
+
+ TQString contentclass;
+ bool success = WebdavHandler::extractString( prop, "contentclass", contentclass );
+ if ( !success ) return Incidence::List();
+
+ Incidence *incidence = 0;
+ success = false;
+ if ( contentclass == "urn:content-classes:appointment" ) {
+ Event *event = new Event();
+ success = readEvent( prop, event );
+ incidence = event;
+ } else if ( contentclass == "urn:content-classes:task" ) {
+ Todo *todo = new Todo();
+ success = readTodo( prop, todo );
+ incidence = todo;
+ } else if ( contentclass == "urn:content-classes:journal" ||
+ contentclass == "urn:content-classes:message" ) {
+ Journal *journal = new Journal();
+ success = readJournal( prop, journal );
+ incidence = journal;
+ }
+
+ Incidence::List list;
+ if ( success ) {
+ list.append( incidence );
+ }
+ return list;
+}
+
+
+#define domDavProperty( name, value ) \
+ WebdavHandler::addElement( mDoc, mElement, "d:"name, value )
+#define domProperty( NS, name, value ) \
+ WebdavHandler::addElementNS( mDoc, mElement, NS, name, value )
+#define domCalendarProperty( name, value ) \
+ WebdavHandler::addElement( mDoc, mElement, "c:"name, value )
+#define domHTTPMailProperty( name, value ) \
+ WebdavHandler::addElement( mDoc, mElement, "m:"name, value )
+#define domMailHeaderProperty( name, value ) \
+ WebdavHandler::addElement( mDoc, mElement, "h:"name, value )
+
+
+
+
+class ExchangeConverterCalendar::createWebDAVVisitor : public IncidenceBase::Visitor
+{
+ public:
+ createWebDAVVisitor() : Visitor() {}
+ bool act( TQDomDocument doc, TQDomElement el, IncidenceBase *incidence, const TQString &timeZoneId )
+ {
+ mDoc = doc;
+ mElement = el;
+ mTimeZoneId = timeZoneId;
+ return incidence->accept( *this );
+ }
+ protected:
+ void addBoolProp( TQDomElement &el ) { el.setAttribute( "b:dt", "boolean" ); }
+ void addDateProp( TQDomElement &el ) { el.setAttribute( "b:dt", "dateTime.tz" ); }
+ void addFloatProp( TQDomElement &el ) { el.setAttribute( "b:dt", "float" ); }
+ void addIntProp( TQDomElement &el ) { el.setAttribute( "b:dt", "int" ); }
+ TQString timePropString( const TQDateTime &dt ) { return dt.toString( Qt::ISODate )+"Z"; }
+
+ bool visitIncidence( Incidence *incidence )
+ {
+ TQString tmpstr;
+ domDavProperty( "isreadonly", (incidence->isReadOnly())?"1":"0" );
+ // FIXME: scheduling ID
+// domProperty( "http://schemas.microsoft.com/repl/", "repl-uid", ??? );
+ domHTTPMailProperty( "subject", incidence->summary() );
+ domHTTPMailProperty( "textdescription", incidence->description() );
+ // FIXME: timestampt, comments and categories
+// domHTTPMailProperty( "date", ??? ); // timestamp not available in libkcal
+// domDavProperty( "comment", incidence->comments() ); // libkcal has a TQStringlist, not one string
+// domProperty( "urn:schemas-microsoft-com:office:office", "Keywords", ??? ); // It's a <v>entyr1</v><v>entry2</v> String list!
+ tmpstr = TQString();
+ switch ( incidence->secrecy() ) {
+ case KCal::Incidence::SecrecyPublic: tmpstr = "0"; break;
+ case KCal::Incidence::SecrecyPrivate: tmpstr = "2"; break;
+ case KCal::Incidence::SecrecyConfidential: tmpstr = "3"; break;
+ default: break;
+ }
+ if ( !tmpstr.isEmpty() )
+ domProperty( "http://schemas.microsoft.com/exchange/", "sensitivity", tmpstr );
+
+ domHTTPMailProperty( "priority", TQString::number(incidence->priority()) );
+
+ domMailHeaderProperty( "from", incidence->organizer().fullName() );
+
+ // Attendees:
+ tmpstr = TQString();
+ TQStringList reqattnames;
+ TQStringList optattnames;
+ Attendee::List atts = incidence->attendees();
+ for ( Attendee::List::Iterator it = atts.begin(); it != atts.end(); ++it ) {
+ switch ( (*it)->role() ) {
+ case KCal::Attendee::Chair:
+ case KCal::Attendee::ReqParticipant:
+ reqattnames << (*it)->fullName();
+ break;
+ case KCal::Attendee::OptParticipant:
+ case KCal::Attendee::NonParticipant:
+ optattnames << (*it)->fullName();
+ break;
+ default: break;
+ }
+ }
+
+ domMailHeaderProperty( "to", reqattnames.join(", ") );
+
+ domMailHeaderProperty( "cc", optattnames.join(", ") );
+
+ // FIXME: Attachments: propertyHTTPMail( "hasattachment" );
+
+ return true;
+ }
+ bool visit( Event *event )
+ {
+ if ( !visitIncidence(event) ) return false;
+
+ TQDomAttr att_c = mDoc.createAttribute( "xmlns:c" );
+ att_c.setValue( "urn:schemas:calendar:" );
+ mDoc.documentElement().setAttributeNode( att_c );
+
+ domDavProperty( "contentclass", "urn:content-classes:appointment" );
+ domProperty( "http://schemas.microsoft.com/exchange/",
+ "outlookmessageclass", "IPM.Appointment" );
+ domCalendarProperty( "uid", event->uid() );
+ TQDomElement el = domCalendarProperty( "created", timePropString( WebdavHandler::zoneAsUtc( event->created(), mTimeZoneId ) ) );
+ addDateProp( el );
+ el = domCalendarProperty( "lastmodified", timePropString( WebdavHandler::zoneAsUtc( event->lastModified(), mTimeZoneId ) ) );
+ addDateProp( el );
+ // FIXME: domCalendarProperty( "dtstamp", ??);
+// FIXME: domCalendarProperty( "sequence", event->sequence() );
+ domCalendarProperty( "location", event->location() );
+
+ TQString tmpstr;
+ switch ( event->transparency() ) {
+ case KCal::Event::Transparent: tmpstr = "FREE"; break;
+ case KCal::Event::Opaque: tmpstr = "BUSY"; break;
+ }
+ if ( !tmpstr.isEmpty() )
+ domCalendarProperty( "busystatus", tmpstr );
+// FIXME: What do do with the "transparent" property?
+// FIXME: Use the "timezone" property...
+ domCalendarProperty( "alldayevent", event->doesFloat()?"1":"0" );
+ el = domCalendarProperty( "dtstart", timePropString( WebdavHandler::zoneAsUtc( event->dtStart(), mTimeZoneId ) ) );
+ addDateProp( el );
+ if ( event->hasEndDate() ) {
+ el = domCalendarProperty( "dtend", timePropString( WebdavHandler::zoneAsUtc( event->dtEnd(), mTimeZoneId ) ) );
+ addDateProp( el );
+ } else {
+ domCalendarProperty( "duration", TQString::number( event->duration() ) );
+ }
+ // FIXME: Convert the recurrence rule to a string:
+ if ( event->doesRecur() ) {
+// tmpstr = event->recurrence().....
+// domCalendarProperty( "rrule", tmpstr );
+ // FIXME: Use "rdate" and "exrule"
+ // FIXME: Use "exdate", what's the syntax?
+ // FIXME: use the "instancetype" property
+ }
+ // FIXME: RecurrenceID is protected!
+// domCalendarProperty( "recurrenceid", event->recurrenceId() );
+ // FIXME: "reminderoffset"
+ // FIXME: "resources" Alarm::List alarms = event->alarms();
+
+ Alarm::List::ConstIterator it;
+ Alarm::List alarms = event->alarms();
+ for( it = alarms.begin(); it != alarms.end(); ++it ) {
+ if ((*it)->hasStartOffset()) {
+ domCalendarProperty( "reminderoffset", TQString::number( (*it)->startOffset().asSeconds() * -1 ) );
+ } else {
+ kdDebug() << "ExchangeConverterCalendar::createWebDAVVisitor: Alarm type not supported\n";
+ }
+ }
+
+ return true;
+ }
+ bool visit( Todo *todo )
+ {
+ if ( !visitIncidence(todo) ) return false;
+
+ TQDomAttr att_t1 = mDoc.createAttribute( "xmlns:t1" );
+ att_t1.setValue( TaskNamespace1 );
+ mDoc.documentElement().setAttributeNode( att_t1 );
+
+ TQDomAttr att_t2 = mDoc.createAttribute( "xmlns:t2" );
+ att_t2.setValue( TaskNamespace2 );
+ mDoc.documentElement().setAttributeNode( att_t2 );
+
+
+ domDavProperty( "contentclass", "urn:content-classes:task" );
+ domProperty( "http://schemas.microsoft.com/exchange/",
+ "outlookmessageclass", "IPM.Task" );
+
+/* FIXME:
+ domCalendarProperty( "uid", todo->uid() );
+ domCalendarProperty( "created", todo->created().toString( Qt::ISODate ) );
+ domCalendarProperty( "lastmodified", todo->lastModified().toString( Qt::ISODate ) );*/
+ // TODO
+/*propertyTask1( TaskProp_Owner );
+ propertyTask2( TaskProp_ContactNames );
+ propertyTask1( TaskProp_DtStart );
+ propertyTask1( TaskProp_DtDue );
+ propertyTask1( TaskProp_Duration );
+ propertyTask1( TaskProp_IsCompleted );
+ propertyTask1( TaskProp_PercentCompleted );
+ propertyTask1( TaskProp_CompetionDate );
+ propertyTask1( TaskProp_DoesRecur );
+ // What to do about recurrence rules?
+ propertyTask2( TaskProp_ReminderSet );
+ propertyTask2( TaskProp_ReminderTime );
+ propertyTask2( TaskProp_ReminderPlaySound );
+ propertyTask2( TaskProp_ReminderSoundFile );
+ propertyTask1( TaskProp_Status );*/
+ return true;
+ }
+ bool visit( Journal *journal )
+ {
+ if ( !visitIncidence(journal) ) return false;
+ domDavProperty( "contentclass", "urn:content-classes:journal" );
+ domProperty( "http://schemas.microsoft.com/exchange/",
+ "outlookmessageclass", "IPM.Journal" );
+/* FIXME:
+ domCalendarProperty( "uid", todo->uid() );
+ domCalendarProperty( "created", todo->created().toString( Qt::ISODate ) );
+ domCalendarProperty( "lastmodified", todo->lastModified().toString( Qt::ISODate ) );*/
+ // TODO
+ return true;
+ }
+
+ protected:
+ TQDomDocument mDoc;
+ TQDomElement mElement;
+ TQString mTimeZoneId;
+};
+
+// Prefixes for the namespaces:
+// d... DAV:
+// b... urn:schemas-microsoft-com:datatypes
+// c... calendar
+// m... httpmail
+// h... httpheader
+// p... mapi
+// o... office
+//
+
+TQDomDocument ExchangeConverterCalendar::createWebDAV( Incidence *incidence )
+{
+ // TODO
+ TQDomDocument doc;
+ TQDomElement root = WebdavHandler::addDavElement( doc, doc, "d:propertyupdate" );
+ TQDomElement set = WebdavHandler::addElement( doc, root, "d:set" );
+ TQDomElement prop = WebdavHandler::addElement( doc, set, "d:prop" );
+
+ TQDomAttr att_b = doc.createAttribute( "xmlns:b" );
+ att_b.setValue( "urn:schemas-microsoft-com:datatypes" );
+ root.setAttributeNode( att_b );
+
+ TQDomAttr att_h = doc.createAttribute( "xmlns:h" );
+ att_h.setValue( "urn:schemas:mailheader:" );
+ root.setAttributeNode( att_h );
+
+ TQDomAttr att_m = doc.createAttribute( "xmlns:m" );
+ att_m.setValue( "urn:schemas:httpmail:" );
+ root.setAttributeNode( att_m );
+
+// TQDomAttr att1 = doc.createAttributeNS( "do:whatever:you:like", "x:attname");
+// att1.setValue( "value" );
+// prop.setAttributeNodeNS( att1 );
+// root.setAttributeNodeNS( att1 );
+// set.setAttributeNode( att1 );
+// // prop.setAttributeNS ( "xmlns:b", "xmlns:b", "urn:schemas-microsoft-com:datatypes" );
+
+ ExchangeConverterCalendar::createWebDAVVisitor v;
+ v.act( doc, prop, incidence, mFormat.timeZoneId() );
+ kdDebug() << "ExchangeConverterCalendar::createWebDAVVisitor=" << doc.toString() << "\n";
+
+ return doc;
+}
+#undef domDavProperty
+#undef domProperty
+#undef domCalendarProperty
+#undef domHTTPMailProperty
+#undef domMailHeaderProperty