-rw-r--r-- | libkcal/icalformat.cpp | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/libkcal/icalformat.cpp b/libkcal/icalformat.cpp new file mode 100644 index 0000000..5893db5 --- a/dev/null +++ b/libkcal/icalformat.cpp | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | This file is part of libkcal. | ||
3 | Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to | ||
17 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <qdatetime.h> | ||
22 | #include <qstring.h> | ||
23 | #include <qptrlist.h> | ||
24 | #include <qregexp.h> | ||
25 | #include <qclipboard.h> | ||
26 | #include <qfile.h> | ||
27 | #include <qtextstream.h> | ||
28 | #include <qtextcodec.h> | ||
29 | #include <stdlib.h> | ||
30 | |||
31 | #include <kdebug.h> | ||
32 | #include <kglobal.h> | ||
33 | #include <klocale.h> | ||
34 | |||
35 | extern "C" { | ||
36 | #include <ical.h> | ||
37 | #include <icalss.h> | ||
38 | #include <icalparser.h> | ||
39 | #include <icalrestriction.h> | ||
40 | } | ||
41 | |||
42 | #include "calendar.h" | ||
43 | #include "calendarlocal.h" | ||
44 | #include "journal.h" | ||
45 | |||
46 | #include "icalformat.h" | ||
47 | #include "icalformatimpl.h" | ||
48 | |||
49 | #define _ICAL_VERSION "2.0" | ||
50 | |||
51 | using namespace KCal; | ||
52 | |||
53 | ICalFormat::ICalFormat(bool quick ) | ||
54 | { | ||
55 | mQuicksave = false; //quick; | ||
56 | mImpl = new ICalFormatImpl( this ); | ||
57 | tzOffsetMin = 0; | ||
58 | //qDebug("new ICalFormat() "); | ||
59 | } | ||
60 | |||
61 | ICalFormat::~ICalFormat() | ||
62 | { | ||
63 | delete mImpl; | ||
64 | //qDebug("delete ICalFormat "); | ||
65 | } | ||
66 | |||
67 | bool ICalFormat::load( Calendar *calendar, const QString &fileName) | ||
68 | { | ||
69 | |||
70 | clearException(); | ||
71 | |||
72 | QFile file( fileName ); | ||
73 | if (!file.open( IO_ReadOnly ) ) { | ||
74 | setException(new ErrorFormat(ErrorFormat::LoadError)); | ||
75 | return false; | ||
76 | } | ||
77 | QTextStream ts( &file ); | ||
78 | QString text; | ||
79 | #if 0 | ||
80 | if ( !mQuicksave ) { | ||
81 | qDebug("KO: No quickload!"); | ||
82 | ts.setEncoding( QTextStream::Latin1 ); | ||
83 | text = ts.read(); | ||
84 | } else { | ||
85 | ts.setCodec( QTextCodec::codecForName("utf8") ); | ||
86 | text = ts.read(); | ||
87 | } | ||
88 | #endif | ||
89 | ts.setEncoding( QTextStream::Latin1 ); | ||
90 | text = ts.read(); | ||
91 | file.close(); | ||
92 | |||
93 | return fromString( calendar, text ); | ||
94 | } | ||
95 | |||
96 | //#include <qdatetime.h> | ||
97 | bool ICalFormat::save( Calendar *calendar, const QString &fileName ) | ||
98 | { | ||
99 | //kdDebug(5800) << "ICalFormat::save(): " << fileName << endl; | ||
100 | //qDebug("ICalFormat::save "); | ||
101 | clearException(); | ||
102 | QString text = toString( calendar ); | ||
103 | //return false; | ||
104 | // qDebug("to string takes ms: %d ",is.elapsed() ); | ||
105 | if ( text.isNull() ) return false; | ||
106 | |||
107 | // TODO: write backup file | ||
108 | //is.restart(); | ||
109 | QFile file( fileName ); | ||
110 | if (!file.open( IO_WriteOnly ) ) { | ||
111 | setException(new ErrorFormat(ErrorFormat::SaveError, | ||
112 | i18n("Could not open file '%1'").arg(fileName))); | ||
113 | return false; | ||
114 | } | ||
115 | QTextStream ts( &file ); | ||
116 | |||
117 | // #ifdef DESKTOP_VERSION | ||
118 | // mQuicksave = false; | ||
119 | // #endif | ||
120 | // if ( mQuicksave ) { | ||
121 | // ts << text.utf8(); | ||
122 | // } else { | ||
123 | // ts.setEncoding( QTextStream::Latin1 ); | ||
124 | // ts << text; | ||
125 | // //ts << text.latin1(); | ||
126 | // } | ||
127 | ts.setEncoding( QTextStream::Latin1 ); | ||
128 | ts << text; | ||
129 | file.close(); | ||
130 | //qDebug("saving file takes ms: %d ", is.elapsed() ); | ||
131 | return true; | ||
132 | } | ||
133 | |||
134 | bool ICalFormat::fromString( Calendar *cal, const QString &text ) | ||
135 | { | ||
136 | setTimeZone( cal->timeZoneId(), !cal->isLocalTime() ); | ||
137 | // qDebug("ICalFormat::fromString tz: %s ", cal->timeZoneId().latin1()); | ||
138 | // Get first VCALENDAR component. | ||
139 | // TODO: Handle more than one VCALENDAR or non-VCALENDAR top components | ||
140 | icalcomponent *calendar; | ||
141 | |||
142 | //calendar = icalcomponent_new_from_string( text.local8Bit().data()); | ||
143 | // good calendar = icalcomponent_new_from_string( text.utf8().data()); | ||
144 | calendar = icalcomponent_new_from_string( (char*)text.latin1()); | ||
145 | if (!calendar) { | ||
146 | setException(new ErrorFormat(ErrorFormat::ParseErrorIcal)); | ||
147 | return false; | ||
148 | } | ||
149 | |||
150 | bool success = true; | ||
151 | |||
152 | if (icalcomponent_isa(calendar) != ICAL_VCALENDAR_COMPONENT) { | ||
153 | setException(new ErrorFormat(ErrorFormat::NoCalendar)); | ||
154 | success = false; | ||
155 | } else { | ||
156 | // put all objects into their proper places | ||
157 | if ( !mImpl->populate( cal, calendar ) ) { | ||
158 | if ( !exception() ) { | ||
159 | setException(new ErrorFormat(ErrorFormat::ParseErrorKcal)); | ||
160 | } | ||
161 | success = false; | ||
162 | } else | ||
163 | mLoadedProductId = mImpl->loadedProductId(); | ||
164 | } | ||
165 | |||
166 | icalcomponent_free( calendar ); | ||
167 | |||
168 | return success; | ||
169 | } | ||
170 | |||
171 | Incidence *ICalFormat::fromString( const QString &text ) | ||
172 | { | ||
173 | CalendarLocal cal( mTimeZoneId ); | ||
174 | fromString(&cal, text); | ||
175 | |||
176 | Incidence *ical = 0; | ||
177 | QPtrList<Event> elist = cal.events(); | ||
178 | if ( elist.count() > 0 ) { | ||
179 | ical = elist.first(); | ||
180 | } else { | ||
181 | QPtrList<Todo> tlist = cal.todos(); | ||
182 | if ( tlist.count() > 0 ) { | ||
183 | ical = tlist.first(); | ||
184 | } else { | ||
185 | QPtrList<Journal> jlist = cal.journals(); | ||
186 | if ( jlist.count() > 0 ) { | ||
187 | ical = jlist.first(); | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | return ical; | ||
192 | } | ||
193 | #include <qapp.h> | ||
194 | |||
195 | QString ICalFormat::toString( Calendar *cal ) | ||
196 | { | ||
197 | |||
198 | setTimeZone( cal->timeZoneId(), !cal->isLocalTime() ); | ||
199 | |||
200 | icalcomponent *calendar = mImpl->createCalendarComponent(cal); | ||
201 | |||
202 | icalcomponent *component; | ||
203 | |||
204 | // todos | ||
205 | QPtrList<Todo> todoList = cal->rawTodos(); | ||
206 | QPtrListIterator<Todo> qlt(todoList); | ||
207 | for (; qlt.current(); ++qlt) { | ||
208 | component = mImpl->writeTodo(qlt.current()); | ||
209 | icalcomponent_add_component(calendar,component); | ||
210 | //qDebug(" todos "); | ||
211 | qApp->processEvents(); | ||
212 | } | ||
213 | // events | ||
214 | QPtrList<Event> events = cal->rawEvents(); | ||
215 | Event *ev; | ||
216 | for(ev=events.first();ev;ev=events.next()) { | ||
217 | component = mImpl->writeEvent(ev); | ||
218 | icalcomponent_add_component(calendar,component); | ||
219 | //qDebug("events "); | ||
220 | qApp->processEvents(); | ||
221 | } | ||
222 | |||
223 | // journals | ||
224 | QPtrList<Journal> journals = cal->journals(); | ||
225 | Journal *j; | ||
226 | for(j=journals.first();j;j=journals.next()) { | ||
227 | component = mImpl->writeJournal(j); | ||
228 | icalcomponent_add_component(calendar,component); | ||
229 | //qDebug("journals "); | ||
230 | qApp->processEvents(); | ||
231 | } | ||
232 | const char *text; | ||
233 | QString ret =""; | ||
234 | text = icalcomponent_as_ical_string( calendar ); | ||
235 | qApp->processEvents(); | ||
236 | |||
237 | // text = "BEGIN:VCALENDAR\nPRODID\n :-//K Desktop Environment//NONSGML libkcal 3.1//EN\nVERSION\n :2.0\nBEGIN:VEVENT\nDTSTAMP\n :20031231T213514Z\nORGANIZER\n :MAILTO:lutz@putz.de\nCREATED\n :20031231T213513Z\nUID\n :libkcal-1295166342.120\nSEQUENCE\n :0\nLAST-MODIFIED\n :20031231T213513Z\nSUMMARY\n :test1\nCLASS\n :PUBLIC\nPRIORITY\n :3\nDTSTART\n :20040101T090000Z\nDTEND\n :20040101T110000Z\nTRANSP\n :OPAQUE\nEND:VEVENT\nEND:VCALENDAR\n"; | ||
238 | |||
239 | |||
240 | if ( text ) { | ||
241 | ret = QString ( text ); | ||
242 | } | ||
243 | icalcomponent_free( calendar ); | ||
244 | |||
245 | if (!text) { | ||
246 | setException(new ErrorFormat(ErrorFormat::SaveError, | ||
247 | i18n("libical error"))); | ||
248 | return QString::null; | ||
249 | } | ||
250 | |||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | QString ICalFormat::toICalString( Incidence *incidence ) | ||
255 | { | ||
256 | CalendarLocal cal( mTimeZoneId ); | ||
257 | cal.addIncidence( incidence->clone() ); | ||
258 | return toString( &cal ); | ||
259 | } | ||
260 | |||
261 | QString ICalFormat::toString( Incidence *incidence ) | ||
262 | { | ||
263 | icalcomponent *component; | ||
264 | |||
265 | component = mImpl->writeIncidence( incidence ); | ||
266 | |||
267 | const char *text = icalcomponent_as_ical_string( component ); | ||
268 | |||
269 | icalcomponent_free( component ); | ||
270 | |||
271 | return QString::fromLocal8Bit( text ); | ||
272 | } | ||
273 | |||
274 | QString ICalFormat::toString( Recurrence *recurrence ) | ||
275 | { | ||
276 | icalproperty *property; | ||
277 | property = mImpl->writeRecurrenceRule( recurrence ); | ||
278 | const char *text = icalproperty_as_ical_string( property ); | ||
279 | icalproperty_free( property ); | ||
280 | return QString::fromLocal8Bit( text ); | ||
281 | } | ||
282 | /* | ||
283 | bool ICalFormat::fromString( Recurrence * recurrence, const QString& rrule ) | ||
284 | { | ||
285 | bool success = true; | ||
286 | icalerror_clear_errno(); | ||
287 | struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule ); | ||
288 | if ( icalerrno != ICAL_NO_ERROR ) { | ||
289 | kdDebug() << "Recurrence parsing error: " << icalerror_strerror( icalerrno ) << endl; | ||
290 | success = false; | ||
291 | } | ||
292 | |||
293 | if ( success ) { | ||
294 | mImpl->readRecurrence( recur, recurrence ); | ||
295 | } | ||
296 | |||
297 | return success; | ||
298 | } | ||
299 | */ | ||
300 | |||
301 | QString ICalFormat::createScheduleMessage(IncidenceBase *incidence, | ||
302 | Scheduler::Method method) | ||
303 | { | ||
304 | icalcomponent *message = mImpl->createScheduleComponent(incidence,method); | ||
305 | |||
306 | QString messageText = icalcomponent_as_ical_string(message); | ||
307 | |||
308 | |||
309 | |||
310 | return messageText; | ||
311 | } | ||
312 | |||
313 | ScheduleMessage *ICalFormat::parseScheduleMessage( Calendar *cal, | ||
314 | const QString &messageText ) | ||
315 | { | ||
316 | setTimeZone( cal->timeZoneId(), !cal->isLocalTime() ); | ||
317 | clearException(); | ||
318 | |||
319 | if (messageText.isEmpty()) return 0; | ||
320 | |||
321 | icalcomponent *message; | ||
322 | message = icalparser_parse_string(messageText.local8Bit()); | ||
323 | |||
324 | if (!message) return 0; | ||
325 | |||
326 | icalproperty *m = icalcomponent_get_first_property(message, | ||
327 | ICAL_METHOD_PROPERTY); | ||
328 | |||
329 | if (!m) return 0; | ||
330 | |||
331 | icalcomponent *c; | ||
332 | |||
333 | IncidenceBase *incidence = 0; | ||
334 | c = icalcomponent_get_first_component(message,ICAL_VEVENT_COMPONENT); | ||
335 | if (c) { | ||
336 | incidence = mImpl->readEvent(c); | ||
337 | } | ||
338 | |||
339 | if (!incidence) { | ||
340 | c = icalcomponent_get_first_component(message,ICAL_VTODO_COMPONENT); | ||
341 | if (c) { | ||
342 | incidence = mImpl->readTodo(c); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | if (!incidence) { | ||
347 | c = icalcomponent_get_first_component(message,ICAL_VFREEBUSY_COMPONENT); | ||
348 | if (c) { | ||
349 | incidence = mImpl->readFreeBusy(c); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | if (!incidence) { | ||
354 | kdDebug() << "ICalFormat:parseScheduleMessage: object is not a freebusy, event or todo" << endl; | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | kdDebug(5800) << "ICalFormat::parseScheduleMessage() getting method..." << endl; | ||
359 | |||
360 | icalproperty_method icalmethod = icalproperty_get_method(m); | ||
361 | Scheduler::Method method; | ||
362 | |||
363 | switch (icalmethod) { | ||
364 | case ICAL_METHOD_PUBLISH: | ||
365 | method = Scheduler::Publish; | ||
366 | break; | ||
367 | case ICAL_METHOD_REQUEST: | ||
368 | method = Scheduler::Request; | ||
369 | break; | ||
370 | case ICAL_METHOD_REFRESH: | ||
371 | method = Scheduler::Refresh; | ||
372 | break; | ||
373 | case ICAL_METHOD_CANCEL: | ||
374 | method = Scheduler::Cancel; | ||
375 | break; | ||
376 | case ICAL_METHOD_ADD: | ||
377 | method = Scheduler::Add; | ||
378 | break; | ||
379 | case ICAL_METHOD_REPLY: | ||
380 | method = Scheduler::Reply; | ||
381 | break; | ||
382 | case ICAL_METHOD_COUNTER: | ||
383 | method = Scheduler::Counter; | ||
384 | break; | ||
385 | case ICAL_METHOD_DECLINECOUNTER: | ||
386 | method = Scheduler::Declinecounter; | ||
387 | break; | ||
388 | default: | ||
389 | method = Scheduler::NoMethod; | ||
390 | kdDebug(5800) << "ICalFormat::parseScheduleMessage(): Unknow method" << endl; | ||
391 | break; | ||
392 | } | ||
393 | |||
394 | |||
395 | if (!icalrestriction_check(message)) { | ||
396 | setException(new ErrorFormat(ErrorFormat::Restriction, | ||
397 | Scheduler::translatedMethodName(method) + ": " + | ||
398 | mImpl->extractErrorProperty(c))); | ||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | icalcomponent *calendarComponent = mImpl->createCalendarComponent(cal); | ||
403 | |||
404 | Incidence *existingIncidence = cal->event(incidence->uid()); | ||
405 | if (existingIncidence) { | ||
406 | // TODO: check, if cast is required, or if it can be done by virtual funcs. | ||
407 | if (existingIncidence->type() == "Todo") { | ||
408 | Todo *todo = static_cast<Todo *>(existingIncidence); | ||
409 | icalcomponent_add_component(calendarComponent, | ||
410 | mImpl->writeTodo(todo)); | ||
411 | } | ||
412 | if (existingIncidence->type() == "Event") { | ||
413 | Event *event = static_cast<Event *>(existingIncidence); | ||
414 | icalcomponent_add_component(calendarComponent, | ||
415 | mImpl->writeEvent(event)); | ||
416 | } | ||
417 | } else { | ||
418 | calendarComponent = 0; | ||
419 | } | ||
420 | |||
421 | |||
422 | icalclass result = icalclassify(message,calendarComponent,(char *)""); | ||
423 | |||
424 | |||
425 | ScheduleMessage::Status status; | ||
426 | |||
427 | switch (result) { | ||
428 | case ICAL_PUBLISH_NEW_CLASS: | ||
429 | status = ScheduleMessage::PublishNew; | ||
430 | break; | ||
431 | case ICAL_OBSOLETE_CLASS: | ||
432 | status = ScheduleMessage::Obsolete; | ||
433 | break; | ||
434 | case ICAL_REQUEST_NEW_CLASS: | ||
435 | status = ScheduleMessage::RequestNew; | ||
436 | break; | ||
437 | case ICAL_REQUEST_UPDATE_CLASS: | ||
438 | status = ScheduleMessage::RequestUpdate; | ||
439 | break; | ||
440 | case ICAL_UNKNOWN_CLASS: | ||
441 | default: | ||
442 | status = ScheduleMessage::Unknown; | ||
443 | break; | ||
444 | } | ||
445 | |||
446 | return new ScheduleMessage(incidence,method,status); | ||
447 | } | ||
448 | |||
449 | void ICalFormat::setTimeZone( const QString &id, bool utc ) | ||
450 | { | ||
451 | |||
452 | |||
453 | mTimeZoneId = id; | ||
454 | mUtc = utc; | ||
455 | |||
456 | tzOffsetMin = KGlobal::locale()->timezoneOffset(mTimeZoneId); | ||
457 | |||
458 | //qDebug("ICalFormat::setTimeZoneOffset %s %d ",mTimeZoneId.latin1(), tzOffsetMin); | ||
459 | } | ||
460 | |||
461 | QString ICalFormat::timeZoneId() const | ||
462 | { | ||
463 | return mTimeZoneId; | ||
464 | } | ||
465 | |||
466 | bool ICalFormat::utc() const | ||
467 | { | ||
468 | return mUtc; | ||
469 | } | ||
470 | int ICalFormat::timeOffset() | ||
471 | { | ||
472 | return tzOffsetMin; | ||
473 | } | ||
474 | const char *ICalFormat::tzString() | ||
475 | { | ||
476 | const char* ret = (const char* ) mTzString; | ||
477 | return ret; | ||
478 | } | ||