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 Sat May 1 11:36:21 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003