diff options
Diffstat (limited to 'tderesources/newexchange/exchangeconvertercalendar.cpp')
-rw-r--r-- | tderesources/newexchange/exchangeconvertercalendar.cpp | 820 |
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 |