00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include <qstring.h>
00022
#include <qregexp.h>
00023
00024
#include <kurl.h>
00025
#include <kdebug.h>
00026
#include <krfcdate.h>
00027
#include <kio/job.h>
00028
00029
#include <kio/slave.h>
00030
#include <kio/scheduler.h>
00031
#include <kio/slavebase.h>
00032
#include <kio/davjob.h>
00033
#include <kio/http.h>
00034
00035
extern "C" {
00036
#include <ical.h>
00037 }
00038
00039
#include <libkcal/event.h>
00040
#include <libkcal/icalformat.h>
00041
#include <libkcal/icalformatimpl.h>
00042
#include <libkcal/recurrence.h>
00043
#include <libkcal/incidence.h>
00044
#include <libkcal/event.h>
00045
00046
#include "exchangeclient.h"
00047
#include "exchangeprogress.h"
00048
#include "exchangeupload.h"
00049
#include "exchangeaccount.h"
00050
#include "utils.h"
00051
00052
using namespace KPIM;
00053
00054 ExchangeUpload::ExchangeUpload( KCal::Event* event, ExchangeAccount* account,
const QString& timeZoneId, QWidget* window ) :
00055 mTimeZoneId( timeZoneId), mWindow( window )
00056 {
00057 kdDebug() <<
"Called ExchangeUpload" << endl;
00058
00059 mAccount = account;
00060 m_currentUpload = event;
00061 m_currentUploadNumber = 0;
00062
00063
00064
00065 findUid( m_currentUpload->uid() );
00066 }
00067
00068 ExchangeUpload::~ExchangeUpload()
00069 {
00070 kdDebug() <<
"Entering ExchangeUpload destructor" << endl;
00071 kdDebug() <<
"Finished ExchangeUpload destructor" << endl;
00072 }
00073
00074
void ExchangeUpload::findUid( QString
const& uid )
00075 {
00076 QString query =
00077
"SELECT \"DAV:href\", \"urn:schemas:calendar:uid\"\r\n"
00078
"FROM Scope('shallow traversal of \"\"')\r\n"
00079
"WHERE \"urn:schemas:calendar:uid\" = '" + uid +
"'\r\n";
00080
00081
00082 kdDebug() <<
"Looking for uid " << uid << endl;
00083
00084 KIO::DavJob* job = KIO::davSearch( mAccount->calendarURL(),
"DAV:",
"sql", query,
false );
00085 job->setWindow( mWindow );
00086 connect(job, SIGNAL(result( KIO::Job * )),
this, SLOT(slotFindUidResult(KIO::Job *)));
00087 }
00088
00089
void ExchangeUpload::slotFindUidResult( KIO::Job * job )
00090 {
00091 kdDebug() <<
"slotFindUidResult()" << endl;
00092
if ( job->error() ) {
00093 kdDebug() <<
"Error: " << job->error() << endl;
00094 job->showErrorDialog( 0L );
00095 emit finished(
this, ExchangeClient::CommunicationError,
"IO Error: " + QString::number(job->error()) +
":" + job->errorString() );
00096
return;
00097 }
00098 QDomDocument& response = static_cast<KIO::DavJob *>( job )->response();
00099
00100
00101
00102 QDomElement item = response.documentElement().firstChild().toElement();
00103 QDomElement hrefElement = item.namedItem(
"href" ).toElement();
00104
if ( item.isNull() || hrefElement.isNull() ) {
00105
00106
00107 tryExist();
00108
return;
00109 }
00110
00111
00112 QString href = hrefElement.text();
00113 KURL url(href);
00114 kdDebug() <<
"Found URL with identical uid: " << url.prettyURL() <<
", overwriting that one" << endl;
00115
00116 startUpload( toDAV( url ) );
00117 }
00118
00119
void ExchangeUpload::tryExist()
00120 {
00121
00122
00123 KURL url = mAccount->calendarURL();
00124
if ( m_currentUploadNumber == 0 )
00125 url.addPath( m_currentUpload->summary() +
".EML" );
00126
else
00127 url.addPath( m_currentUpload->summary() +
"-" + QString::number( m_currentUploadNumber ) +
".EML" );
00128
00129 kdDebug() <<
"Trying to see whether " << url.prettyURL() <<
" exists" << endl;
00130
00131 QDomDocument doc;
00132 QDomElement root = addElement( doc, doc,
"DAV:",
"propfind" );
00133 QDomElement prop = addElement( doc, root,
"DAV:",
"prop" );
00134 addElement( doc, prop,
"DAV:",
"displayname" );
00135 addElement( doc, prop,
"urn:schemas:calendar",
"uid" );
00136
00137 KIO::DavJob* job = KIO::davPropFind( url, doc,
"0",
false );
00138 job->setWindow( mWindow );
00139 job->addMetaData(
"errorPage",
"false" );
00140 connect( job, SIGNAL( result( KIO::Job * ) ),
this, SLOT( slotPropFindResult( KIO::Job * ) ) );
00141 }
00142
00143
void ExchangeUpload::slotPropFindResult( KIO::Job *job )
00144 {
00145 kdDebug() <<
"slotPropFindResult()" << endl;
00146
int error = job->error();
00147 kdDebug() <<
"PROPFIND error: " << error <<
":" << job->errorString() << endl;
00148
if ( error && error != KIO::ERR_DOES_NOT_EXIST )
00149 {
00150 job->showErrorDialog( 0L );
00151 emit finished(
this, ExchangeClient::CommunicationError,
"IO Error: " + QString::number(error) +
":" + job->errorString() );
00152
return;
00153 }
00154
00155
if ( !error )
00156 {
00157
00158 m_currentUploadNumber++;
00159 tryExist();
00160
return;
00161 }
00162
00163
00164
00165
00166
00167 KURL url = mAccount->calendarURL();
00168
if ( m_currentUploadNumber == 0 )
00169 url.addPath( m_currentUpload->summary() +
".EML" );
00170
else
00171 url.addPath( m_currentUpload->summary() +
"-" + QString::number( m_currentUploadNumber ) +
".EML" );
00172
00173 startUpload( url );
00174 }
00175
00176 QString timezoneid(
int offset ) {
00177
switch ( offset ) {
00178
case 0:
return "0";
00179
case -60:
return "3";
00180
case -120:
return "5";
00181
case -180:
return "51";
00182
case -210:
return "25";
00183
case -240:
return "24";
00184
case -270:
return "48";
00185
case -300:
return "47";
00186
case -330:
return "23";
00187
case -360:
return "46";
00188
case -420:
return "22";
00189
case -480:
return "45";
00190
case -540:
return "20";
00191
case -570:
return "44";
00192
case -600:
return "18";
00193
case -660:
return "41";
00194
case -720:
return "17";
00195
case 60:
return "29";
00196
case 120:
return "30";
00197
case 180:
return "8";
00198
case 210:
return "28";
00199
case 240:
return "9";
00200
case 300:
return "10";
00201
case 360:
return "11";
00202
case 420:
return "12";
00203
case 480:
return "13";
00204
case 540:
return "14";
00205
case 600:
return "15";
00206
case 660:
return "16";
00207
case 720:
return "39";
00208
default:
return "52";
00209 }
00210 }
00211
00212
00213
void ExchangeUpload::startUpload(
const KURL& url )
00214 {
00215 KCal::Event*
event = static_cast<KCal::Event *>( m_currentUpload );
00216
if ( ! event ) {
00217 kdDebug() <<
"ERROR: trying to upload a non-Event Incidence" << endl;
00218 emit finished(
this, ExchangeClient::NonEventError,
"The incidence that is to be uploaded to the exchange server is not of type KCal::Event" );
00219
return;
00220 }
00221
00222 QDomDocument doc;
00223 QDomElement root = addElement( doc, doc,
"DAV:",
"propertyupdate" );
00224 QDomElement set = addElement( doc, root,
"DAV:",
"set" );
00225 QDomElement prop = addElement( doc, set,
"DAV:",
"prop" );
00226 addElement( doc, prop,
"DAV:",
"contentclass",
"urn:content-classes:appointment" );
00227 addElement( doc, prop,
"http://schemas.microsoft.com/exchange/",
"outlookmessageclass",
"IPM.appointment" );
00228
00229 addElement( doc, prop,
"urn:schemas:calendar:",
"alldayevent",
00230 event->doesFloat() ?
"1" :
"0" );
00231 addElement( doc, prop,
"urn:schemas:calendar:",
"busystatus",
00232 event->transparency() ?
"Free" :
"Busy" );
00233
00234
00235
int tzOffset = - KRFCDate::localUTCOffset();
00236 QString offsetString;
00237
if ( tzOffset==0 )
00238 offsetString =
"Z";
00239
else if ( tzOffset > 0 )
00240 offsetString = QString(
"+%1:%2" ).arg(tzOffset/60, 2).arg( tzOffset%60, 2 );
00241
else
00242 offsetString = QString(
"-%1:%2" ).arg((-tzOffset)/60, 2).arg( (-tzOffset)%60, 2 );
00243 offsetString = offsetString.replace( QRegExp(
" "),
"0" );
00244
00245 kdDebug() <<
"Timezone offset: " << tzOffset <<
" : " << offsetString << endl;
00246
00247 addElement( doc, prop,
"urn:schemas:calendar:",
"dtstart",
00248 event->dtStart().toString(
"yyyy-MM-ddThh:mm:ss.zzz" )+ offsetString );
00249
00250
00251 addElement( doc, prop,
"urn:schemas:calendar:",
"dtend",
00252 event->dtEnd().toString(
"yyyy-MM-ddThh:mm:ss.zzz" ) + offsetString );
00253 addElement( doc, prop,
"urn:schemas:calendar:",
"lastmodified", zoneAsUtc( event->lastModified(), mTimeZoneId ).toString( Qt::ISODate )+
"Z" );
00254
00255
00256 addElement( doc, prop,
"urn:schemas:httpmail:",
"textdescription", event->description() );
00257 addElement( doc, prop,
"urn:schemas:httpmail:",
"subject", event->summary() );
00258 addElement( doc, prop,
"urn:schemas:calendar:",
"location", event->location() );
00259
00260 addElement( doc, prop,
"urn:schemas:calendar:",
"uid", event->uid() );
00261
00262
00263 KCal::Recurrence *recurrence = event->recurrence();
00264 kdDebug() <<
"Recurrence->doesRecur(): " << recurrence->doesRecur() << endl;
00265
if ( recurrence->doesRecur() != KCal::Recurrence::rNone ) {
00266 addElement( doc, prop,
"urn:schemas:calendar:",
"instancetype",
"1" );
00267 KCal::ICalFormat *format =
new KCal::ICalFormat();
00268 QString recurstr = format->toString( recurrence );
00269
00270 recurstr = recurstr.replace( QRegExp(
"^[A-Z]*[\\s]*:"),
"").stripWhiteSpace();
00271 kdDebug() <<
"Recurrence rule after replace: \"" << recurstr <<
"\"" << endl;
00272
delete format;
00273 QDomElement rrule = addElement( doc, prop,
"urn:schemas:calendar:",
"rrule" );
00274 addElement( doc, rrule,
"xml:",
"v", recurstr );
00275 addElement( doc, prop,
"urn:schemas:calendar:",
"timezoneid", timezoneid( tzOffset ) );
00276 }
else {
00277 addElement( doc, prop,
"urn:schemas:calendar:",
"instancetype",
"0" );
00278 }
00279
00280 KCal::DateList exdates = event->exDates();
00281
if ( !exdates.isEmpty() ) {
00282 QDomElement exdate = addElement( doc, prop,
"urn:schemas:calendar:",
"exdate" );
00283 KCal::DateList::iterator it;
00284
for ( it = exdates.begin(); it != exdates.end(); ++it ) {
00285 QString date = (*it).toString(
"yyyy-MM-ddT00:00:00.000" )+ offsetString;
00286
00287 addElement( doc, exdate,
"xml:",
"v", date );
00288 }
00289 }
00290
00291 KCal::Alarm::List
alarms = event->alarms();
00292
if ( alarms.count() > 0 ) {
00293 KCal::Alarm* alarm = alarms.first();
00294
00295
00296
00297
if ( alarm->hasStartOffset() ) {
00298
int offset = - alarm->startOffset().asSeconds();
00299 addElement( doc, prop,
"urn:schemas:calendar:",
"reminderoffset", QString::number( offset ) );
00300 }
00301 }
00302
00303 kdDebug() <<
"Uploading event: " << endl;
00304 kdDebug() << doc.toString() << endl;
00305
00306 KIO::DavJob *job = KIO::davPropPatch( url, doc,
false );
00307 job->setWindow( mWindow );
00308 connect( job, SIGNAL( result( KIO::Job * ) ),
this, SLOT( slotPatchResult( KIO::Job * ) ) );
00309 }
00310
00311
void ExchangeUpload::slotPatchResult( KIO::Job* job )
00312 {
00313 kdDebug() <<
"slotPropPatchResult()" << endl;
00314
if ( job->error() ) {
00315 job->showErrorDialog( 0L );
00316 kdDebug() <<
"Error: " << job->error() << endl;
00317 emit finished(
this, ExchangeClient::CommunicationError,
"IO Error: " + QString::number(job->error()) +
":" + job->errorString() );
00318
return;
00319 }
00320
00321 QDomDocument response = static_cast<KIO::DavJob *>( job )->response();
00322
00323
00324
00325
00326
00327 QDomElement status = response.documentElement().namedItem(
"response" ).namedItem(
"status" ).toElement();
00328 QDomElement propstat = response.documentElement().namedItem(
"response" ).namedItem(
"propstat" ).namedItem(
"status" ).toElement();
00329 kdDebug() <<
"status: " << status.text() << endl;
00330 kdDebug() <<
"propstat: " << propstat.text() << endl;
00331
if ( ! ( status.text().contains(
"201" ) ||
00332 propstat.text().contains(
"200" ) ) )
00333 emit finished(
this, ExchangeClient::EventWriteError,
"Upload error response: \n" + response.toString() );
00334
else
00335 emit finished(
this, ExchangeClient::ResultOK, QString::null );
00336 }
00337
00338
#include "exchangeupload.moc"