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 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 // We need to do the unfolding (removing the "\n " in the ics file) 00080 // before interpreting the contents as UTF-8. So, first read in the 00081 // file as latin1, unfold, and only then convert to UTF-8. 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() ) // empty files are valid 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 // Write backup file 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 // Convert to UTF8 and save 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 // Get first VCALENDAR component. 00135 // TODO: Handle more than one VCALENDAR or non-VCALENDAR top components 00136 icalcomponent *calendar; 00137 00138 calendar = icalcomponent_new_from_string( text.utf8().data() ); 00139 // kdDebug(5800) << "Error: " << icalerror_perror() << endl; 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 // put all objects into their proper places 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 // put all objects into their proper places 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 // todos 00216 Todo::List todoList = cal->rawTodos(); 00217 Todo::List::ConstIterator it; 00218 for( it = todoList.begin(); it != todoList.end(); ++it ) { 00219 // kdDebug(5800) << "ICalFormat::toString() write todo " 00220 // << (*it)->uid() << endl; 00221 component = mImpl->writeTodo( *it ); 00222 icalcomponent_add_component( calendar, component ); 00223 } 00224 00225 // events 00226 Event::List events = cal->rawEvents(); 00227 Event::List::ConstIterator it2; 00228 for( it2 = events.begin(); it2 != events.end(); ++it2 ) { 00229 // kdDebug(5800) << "ICalFormat::toString() write event " 00230 // << (*it2)->uid() << endl; 00231 component = mImpl->writeEvent( *it2 ); 00232 icalcomponent_add_component( calendar, component ); 00233 } 00234 00235 // journals 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 // TODO: check, if cast is required, or if it can be done by virtual funcs. 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 }
KDE Logo
This file is part of the documentation for libkcal Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:57:44 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003