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 = mImpl->createScheduleComponent(incidence,method);
00313
00314 QString messageText = QString::fromUtf8( icalcomponent_as_ical_string(message) );
00315
00316 #if 0
00317 kdDebug(5800) << "ICalFormat::createScheduleMessage: message START\n"
00318 << messageText
00319 << "ICalFormat::createScheduleMessage: message END" << endl;
00320 #endif
00321
00322 return messageText;
00323 }
00324
00325 FreeBusy *ICalFormat::parseFreeBusy( const QString &str )
00326 {
00327 clearException();
00328
00329 icalcomponent *message;
00330 message = icalparser_parse_string( str.utf8() );
00331
00332 if ( !message ) return 0;
00333
00334 icalcomponent *c;
00335 c = icalcomponent_get_first_component( message, ICAL_VFREEBUSY_COMPONENT );
00336 if ( c ) {
00337 return mImpl->readFreeBusy( c );
00338 } else {
00339 kdDebug(5800) << "ICalFormat:parseFreeBusy: object is not a freebusy."
00340 << endl;
00341 return 0;
00342 }
00343 }
00344
00345 ScheduleMessage *ICalFormat::parseScheduleMessage( Calendar *cal,
00346 const QString &messageText )
00347 {
00348 setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );
00349 clearException();
00350
00351 if (messageText.isEmpty()) return 0;
00352
00353 icalcomponent *message;
00354 message = icalparser_parse_string(messageText.utf8());
00355
00356 if (!message) return 0;
00357
00358 icalproperty *m = icalcomponent_get_first_property(message,
00359 ICAL_METHOD_PROPERTY);
00360
00361 if (!m) return 0;
00362
00363 icalcomponent *c;
00364
00365 IncidenceBase *incidence = 0;
00366 c = icalcomponent_get_first_component(message,ICAL_VEVENT_COMPONENT);
00367 if (c) {
00368 incidence = mImpl->readEvent(c);
00369 }
00370
00371 if (!incidence) {
00372 c = icalcomponent_get_first_component(message,ICAL_VTODO_COMPONENT);
00373 if (c) {
00374 incidence = mImpl->readTodo(c);
00375 }
00376 }
00377
00378 if (!incidence) {
00379 c = icalcomponent_get_first_component(message,ICAL_VFREEBUSY_COMPONENT);
00380 if (c) {
00381 incidence = mImpl->readFreeBusy(c);
00382 }
00383 }
00384
00385 if (!incidence) {
00386 kdDebug(5800) << "ICalFormat:parseScheduleMessage: object is not a freebusy, event or todo" << endl;
00387 return 0;
00388 }
00389
00390 kdDebug(5800) << "ICalFormat::parseScheduleMessage() getting method..." << endl;
00391
00392 icalproperty_method icalmethod = icalproperty_get_method(m);
00393 Scheduler::Method method;
00394
00395 switch (icalmethod) {
00396 case ICAL_METHOD_PUBLISH:
00397 method = Scheduler::Publish;
00398 break;
00399 case ICAL_METHOD_REQUEST:
00400 method = Scheduler::Request;
00401 break;
00402 case ICAL_METHOD_REFRESH:
00403 method = Scheduler::Refresh;
00404 break;
00405 case ICAL_METHOD_CANCEL:
00406 method = Scheduler::Cancel;
00407 break;
00408 case ICAL_METHOD_ADD:
00409 method = Scheduler::Add;
00410 break;
00411 case ICAL_METHOD_REPLY:
00412 method = Scheduler::Reply;
00413 break;
00414 case ICAL_METHOD_COUNTER:
00415 method = Scheduler::Counter;
00416 break;
00417 case ICAL_METHOD_DECLINECOUNTER:
00418 method = Scheduler::Declinecounter;
00419 break;
00420 default:
00421 method = Scheduler::NoMethod;
00422 kdDebug(5800) << "ICalFormat::parseScheduleMessage(): Unknow method" << endl;
00423 break;
00424 }
00425
00426 kdDebug(5800) << "ICalFormat::parseScheduleMessage() restriction..." << endl;
00427
00428 if (!icalrestriction_check(message)) {
00429 setException(new ErrorFormat(ErrorFormat::Restriction,
00430 Scheduler::translatedMethodName(method) + ": " +
00431 mImpl->extractErrorProperty(c)));
00432 return 0;
00433 }
00434
00435 icalcomponent *calendarComponent = mImpl->createCalendarComponent(cal);
00436
00437 Incidence *existingIncidence = cal->event(incidence->uid());
00438 if (existingIncidence) {
00439
00440 if (existingIncidence->type() == "Todo") {
00441 Todo *todo = static_cast<Todo *>(existingIncidence);
00442 icalcomponent_add_component(calendarComponent,
00443 mImpl->writeTodo(todo));
00444 }
00445 if (existingIncidence->type() == "Event") {
00446 Event *event = static_cast<Event *>(existingIncidence);
00447 icalcomponent_add_component(calendarComponent,
00448 mImpl->writeEvent(event));
00449 }
00450 } else {
00451 calendarComponent = 0;
00452 }
00453
00454 kdDebug(5800) << "ICalFormat::parseScheduleMessage() classify..." << endl;
00455
00456 icalclass result = icalclassify(message,calendarComponent,(char *)"");
00457
00458 kdDebug(5800) << "ICalFormat::parseScheduleMessage() returning..." << endl;
00459 kdDebug(5800) << "ICalFormat::parseScheduleMessage(), result = " << result << endl;
00460
00461 ScheduleMessage::Status status;
00462
00463 switch (result) {
00464 case ICAL_PUBLISH_NEW_CLASS:
00465 status = ScheduleMessage::PublishNew;
00466 break;
00467 case ICAL_PUBLISH_UPDATE_CLASS:
00468 status = ScheduleMessage::PublishUpdate;
00469 break;
00470 case ICAL_OBSOLETE_CLASS:
00471 status = ScheduleMessage::Obsolete;
00472 break;
00473 case ICAL_REQUEST_NEW_CLASS:
00474 status = ScheduleMessage::RequestNew;
00475 break;
00476 case ICAL_REQUEST_UPDATE_CLASS:
00477 status = ScheduleMessage::RequestUpdate;
00478 break;
00479 case ICAL_UNKNOWN_CLASS:
00480 default:
00481 status = ScheduleMessage::Unknown;
00482 break;
00483 }
00484
00485 kdDebug(5800) << "ICalFormat::parseScheduleMessage(), status = " << status << endl;
00486
00487 return new ScheduleMessage(incidence,method,status);
00488 }
00489
00490 void ICalFormat::setTimeZone( const QString &id, bool utc )
00491 {
00492 mTimeZoneId = id;
00493 mUtc = utc;
00494 }
00495
00496 QString ICalFormat::timeZoneId() const
00497 {
00498 return mTimeZoneId;
00499 }
00500
00501 bool ICalFormat::utc() const
00502 {
00503 return mUtc;
00504 }
This file is part of the documentation for libkcal Library Version 3.3.2.