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
#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
00084
00085
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() )
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
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
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
00139
00140 icalcomponent *calendar;
00141
00142 calendar = icalcomponent_new_from_string( text.utf8().data() );
00143
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
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
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
00220
Todo::List todoList = cal->
rawTodos();
00221 Todo::List::ConstIterator it;
00222
for( it = todoList.begin(); it != todoList.end(); ++it ) {
00223
00224
00225 component = mImpl->writeTodo( *it );
00226 icalcomponent_add_component( calendar, component );
00227 }
00228
00229
00230
Event::List events = cal->
rawEvents();
00231 Event::List::ConstIterator it2;
00232
for( it2 = events.begin(); it2 != events.end(); ++it2 ) {
00233
00234
00235 component = mImpl->writeEvent( *it2 );
00236 icalcomponent_add_component( calendar, component );
00237 }
00238
00239
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
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 }