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