icalformat.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qdatetime.h>
00022 #include <qstring.h>
00023 #include <qptrlist.h>
00024 #include <qregexp.h>
00025 #include <qclipboard.h>
00026 #include <qfile.h>
00027 #include <qtextstream.h>
00028
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031
00032 extern "C" {
00033 #include <ical.h>
00034 #include <icalss.h>
00035 #include <icalparser.h>
00036 #include <icalrestriction.h>
00037 }
00038
00039 #include "calendar.h"
00040 #include "calendarlocal.h"
00041 #include "journal.h"
00042
00043 #include "icalformat.h"
00044 #include "icalformatimpl.h"
00045 #include <ksavefile.h>
00046
00047 #include <stdio.h>
00048
00049 #define _ICAL_VERSION "2.0"
00050
00051 using namespace KCal;
00052
00053 ICalFormat::ICalFormat()
00054 {
00055 mImpl = new ICalFormatImpl( this );
00056
00057 mTimeZoneId = "UTC";
00058 mUtc = true;
00059 }
00060
00061 ICalFormat::~ICalFormat()
00062 {
00063 delete mImpl;
00064 }
00065
00066 #if defined(_AIX) && defined(open)
00067 #undef open
00068 #endif
00069
00070 bool ICalFormat::load( Calendar *calendar, const QString &fileName)
00071 {
00072 kdDebug(5800) << "ICalFormat::load() " << fileName << endl;
00073
00074 clearException();
00075
00076 QFile file( fileName );
00077 if (!file.open( IO_ReadOnly ) ) {
00078 kdDebug(5800) << "ICalFormat::load() load error" << endl;
00079 setException(new ErrorFormat(ErrorFormat::LoadError));
00080 return false;
00081 }
00082 QTextStream ts( &file );
00083
00084
00085
00086 ts.setEncoding( QTextStream::Latin1 );
00087 QString text = ts.read();
00088 text.replace( QRegExp("\n[ \t]"), "");
00089 text = QString::fromUtf8( text.latin1() );
00090 file.close();
00091
00092 if ( text.stripWhiteSpace().isEmpty() )
00093 return true;
00094 else
00095 return fromString( calendar, text );
00096 }
00097
00098
00099 bool ICalFormat::save( Calendar *calendar, const QString &fileName )
00100 {
00101 kdDebug(5800) << "ICalFormat::save(): " << fileName << endl;
00102
00103 clearException();
00104
00105 QString text = toString( calendar );
00106
00107 if ( text.isNull() ) return false;
00108
00109
00110 KSaveFile::backupFile( fileName );
00111
00112 KSaveFile file( fileName );
00113 if ( file.status() != 0 ) {
00114 kdDebug(5800) << "ICalFormat::save() errno: " << strerror( file.status() )
00115 << endl;
00116 setException( new ErrorFormat( ErrorFormat::SaveError,
00117 i18n( "Error saving to '%1'." ).arg( fileName ) ) );
00118 return false;
00119 }
00120
00121
00122 QCString textUtf8 = text.utf8();
00123 file.file()->writeBlock( textUtf8.data(), textUtf8.size() - 1 );
00124
00125 if ( !file.close() ) {
00126 setException(new ErrorFormat(ErrorFormat::SaveError,
00127 i18n("Could not save '%1'").arg(fileName)));
00128 return false;
00129 }
00130
00131 return true;
00132 }
00133
00134 bool ICalFormat::fromString( Calendar *cal, const QString &text )
00135 {
00136 setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );
00137
00138
00139
00140 icalcomponent *calendar;
00141
00142 calendar = icalcomponent_new_from_string( text.utf8().data() );
00143
00144 if (!calendar) {
00145 kdDebug(5800) << "ICalFormat::load() parse error" << endl;
00146 setException(new ErrorFormat(ErrorFormat::ParseErrorIcal));
00147 return false;
00148 }
00149
00150 bool success = true;
00151
00152 if (icalcomponent_isa(calendar) == ICAL_XROOT_COMPONENT) {
00153 icalcomponent *comp;
00154 for ( comp = icalcomponent_get_first_component(calendar, ICAL_VCALENDAR_COMPONENT);
00155 comp != 0; comp = icalcomponent_get_next_component(calendar, ICAL_VCALENDAR_COMPONENT) ) {
00156
00157 if ( !mImpl->populate( cal, comp ) ) {
00158 kdDebug(5800) << "ICalFormat::load(): Could not populate calendar" << endl;
00159 if ( !exception() ) {
00160 setException(new ErrorFormat(ErrorFormat::ParseErrorKcal));
00161 }
00162 success = false;
00163 } else
00164 mLoadedProductId = mImpl->loadedProductId();
00165 }
00166 } else if (icalcomponent_isa(calendar) != ICAL_VCALENDAR_COMPONENT) {
00167 kdDebug(5800) << "ICalFormat::load(): No VCALENDAR component found" << endl;
00168 setException(new ErrorFormat(ErrorFormat::NoCalendar));
00169 success = false;
00170 } else {
00171
00172 if ( !mImpl->populate( cal, calendar ) ) {
00173 kdDebug(5800) << "ICalFormat::load(): Could not populate calendar" << endl;
00174 if ( !exception() ) {
00175 setException(new ErrorFormat(ErrorFormat::ParseErrorKcal));
00176 }
00177 success = false;
00178 } else
00179 mLoadedProductId = mImpl->loadedProductId();
00180 }
00181
00182 icalcomponent_free( calendar );
00183
00184 return success;
00185 }
00186
00187 Incidence *ICalFormat::fromString( const QString &text )
00188 {
00189 CalendarLocal cal( mTimeZoneId );
00190 fromString(&cal, text);
00191
00192 Incidence *ical = 0;
00193 Event::List elist = cal.events();
00194 if ( elist.count() > 0 ) {
00195 ical = elist.first();
00196 } else {
00197 Todo::List tlist = cal.todos();
00198 if ( tlist.count() > 0 ) {
00199 ical = tlist.first();
00200 } else {
00201 Journal::List jlist = cal.journals();
00202 if ( jlist.count() > 0 ) {
00203 ical = jlist.first();
00204 }
00205 }
00206 }
00207
00208 return ical ? ical->clone() : 0;
00209 }
00210
00211 QString ICalFormat::toString( Calendar *cal )
00212 {
00213 setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );
00214
00215 icalcomponent *calendar = mImpl->createCalendarComponent(cal);
00216
00217 icalcomponent *component;
00218
00219
00220 Todo::List todoList = cal->rawTodos();
00221 Todo::List::ConstIterator it;
00222 for( it = todoList.begin(); it != todoList.end(); ++it ) {
00223
00224
00225 component = mImpl->writeTodo( *it );
00226 icalcomponent_add_component( calendar, component );
00227 }
00228
00229
00230 Event::List events = cal->rawEvents();
00231 Event::List::ConstIterator it2;
00232 for( it2 = events.begin(); it2 != events.end(); ++it2 ) {
00233
00234
00235 component = mImpl->writeEvent( *it2 );
00236 icalcomponent_add_component( calendar, component );
00237 }
00238
00239
00240 Journal::List journals = cal->journals();
00241 Journal::List::ConstIterator it3;
00242 for( it3 = journals.begin(); it3 != journals.end(); ++it3 ) {
00243 kdDebug(5800) << "ICalFormat::toString() write journal "
00244 << (*it3)->uid() << endl;
00245 component = mImpl->writeJournal( *it3 );
00246 icalcomponent_add_component( calendar, component );
00247 }
00248
00249 QString text = QString::fromUtf8( icalcomponent_as_ical_string( calendar ) );
00250
00251 icalcomponent_free( calendar );
00252
00253 if (!text) {
00254 setException(new ErrorFormat(ErrorFormat::SaveError,
00255 i18n("libical error")));
00256 return QString::null;
00257 }
00258
00259 return text;
00260 }
00261
00262 QString ICalFormat::toICalString( Incidence *incidence )
00263 {
00264 CalendarLocal cal( mTimeZoneId );
00265 cal.addIncidence( incidence->clone() );
00266 return toString( &cal );
00267 }
00268
00269 QString ICalFormat::toString( Incidence *incidence )
00270 {
00271 icalcomponent *component;
00272
00273 component = mImpl->writeIncidence( incidence );
00274
00275 QString text = QString::fromUtf8( icalcomponent_as_ical_string( component ) );
00276
00277 icalcomponent_free( component );
00278
00279 return text;
00280 }
00281
00282 QString ICalFormat::toString( Recurrence *recurrence )
00283 {
00284 icalproperty *property;
00285 property = mImpl->writeRecurrenceRule( recurrence );
00286 QString text = QString::fromUtf8( icalproperty_as_ical_string( property ) );
00287 icalproperty_free( property );
00288 return text;
00289 }
00290
00291 bool ICalFormat::fromString( Recurrence * recurrence, const QString& rrule )
00292 {
00293 bool success = true;
00294 icalerror_clear_errno();
00295 struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule.latin1() );
00296 if ( icalerrno != ICAL_NO_ERROR ) {
00297 kdDebug(5800) << "Recurrence parsing error: " << icalerror_strerror( icalerrno ) << endl;
00298 success = false;
00299 }
00300
00301 if ( success ) {
00302 mImpl->readRecurrence( recur, recurrence );
00303 }
00304
00305 return success;
00306 }
00307
00308
00309 QString ICalFormat::createScheduleMessage(IncidenceBase *incidence,
00310 Scheduler::Method method)
00311 {
00312 icalcomponent *message = 0;
00313
00314
00315 if ( incidence->type() == "Event" || incidence->type() == "Todo" ) {
00316 Incidence* i = static_cast<Incidence*>( incidence );
00317 if ( i->schedulingID() != i->uid() ) {
00318
00319 i = i->clone();
00320 i->setUid( i->schedulingID() );
00321 i->setSchedulingID( QString::null );
00322
00323
00324 message = mImpl->createScheduleComponent( i, method );
00325
00326
00327 delete i;
00328 }
00329 }
00330
00331 if ( message == 0 )
00332 message = mImpl->createScheduleComponent(incidence,method);
00333
00334 QString messageText = QString::fromUtf8( icalcomponent_as_ical_string(message) );
00335
00336 #if 0
00337 kdDebug(5800) << "ICalFormat::createScheduleMessage: message START\n"
00338 << messageText
00339 << "ICalFormat::createScheduleMessage: message END" << endl;
00340 #endif
00341
00342 return messageText;
00343 }
00344
00345 FreeBusy *ICalFormat::parseFreeBusy( const QString &str )
00346 {
00347 clearException();
00348
00349 icalcomponent *message;
00350 message = icalparser_parse_string( str.utf8() );
00351
00352 if ( !message ) return 0;
00353
00354 icalcomponent *c;
00355 c = icalcomponent_get_first_component( message, ICAL_VFREEBUSY_COMPONENT );
00356 if ( c ) {
00357 return mImpl->readFreeBusy( c );
00358 } else {
00359 kdDebug(5800) << "ICalFormat:parseFreeBusy: object is not a freebusy."
00360 << endl;
00361 return 0;
00362 }
00363 }
00364
00365 ScheduleMessage *ICalFormat::parseScheduleMessage( Calendar *cal,
00366 const QString &messageText )
00367 {
00368 setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );
00369 clearException();
00370
00371 if (messageText.isEmpty()) {
00372 setException(new ErrorFormat(ErrorFormat::LoadError, i18n( "Empty file" )));
00373 return 0;
00374 }
00375
00376 icalcomponent *message;
00377 message = icalparser_parse_string(messageText.utf8());
00378
00379 if (!message) return 0;
00380
00381 icalproperty *m = icalcomponent_get_first_property(message,
00382 ICAL_METHOD_PROPERTY);
00383
00384 if (!m) return 0;
00385
00386 icalcomponent *c;
00387
00388 IncidenceBase *incidence = 0;
00389 c = icalcomponent_get_first_component(message,ICAL_VEVENT_COMPONENT);
00390 if (c) {
00391 incidence = mImpl->readEvent(c);
00392 }
00393
00394 if (!incidence) {
00395 c = icalcomponent_get_first_component(message,ICAL_VTODO_COMPONENT);
00396 if (c) {
00397 incidence = mImpl->readTodo(c);
00398 }
00399 }
00400
00401 if (!incidence) {
00402 c = icalcomponent_get_first_component(message,ICAL_VFREEBUSY_COMPONENT);
00403 if (c) {
00404 incidence = mImpl->readFreeBusy(c);
00405 }
00406 }
00407
00408 if (!incidence) {
00409 kdDebug(5800) << "ICalFormat:parseScheduleMessage: object is not a freebusy, event or todo" << endl;
00410 return 0;
00411 }
00412
00413 kdDebug(5800) << "ICalFormat::parseScheduleMessage() getting method..." << endl;
00414
00415 icalproperty_method icalmethod = icalproperty_get_method(m);
00416 Scheduler::Method method;
00417
00418 switch (icalmethod) {
00419 case ICAL_METHOD_PUBLISH:
00420 method = Scheduler::Publish;
00421 break;
00422 case ICAL_METHOD_REQUEST:
00423 method = Scheduler::Request;
00424 break;
00425 case ICAL_METHOD_REFRESH:
00426 method = Scheduler::Refresh;
00427 break;
00428 case ICAL_METHOD_CANCEL:
00429 method = Scheduler::Cancel;
00430 break;
00431 case ICAL_METHOD_ADD:
00432 method = Scheduler::Add;
00433 break;
00434 case ICAL_METHOD_REPLY:
00435 method = Scheduler::Reply;
00436 break;
00437 case ICAL_METHOD_COUNTER:
00438 method = Scheduler::Counter;
00439 break;
00440 case ICAL_METHOD_DECLINECOUNTER:
00441 method = Scheduler::Declinecounter;
00442 break;
00443 default:
00444 method = Scheduler::NoMethod;
00445 kdDebug(5800) << "ICalFormat::parseScheduleMessage(): Unknow method" << endl;
00446 break;
00447 }
00448
00449 kdDebug(5800) << "ICalFormat::parseScheduleMessage() restriction..." << endl;
00450
00451 if (!icalrestriction_check(message)) {
00452 setException(new ErrorFormat(ErrorFormat::Restriction,
00453 Scheduler::translatedMethodName(method) + ": " +
00454 mImpl->extractErrorProperty(c)));
00455 return 0;
00456 }
00457
00458 icalcomponent *calendarComponent = mImpl->createCalendarComponent(cal);
00459
00460 Incidence *existingIncidence =
00461 cal->incidenceFromSchedulingID( incidence->uid() );
00462 if (existingIncidence) {
00463
00464 if (existingIncidence->type() == "Todo") {
00465 Todo *todo = static_cast<Todo *>(existingIncidence);
00466 icalcomponent_add_component(calendarComponent,
00467 mImpl->writeTodo(todo));
00468 }
00469 if (existingIncidence->type() == "Event") {
00470 Event *event = static_cast<Event *>(existingIncidence);
00471 icalcomponent_add_component(calendarComponent,
00472 mImpl->writeEvent(event));
00473 }
00474 } else {
00475 calendarComponent = 0;
00476 }
00477
00478 kdDebug(5800) << "ICalFormat::parseScheduleMessage() classify..." << endl;
00479
00480 icalclass result = icalclassify(message,calendarComponent,(char *)"");
00481
00482 kdDebug(5800) << "ICalFormat::parseScheduleMessage() returning..." << endl;
00483 kdDebug(5800) << "ICalFormat::parseScheduleMessage(), result = " << result << endl;
00484
00485 ScheduleMessage::Status status;
00486
00487 switch (result) {
00488 case ICAL_PUBLISH_NEW_CLASS:
00489 status = ScheduleMessage::PublishNew;
00490 break;
00491 case ICAL_PUBLISH_UPDATE_CLASS:
00492 status = ScheduleMessage::PublishUpdate;
00493 break;
00494 case ICAL_OBSOLETE_CLASS:
00495 status = ScheduleMessage::Obsolete;
00496 break;
00497 case ICAL_REQUEST_NEW_CLASS:
00498 status = ScheduleMessage::RequestNew;
00499 break;
00500 case ICAL_REQUEST_UPDATE_CLASS:
00501 status = ScheduleMessage::RequestUpdate;
00502 break;
00503 case ICAL_UNKNOWN_CLASS:
00504 default:
00505 status = ScheduleMessage::Unknown;
00506 break;
00507 }
00508
00509 kdDebug(5800) << "ICalFormat::parseScheduleMessage(), status = " << status << endl;
00510
00511 return new ScheduleMessage(incidence,method,status);
00512 }
00513
00514 void ICalFormat::setTimeZone( const QString &id, bool utc )
00515 {
00516 mTimeZoneId = id;
00517 mUtc = utc;
00518 }
00519
00520 QString ICalFormat::timeZoneId() const
00521 {
00522 return mTimeZoneId;
00523 }
00524
00525 bool ICalFormat::utc() const
00526 {
00527 return mUtc;
00528 }
This file is part of the documentation for libkcal Library Version 3.3.2.