libkcal Library API Documentation

icalformat.cpp

00001 /* 00002 This file is part of libkcal. 00003 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 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 // We need to do the unfolding (removing the "\n " in the ics file) 00084 // before interpreting the contents as UTF-8. So, first read in the 00085 // file as latin1, unfold, and only then convert to UTF-8. 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() ) // empty files are valid 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 // Write backup file 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 // Convert to UTF8 and save 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 // Get first VCALENDAR component. 00139 // TODO: Handle more than one VCALENDAR or non-VCALENDAR top components 00140 icalcomponent *calendar; 00141 00142 calendar = icalcomponent_new_from_string( text.utf8().data() ); 00143 // kdDebug(5800) << "Error: " << icalerror_perror() << endl; 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 // put all objects into their proper places 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 // put all objects into their proper places 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 // todos 00220 Todo::List todoList = cal->rawTodos(); 00221 Todo::List::ConstIterator it; 00222 for( it = todoList.begin(); it != todoList.end(); ++it ) { 00223 // kdDebug(5800) << "ICalFormat::toString() write todo " 00224 // << (*it)->uid() << endl; 00225 component = mImpl->writeTodo( *it ); 00226 icalcomponent_add_component( calendar, component ); 00227 } 00228 00229 // events 00230 Event::List events = cal->rawEvents(); 00231 Event::List::ConstIterator it2; 00232 for( it2 = events.begin(); it2 != events.end(); ++it2 ) { 00233 // kdDebug(5800) << "ICalFormat::toString() write event " 00234 // << (*it2)->uid() << endl; 00235 component = mImpl->writeEvent( *it2 ); 00236 icalcomponent_add_component( calendar, component ); 00237 } 00238 00239 // journals 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 // TODO: check, if cast is required, or if it can be done by virtual funcs. 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 }
KDE Logo
This file is part of the documentation for libkcal Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:49:08 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003