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.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 22:38:35 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003