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 }