|
|
|
/*
|
|
|
|
This file is part of libkpimexchange
|
|
|
|
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 <tqfile.h>
|
|
|
|
#include <tqtextstream.h>
|
|
|
|
#include <tqdatastream.h>
|
|
|
|
#include <tqcstring.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <kurl.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <krfcdate.h>
|
|
|
|
|
|
|
|
#include <kio/slave.h>
|
|
|
|
#include <kio/scheduler.h>
|
|
|
|
#include <kio/slavebase.h>
|
|
|
|
#include <kio/davjob.h>
|
|
|
|
#include <kio/http.h>
|
|
|
|
#include <kio/job.h>
|
|
|
|
|
|
|
|
#include <libkcal/incidence.h>
|
|
|
|
#include <libkcal/event.h>
|
|
|
|
#include <libkcal/recurrence.h>
|
|
|
|
#include <libkcal/icalformat.h>
|
|
|
|
#include <libkcal/icalformatimpl.h>
|
|
|
|
#include <libkcal/calendarlocal.h>
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include <ical.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "exchangeclient.h"
|
|
|
|
#include "exchangeaccount.h"
|
|
|
|
#include "exchangeprogress.h"
|
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
#include "exchangedownload.h"
|
|
|
|
|
|
|
|
using namespace KPIM;
|
|
|
|
|
|
|
|
ExchangeDownload::ExchangeDownload( ExchangeAccount *account, TQWidget *window )
|
|
|
|
: mWindow( window )
|
|
|
|
{
|
|
|
|
kdDebug() << "ExchangeDownload()" << endl;
|
|
|
|
|
|
|
|
mAccount = account;
|
|
|
|
mDownloadsBusy = 0;
|
|
|
|
mProgress = 0;
|
|
|
|
mCalendar = 0;
|
|
|
|
mFormat = new KCal::ICalFormat();
|
|
|
|
}
|
|
|
|
|
|
|
|
ExchangeDownload::~ExchangeDownload()
|
|
|
|
{
|
|
|
|
kdDebug() << "ExchangeDownload destructor" << endl;
|
|
|
|
delete mFormat;
|
|
|
|
if ( mEvents ) delete mEvents;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::download( KCal::Calendar *calendar, const TQDate &start,
|
|
|
|
const TQDate &end, bool showProgress )
|
|
|
|
{
|
|
|
|
mCalendar = calendar;
|
|
|
|
mEvents = 0;
|
|
|
|
|
|
|
|
if( showProgress ) {
|
|
|
|
#if 0
|
|
|
|
//kdDebug() << "Creating progress dialog" << endl;
|
|
|
|
mProgress = new ExchangeProgress();
|
|
|
|
mProgress->show();
|
|
|
|
|
|
|
|
connect( this, TQT_SIGNAL( startDownload() ), mProgress,
|
|
|
|
TQT_SLOT( slotTransferStarted() ) );
|
|
|
|
connect( this, TQT_SIGNAL(finishDownload() ), mProgress,
|
|
|
|
TQT_SLOT( slotTransferFinished() ) );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString sql = dateSelectQuery( start, end.addDays( 1 ) );
|
|
|
|
|
|
|
|
kdDebug() << "Exchange download query: " << endl << sql << endl;
|
|
|
|
|
|
|
|
increaseDownloads();
|
|
|
|
|
|
|
|
kdDebug() << "ExchangeDownload::download() davSearch URL: "
|
|
|
|
<< mAccount->calendarURL() << endl;
|
|
|
|
|
|
|
|
KIO::DavJob *job = KIO::davSearch( mAccount->calendarURL(), "DAV:", "sql",
|
|
|
|
sql, false );
|
|
|
|
KIO::Scheduler::scheduleJob( job );
|
|
|
|
job->setWindow( mWindow );
|
|
|
|
connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
|
|
|
|
TQT_SLOT( slotSearchResult( KIO::Job *) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::download( const TQDate& start, const TQDate& end, bool showProgress )
|
|
|
|
{
|
|
|
|
mCalendar = 0;
|
|
|
|
mEvents = new TQPtrList<KCal::Event>;
|
|
|
|
|
|
|
|
if( showProgress ) {
|
|
|
|
//kdDebug() << "Creating progress dialog" << endl;
|
|
|
|
mProgress = new ExchangeProgress();
|
|
|
|
mProgress->show();
|
|
|
|
|
|
|
|
connect( this, TQT_SIGNAL(startDownload()), mProgress, TQT_SLOT(slotTransferStarted()) );
|
|
|
|
connect( this, TQT_SIGNAL(finishDownload()), mProgress, TQT_SLOT(slotTransferFinished()) );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString sql = dateSelectQuery( start, end.addDays( 1 ) );
|
|
|
|
|
|
|
|
increaseDownloads();
|
|
|
|
|
|
|
|
KIO::DavJob *job = KIO::davSearch( mAccount->calendarURL(), "DAV:", "sql", sql, false );
|
|
|
|
KIO::Scheduler::scheduleJob(job);
|
|
|
|
job->setWindow( mWindow );
|
|
|
|
connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
|
|
|
|
TQT_SLOT( slotSearchResult( KIO::Job * ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Original query TODO: make query configurable
|
|
|
|
TQString ExchangeDownload::dateSelectQuery( const TQDate& start, const TQDate& end )
|
|
|
|
{
|
|
|
|
TQString startString;
|
|
|
|
startString.sprintf("%04i/%02i/%02i",start.year(),start.month(),start.day());
|
|
|
|
TQString endString;
|
|
|
|
endString.sprintf("%04i/%02i/%02i",end.year(),end.month(),end.day());
|
|
|
|
TQString sql =
|
|
|
|
"SELECT \"DAV:href\", \"urn:schemas:calendar:instancetype\", \"urn:schemas:calendar:uid\"\r\n"
|
|
|
|
"FROM Scope('shallow traversal of \"\"')\r\n"
|
|
|
|
"WHERE \"urn:schemas:calendar:dtend\" > '" + startString + "'\r\n"
|
|
|
|
"AND \"urn:schemas:calendar:dtstart\" < '" + endString + "'";
|
|
|
|
return sql;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// That's the "new" code that breaks with Exchange. It was meant for Opengroupware, but that got its own resource anyway
|
|
|
|
TQString ExchangeDownload::dateSelectQuery( const TQDate& start, const TQDate& end )
|
|
|
|
{
|
|
|
|
TQString startString;
|
|
|
|
startString.sprintf( "%04i-%02i-%02iT00:00:00Z", start.year(),
|
|
|
|
start.month(), start.day() );
|
|
|
|
TQString endString;
|
|
|
|
endString.sprintf( "%04i-%02i-%02iT23:59:59Z", end.year(), end.month(),
|
|
|
|
end.day() );
|
|
|
|
TQString sql =
|
|
|
|
"SELECT \"DAV:href\", \"urn:schemas:calendar:instancetype\", "
|
|
|
|
"\"urn:schemas:calendar:uid\"\r\n"
|
|
|
|
"FROM Scope('shallow traversal of \"\"')\r\n"
|
|
|
|
"WHERE \"urn:schemas:calendar:dtend\" > '" + startString + "'\r\n"
|
|
|
|
"AND \"urn:schemas:calendar:dtstart\" < '" + endString + "'";
|
|
|
|
return sql;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void ExchangeDownload::slotSearchResult( KIO::Job *job )
|
|
|
|
{
|
|
|
|
if ( job->error() ) {
|
|
|
|
kdError() << "ExchangeDownload::slotSearchResult() error: "
|
|
|
|
<< job->error() << endl;
|
|
|
|
TQString text = i18n("ExchangeDownload\nError accessing '%1': %2")
|
|
|
|
.arg( mAccount->calendarURL().prettyURL() )
|
|
|
|
.arg( job->errorString() );
|
|
|
|
KMessageBox::error( 0, text );
|
|
|
|
finishUp( ExchangeClient::CommunicationError, job );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TQDomDocument &response = static_cast<KIO::DavJob *>( job )->response();
|
|
|
|
|
|
|
|
kdDebug() << "Search result: " << endl << response.toString() << endl;
|
|
|
|
|
|
|
|
handleAppointments( response, true );
|
|
|
|
|
|
|
|
decreaseDownloads();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::slotMasterResult( KIO::Job *job )
|
|
|
|
{
|
|
|
|
if ( job->error() ) {
|
|
|
|
kdError() << "Error result for Master search: " << job->error() << endl;
|
|
|
|
job->showErrorDialog( 0 );
|
|
|
|
finishUp( ExchangeClient::CommunicationError, job );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TQDomDocument &response = static_cast<KIO::DavJob *>( job )->response();
|
|
|
|
|
|
|
|
kdDebug() << "Search (master) result: " << endl << response.toString() << endl;
|
|
|
|
|
|
|
|
handleAppointments( response, false );
|
|
|
|
|
|
|
|
decreaseDownloads();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::handleAppointments( const TQDomDocument &response,
|
|
|
|
bool recurrence )
|
|
|
|
{
|
|
|
|
kdDebug() << "Entering handleAppointments" << endl;
|
|
|
|
int successCount = 0;
|
|
|
|
|
|
|
|
if ( response.documentElement().firstChild().toElement().isNull() ) {
|
|
|
|
// Got an empty response, but no error. This would mean there are
|
|
|
|
// no appointments in this time period.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( TQDomElement item = response.documentElement().firstChild().toElement();
|
|
|
|
!item.isNull();
|
|
|
|
item = item.nextSibling().toElement() ) {
|
|
|
|
//kdDebug() << "Current item:" << item.tagName() << endl;
|
|
|
|
TQDomNodeList propstats = item.elementsByTagNameNS( "DAV:", "propstat" );
|
|
|
|
// kdDebug() << "Item has " << propstats.count() << " propstat children" << endl;
|
|
|
|
for( uint i=0; i < propstats.count(); i++ ) {
|
|
|
|
TQDomElement propstat = propstats.item(i).toElement();
|
|
|
|
TQDomElement prop = propstat.namedItem( "prop" ).toElement();
|
|
|
|
if ( prop.isNull() ) {
|
|
|
|
kdError() << "Error: no <prop> in response" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDomElement hrefElement = prop.namedItem( "href" ).toElement();
|
|
|
|
if ( hrefElement.isNull() ) {
|
|
|
|
kdError() << "Error: no href in Exchange server reply" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
TQString href = hrefElement.text();
|
|
|
|
KURL url(href);
|
|
|
|
|
|
|
|
kdDebug() << "Getting appointment from url: " << url.prettyURL() << endl;
|
|
|
|
|
|
|
|
readAppointment( toDAV( url ) );
|
|
|
|
successCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !successCount ) {
|
|
|
|
finishUp( ExchangeClient::ServerResponseError,
|
|
|
|
"WebDAV SEARCH response:\n" + response.toString() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
increaseDownloads();
|
|
|
|
|
|
|
|
KIO::DavJob* job = KIO::davSearch( mAccount->calendarURL(), "DAV:", "sql",
|
|
|
|
query, false );
|
|
|
|
KIO::Scheduler::scheduleJob( job );
|
|
|
|
job->setWindow( mWindow );
|
|
|
|
connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
|
|
|
|
TQT_SLOT( slotMasterResult( KIO::Job * ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::readAppointment( const KURL& url )
|
|
|
|
{
|
|
|
|
TQDomDocument doc;
|
|
|
|
TQDomElement root = addElement( doc, doc, "DAV:", "propfind" );
|
|
|
|
TQDomElement prop = addElement( doc, root, "DAV:", "prop" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "uid" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "timezoneid" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "timezone" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "lastmodified" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "organizer" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "contact" );
|
|
|
|
addElement( doc, prop, "urn:schemas:httpmail:", "to" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "attendeestatus" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "attendeerole" );
|
|
|
|
addElement( doc, prop, "DAV:", "isreadonly" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "instancetype" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "created" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "dtstart" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "dtend" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "alldayevent" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "transparent" );
|
|
|
|
addElement( doc, prop, "urn:schemas:httpmail:", "textdescription" );
|
|
|
|
addElement( doc, prop, "urn:schemas:httpmail:", "subject" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "location" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "rrule" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "exdate" );
|
|
|
|
addElement( doc, prop, "urn:schemas:mailheader:", "sensitivity" );
|
|
|
|
addElement( doc, prop, "urn:schemas:calendar:", "reminderoffset" );
|
|
|
|
|
|
|
|
addElement( doc, prop, "urn:schemas-microsoft-com:office:office",
|
|
|
|
"Keywords" );
|
|
|
|
|
|
|
|
// addElement( doc, prop, "", "" );
|
|
|
|
// addElement( doc, prop, "DAV:", "" );
|
|
|
|
// addElement( doc, prop, "urn:schemas:calendar:", "" );
|
|
|
|
// addElement( doc, prop, "urn:content-classes:appointment", "" );
|
|
|
|
// addElement( doc, prop, "urn:schemas:httpmail:", "" );
|
|
|
|
|
|
|
|
increaseDownloads();
|
|
|
|
|
|
|
|
KIO::DavJob* job = KIO::davPropFind( url, doc, "0", false );
|
|
|
|
KIO::Scheduler::scheduleJob( job );
|
|
|
|
job->setWindow( mWindow );
|
|
|
|
job->addMetaData( "errorPage", "false" );
|
|
|
|
connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
|
|
|
|
TQT_SLOT( slotPropFindResult( KIO::Job * ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::slotPropFindResult( KIO::Job *job )
|
|
|
|
{
|
|
|
|
kdDebug() << "slotPropFindResult" << endl;
|
|
|
|
|
|
|
|
int error = job->error();
|
|
|
|
if ( error ) {
|
|
|
|
job->showErrorDialog( 0 );
|
|
|
|
finishUp( ExchangeClient::CommunicationError, job );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDomDocument response = static_cast<KIO::DavJob *>( job )->response();
|
|
|
|
kdDebug() << "Response: " << endl;
|
|
|
|
kdDebug() << response.toString() << endl;
|
|
|
|
|
|
|
|
TQDomElement prop = response.documentElement().namedItem( "response" )
|
|
|
|
.namedItem( "propstat" ).namedItem( "prop" ).toElement();
|
|
|
|
|
|
|
|
KCal::Event* event = new KCal::Event();
|
|
|
|
|
|
|
|
TQDomElement uidElement = prop.namedItem( "uid" ).toElement();
|
|
|
|
if ( uidElement.isNull() ) {
|
|
|
|
kdError() << "Error: no uid in Exchange server reply" << endl;
|
|
|
|
finishUp( ExchangeClient::IllegalAppointmentError,
|
|
|
|
"WebDAV server response:\n" + response.toString() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
event->setUid( uidElement.text() );
|
|
|
|
// kdDebug() << "Got UID: " << uidElement.text() << endl;
|
|
|
|
|
|
|
|
TQString timezoneid = prop.namedItem( "timezoneid" ).toElement().text();
|
|
|
|
// kdDebug() << "DEBUG: timezoneid = " << timezoneid << endl;
|
|
|
|
|
|
|
|
TQString timezone = prop.namedItem( "timezone" ).toElement().text();
|
|
|
|
// kdDebug() << "DEBUG: timezone = " << timezone << endl;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString lastModified = prop.namedItem( "lastmodified" ).toElement().text();
|
|
|
|
if ( !lastModified.isEmpty() ) {
|
|
|
|
TQDateTime dt = utcAsZone( TQDateTime::fromString( lastModified, Qt::ISODate ), localTimeZoneId );
|
|
|
|
event->setLastModified( dt );
|
|
|
|
kdDebug() << "Got lastModified:" << lastModified << ", " << dt.toString() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString organizer = prop.namedItem( "organizer" ).toElement().text();
|
|
|
|
// TODO: Does outlook have a common name? Or does the organizer already contain both?
|
|
|
|
event->setOrganizer( organizer );
|
|
|
|
// kdDebug() << "Got organizer: " << organizer << endl;
|
|
|
|
|
|
|
|
// Trying to find attendees, not working yet
|
|
|
|
TQString contact = prop.namedItem( "contact" ).toElement().text();
|
|
|
|
// event->setOrganizer( organizer );
|
|
|
|
// kdDebug() << "DEBUG: Got contact: " << contact << endl;
|
|
|
|
|
|
|
|
// This looks promising for finding attendees
|
|
|
|
// FIXME: get this to work
|
|
|
|
TQString to = prop.namedItem( "to" ).toElement().text();
|
|
|
|
// kdDebug() << "DEBUG: Got to: " << to << endl;
|
|
|
|
TQStringList attn = TQStringList::split( ",", to ); // This doesn't work: there can be commas between ""
|
|
|
|
TQStringList::iterator it;
|
|
|
|
for ( it = attn.begin(); it != attn.end(); ++it ) {
|
|
|
|
// kdDebug() << " attendee: " << (*it) << endl;
|
|
|
|
TQString name = "";
|
|
|
|
// KCal::Attendee* a = new KCal::Attendee( name, email );
|
|
|
|
|
|
|
|
// event->addAttendee( a );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString readonly = prop.namedItem( "isreadonly" ).toElement().text();
|
|
|
|
event->setReadOnly( readonly == "1" );
|
|
|
|
kdDebug() << "Got readonly: " << readonly << ":" << (readonly != "0") << endl;
|
|
|
|
|
|
|
|
TQString created = prop.namedItem( "created" ).toElement().text();
|
|
|
|
if ( !created.isEmpty() ) {
|
|
|
|
TQDateTime dt = utcAsZone( TQDateTime::fromString( created, Qt::ISODate ),
|
|
|
|
localTimeZoneId );
|
|
|
|
event->setCreated( dt );
|
|
|
|
kdDebug() << "got created: " << dt.toString() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString dtstart = prop.namedItem( "dtstart" ).toElement().text();
|
|
|
|
if ( !dtstart.isEmpty() ) {
|
|
|
|
TQDateTime dt = utcAsZone( TQDateTime::fromString( dtstart, Qt::ISODate ),
|
|
|
|
localTimeZoneId );
|
|
|
|
event->setDtStart( dt );
|
|
|
|
kdDebug() << "got dtstart: " << dtstart << " becomes in timezone " << dt.toString() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString alldayevent = prop.namedItem( "alldayevent" ).toElement().text();
|
|
|
|
bool floats = alldayevent.toInt() != 0;
|
|
|
|
event->setFloats( floats );
|
|
|
|
kdDebug() << "Got alldayevent: \"" << alldayevent << "\":" << floats << endl;
|
|
|
|
|
|
|
|
TQString dtend = prop.namedItem( "dtend" ).toElement().text();
|
|
|
|
if ( !dtend.isEmpty() ) {
|
|
|
|
TQDateTime dt = utcAsZone( TQDateTime::fromString( dtend, Qt::ISODate ),
|
|
|
|
localTimeZoneId );
|
|
|
|
// Outlook thinks differently about floating event timing than libkcal
|
|
|
|
if ( floats ) dt = dt.addDays( -1 );
|
|
|
|
event->setDtEnd( dt );
|
|
|
|
kdDebug() << "got dtend: " << dtend << " becomes in timezone " << dt.toString() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString transparent = prop.namedItem( "transparent" ).toElement().text();
|
|
|
|
event->setTransparency( transparent.toInt() > 0 ? KCal::Event::Transparent
|
|
|
|
: KCal::Event::Opaque );
|
|
|
|
// kdDebug() << "Got transparent: " << transparent << endl;
|
|
|
|
|
|
|
|
TQString description = prop.namedItem( "textdescription" ).toElement().text();
|
|
|
|
event->setDescription( description );
|
|
|
|
kdDebug() << "Got description: " << description << endl;
|
|
|
|
|
|
|
|
TQString subject = prop.namedItem( "subject" ).toElement().text();
|
|
|
|
event->setSummary( subject );
|
|
|
|
kdDebug() << "Got summary: " << subject << endl;
|
|
|
|
|
|
|
|
TQString location = prop.namedItem( "location" ).toElement().text();
|
|
|
|
event->setLocation( location );
|
|
|
|
// kdDebug() << "Got location: " << location << endl;
|
|
|
|
|
|
|
|
TQString rrule = prop.namedItem( "rrule" ).toElement().text();
|
|
|
|
kdDebug() << "Got rrule: " << rrule << endl;
|
|
|
|
if ( !rrule.isEmpty() ) {
|
|
|
|
// Timezone should be handled automatically
|
|
|
|
// because we used mFormat->setTimeZone() earlier
|
|
|
|
KCal::RecurrenceRule *rr = event->recurrence()->defaultRRule( true );
|
|
|
|
|
|
|
|
if ( !rr || !mFormat->fromString( rr, rrule ) ) {
|
|
|
|
kdError() << "ERROR parsing rrule " << rrule << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDomElement keywords = prop.namedItem( "Keywords" ).toElement();
|
|
|
|
TQStringList categories;
|
|
|
|
TQDomNodeList list = keywords.elementsByTagNameNS( "xml:", "v" );
|
|
|
|
for( uint i=0; i < list.count(); i++ ) {
|
|
|
|
TQDomElement item = list.item(i).toElement();
|
|
|
|
categories.append( item.text() );
|
|
|
|
}
|
|
|
|
event->setCategories( categories );
|
|
|
|
// kdDebug() << "Got categories: " << categories.join( ", " ) << endl;
|
|
|
|
|
|
|
|
|
|
|
|
TQDomElement exdate = prop.namedItem( "exdate" ).toElement();
|
|
|
|
KCal::DateList exdates;
|
|
|
|
list = exdate.elementsByTagNameNS( "xml:", "v" );
|
|
|
|
for( uint i=0; i < list.count(); i++ ) {
|
|
|
|
TQDomElement item = list.item(i).toElement();
|
|
|
|
TQDate date = utcAsZone( TQDateTime::fromString( item.text(), Qt::ISODate ), localTimeZoneId ).date();
|
|
|
|
exdates.append( date );
|
|
|
|
// kdDebug() << "Got exdate: " << date.toString() << endl;
|
|
|
|
}
|
|
|
|
event->recurrence()->setExDates( exdates );
|
|
|
|
|
|
|
|
// Exchange sentitivity values:
|
|
|
|
// 0 None
|
|
|
|
// 1 Personal
|
|
|
|
// 2 Private
|
|
|
|
// 3 Company Confidential
|
|
|
|
TQString sensitivity = prop.namedItem( "sensitivity" ).toElement().text();
|
|
|
|
if ( ! sensitivity.isNull() )
|
|
|
|
switch( sensitivity.toInt() ) {
|
|
|
|
case 0: event->setSecrecy( KCal::Incidence::SecrecyPublic ); break;
|
|
|
|
case 1: event->setSecrecy( KCal::Incidence::SecrecyPrivate ); break;
|
|
|
|
case 2: event->setSecrecy( KCal::Incidence::SecrecyPrivate ); break;
|
|
|
|
case 3: event->setSecrecy( KCal::Incidence::SecrecyConfidential ); break;
|
|
|
|
default: kdWarning() << "Unknown sensitivity: " << sensitivity << endl;
|
|
|
|
}
|
|
|
|
// kdDebug() << "Got sensitivity: " << sensitivity << endl;
|
|
|
|
|
|
|
|
|
|
|
|
TQString reminder = prop.namedItem( "reminderoffset" ).toElement().text();
|
|
|
|
// kdDebug() << "Reminder offset: " << reminder << endl;
|
|
|
|
if ( !reminder.isEmpty() ) {
|
|
|
|
// Duration before event in seconds
|
|
|
|
KCal::Duration offset( - reminder.toInt() );
|
|
|
|
KCal::Alarm *alarm = event->newAlarm();
|
|
|
|
alarm->setStartOffset( offset );
|
|
|
|
alarm->setDisplayAlarm("");
|
|
|
|
alarm->setEnabled( true );
|
|
|
|
// TODO: multiple alarms; alarm->setType( KCal::Alarm::xxxx );
|
|
|
|
}
|
|
|
|
/** Create a new alarm which is associated with this incidence */
|
|
|
|
//Alarm* newAlarm();
|
|
|
|
/** Add an alarm which is associated with this incidence */
|
|
|
|
//void addAlarm(Alarm*);
|
|
|
|
|
|
|
|
/** point at some other event to which the event relates */
|
|
|
|
//void setRelatedTo(Incidence *relatedTo);
|
|
|
|
/** Add an event which is related to this event */
|
|
|
|
//void addRelation(Incidence *);
|
|
|
|
|
|
|
|
/** set the list of attachments/associated files for this event */
|
|
|
|
//void setAttachments(const TQStringList &attachments);
|
|
|
|
|
|
|
|
/** set resources used, such as Office, Car, etc. */
|
|
|
|
//void setResources(const TQStringList &resources);
|
|
|
|
|
|
|
|
/** set the event's priority, 0 is undefined, 1 highest (decreasing order) */
|
|
|
|
//void setPriority(int priority);
|
|
|
|
|
|
|
|
/**
|
|
|
|
Add Attendee to this incidence. IncidenceBase takes ownership of the
|
|
|
|
Attendee object.
|
|
|
|
*/
|
|
|
|
|
|
|
|
//void addAttendee(Attendee *a, bool doupdate=true );
|
|
|
|
|
|
|
|
// THE FOLLOWING EVENT PROPERTIES ARE NOT READ
|
|
|
|
|
|
|
|
// Revision ID in webdav is a String, not an int
|
|
|
|
/** set the number of revisions this event has seen */
|
|
|
|
//void setRevision(int rev);
|
|
|
|
|
|
|
|
// Problem: When you sync Outlook to a Palm, the conduit splits up
|
|
|
|
// multi-day events into single-day events WITH ALL THE SAME UID
|
|
|
|
// Grrrrrrr.
|
|
|
|
if ( mCalendar ) {
|
|
|
|
KCal::Event *oldEvent = mCalendar->event( event->uid() );
|
|
|
|
if ( oldEvent ) {
|
|
|
|
kdWarning() << "Already got his event, replace it..." << endl;
|
|
|
|
mCalendar->deleteEvent( oldEvent );
|
|
|
|
}
|
|
|
|
kdDebug() << "ADD EVENT" << endl;
|
|
|
|
mCalendar->addEvent( event );
|
|
|
|
} else {
|
|
|
|
kdDebug() << "EMIT gotEvent" << endl;
|
|
|
|
emit gotEvent( event, static_cast<KIO::DavJob *>( job )->url() );
|
|
|
|
// mEvents->append( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
decreaseDownloads();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::increaseDownloads()
|
|
|
|
{
|
|
|
|
mDownloadsBusy++;
|
|
|
|
emit startDownload();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::decreaseDownloads()
|
|
|
|
{
|
|
|
|
mDownloadsBusy--;
|
|
|
|
// kdDebug() << "Download finished, waiting for " << mDownloadsBusy << " more" << endl;
|
|
|
|
emit finishDownload();
|
|
|
|
if ( mDownloadsBusy == 0 ) {
|
|
|
|
kdDebug() << "All downloads finished" << endl;
|
|
|
|
finishUp( ExchangeClient::ResultOK );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::finishUp( int result, const TQString &moreInfo )
|
|
|
|
{
|
|
|
|
kdDebug() << "ExchangeDownload::finishUp() " << result << " "
|
|
|
|
<< moreInfo << endl;
|
|
|
|
|
|
|
|
if ( mCalendar ) mCalendar->setModified( true );
|
|
|
|
// Disconnect from progress bar
|
|
|
|
if ( mProgress ) {
|
|
|
|
disconnect( this, 0, mProgress, 0 );
|
|
|
|
disconnect( mProgress, 0, this, 0 );
|
|
|
|
mProgress->delayedDestruct();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if ( mEvents ) {
|
|
|
|
// emit finished( this, result, moreInfo, *mEvents );
|
|
|
|
// } else {
|
|
|
|
emit finished( this, result, moreInfo );
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeDownload::finishUp( int result, KIO::Job *job )
|
|
|
|
{
|
|
|
|
finishUp( result, TQString("WebDAV job error code = ") +
|
|
|
|
TQString::number( job->error() ) + ";\n" + "\"" +
|
|
|
|
job->errorString() + "\"" );
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "exchangedownload.moc"
|