-rw-r--r-- | libkcal/vcalformat.cpp | 1678 |
1 files changed, 1678 insertions, 0 deletions
diff --git a/libkcal/vcalformat.cpp b/libkcal/vcalformat.cpp new file mode 100644 index 0000000..59030d5 --- a/dev/null +++ b/libkcal/vcalformat.cpp | |||
@@ -0,0 +1,1678 @@ | |||
1 | /* | ||
2 | This file is part of libkcal. | ||
3 | Copyright (c) 1998 Preston Brwon | ||
4 | Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> | ||
5 | |||
6 | This library is free software; you can redistribute it and/or | ||
7 | modify it under the terms of the GNU Library General Public | ||
8 | License as published by the Free Software Foundation; either | ||
9 | version 2 of the License, or (at your option) any later version. | ||
10 | |||
11 | This library is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | Library General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU Library General Public License | ||
17 | along with this library; see the file COPYING.LIB. If not, write to | ||
18 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
19 | Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <qapplication.h> | ||
23 | #include <qdatetime.h> | ||
24 | #include <qstring.h> | ||
25 | #include <qptrlist.h> | ||
26 | #include <qregexp.h> | ||
27 | #include <qclipboard.h> | ||
28 | #include <qdialog.h> | ||
29 | #include <qfile.h> | ||
30 | |||
31 | #include <kdebug.h> | ||
32 | #include <kmessagebox.h> | ||
33 | #include <kiconloader.h> | ||
34 | #include <klocale.h> | ||
35 | |||
36 | #include "vcc.h" | ||
37 | #include "vobject.h" | ||
38 | |||
39 | #include "vcaldrag.h" | ||
40 | #include "calendar.h" | ||
41 | |||
42 | #include "vcalformat.h" | ||
43 | |||
44 | using namespace KCal; | ||
45 | |||
46 | VCalFormat::VCalFormat() | ||
47 | { | ||
48 | } | ||
49 | |||
50 | VCalFormat::~VCalFormat() | ||
51 | { | ||
52 | } | ||
53 | |||
54 | bool VCalFormat::load(Calendar *calendar, const QString &fileName) | ||
55 | { | ||
56 | mCalendar = calendar; | ||
57 | |||
58 | clearException(); | ||
59 | |||
60 | kdDebug(5800) << "VCalFormat::load() " << fileName << endl; | ||
61 | |||
62 | VObject *vcal = 0; | ||
63 | |||
64 | // this is not necessarily only 1 vcal. Could be many vcals, or include | ||
65 | // a vcard... | ||
66 | vcal = Parse_MIME_FromFileName(const_cast<char *>(QFile::encodeName(fileName).data())); | ||
67 | |||
68 | if (!vcal) { | ||
69 | setException(new ErrorFormat(ErrorFormat::CalVersionUnknown)); | ||
70 | return FALSE; | ||
71 | } | ||
72 | |||
73 | // any other top-level calendar stuff should be added/initialized here | ||
74 | |||
75 | // put all vobjects into their proper places | ||
76 | populate(vcal); | ||
77 | |||
78 | // clean up from vcal API stuff | ||
79 | cleanVObjects(vcal); | ||
80 | cleanStrTbl(); | ||
81 | |||
82 | return true; | ||
83 | } | ||
84 | |||
85 | |||
86 | bool VCalFormat::save(Calendar *calendar, const QString &fileName) | ||
87 | { | ||
88 | mCalendar = calendar; | ||
89 | |||
90 | QString tmpStr; | ||
91 | VObject *vcal, *vo; | ||
92 | |||
93 | kdDebug(5800) << "VCalFormat::save(): " << fileName << endl; | ||
94 | |||
95 | vcal = newVObject(VCCalProp); | ||
96 | |||
97 | // addPropValue(vcal,VCLocationProp, "0.0"); | ||
98 | addPropValue(vcal,VCProdIdProp, productId()); | ||
99 | tmpStr = mCalendar->getTimeZoneStr(); | ||
100 | //qDebug("mCalendar->getTimeZoneStr() %s",tmpStr.latin1() ); | ||
101 | addPropValue(vcal,VCTimeZoneProp, tmpStr.local8Bit()); | ||
102 | addPropValue(vcal,VCVersionProp, _VCAL_VERSION); | ||
103 | |||
104 | // TODO STUFF | ||
105 | QPtrList<Todo> todoList = mCalendar->rawTodos(); | ||
106 | QPtrListIterator<Todo> qlt(todoList); | ||
107 | for (; qlt.current(); ++qlt) { | ||
108 | vo = eventToVTodo(qlt.current()); | ||
109 | addVObjectProp(vcal, vo); | ||
110 | } | ||
111 | |||
112 | // EVENT STUFF | ||
113 | QPtrList<Event> events = mCalendar->rawEvents(); | ||
114 | Event *ev; | ||
115 | for(ev=events.first();ev;ev=events.next()) { | ||
116 | vo = eventToVEvent(ev); | ||
117 | addVObjectProp(vcal, vo); | ||
118 | } | ||
119 | |||
120 | writeVObjectToFile(QFile::encodeName(fileName).data() ,vcal); | ||
121 | cleanVObjects(vcal); | ||
122 | cleanStrTbl(); | ||
123 | |||
124 | if (QFile::exists(fileName)) { | ||
125 | kdDebug(5800) << "No error" << endl; | ||
126 | return true; | ||
127 | } else { | ||
128 | kdDebug(5800) << "Error" << endl; | ||
129 | return false; // error | ||
130 | } | ||
131 | } | ||
132 | |||
133 | bool VCalFormat::fromString( Calendar *calendar, const QString &text ) | ||
134 | { | ||
135 | // TODO: Factor out VCalFormat::fromString() | ||
136 | |||
137 | QCString data = text.utf8(); | ||
138 | |||
139 | if ( !data.size() ) return false; | ||
140 | |||
141 | VObject *vcal = Parse_MIME( data.data(), data.size()); | ||
142 | if ( !vcal ) return false; | ||
143 | |||
144 | VObjectIterator i; | ||
145 | VObject *curvo; | ||
146 | initPropIterator( &i, vcal ); | ||
147 | |||
148 | // we only take the first object. TODO: parse all incidences. | ||
149 | do { | ||
150 | curvo = nextVObject( &i ); | ||
151 | } while ( strcmp( vObjectName( curvo ), VCEventProp ) && | ||
152 | strcmp( vObjectName( curvo ), VCTodoProp ) ); | ||
153 | |||
154 | if ( strcmp( vObjectName( curvo ), VCEventProp ) == 0 ) { | ||
155 | Event *event = VEventToEvent( curvo ); | ||
156 | calendar->addEvent( event ); | ||
157 | } else { | ||
158 | kdDebug(5800) << "VCalFormat::fromString(): Unknown object type." << endl; | ||
159 | deleteVObject( vcal ); | ||
160 | return false; | ||
161 | } | ||
162 | |||
163 | deleteVObject( vcal ); | ||
164 | |||
165 | return true; | ||
166 | } | ||
167 | |||
168 | QString VCalFormat::toString( Calendar *calendar ) | ||
169 | { | ||
170 | // TODO: Factor out VCalFormat::asString() | ||
171 | |||
172 | VObject *vcal = newVObject(VCCalProp); | ||
173 | |||
174 | addPropValue( vcal, VCProdIdProp, CalFormat::productId() ); | ||
175 | QString tmpStr = mCalendar->getTimeZoneStr(); | ||
176 | addPropValue( vcal, VCTimeZoneProp, tmpStr.local8Bit() ); | ||
177 | addPropValue( vcal, VCVersionProp, _VCAL_VERSION ); | ||
178 | |||
179 | // TODO: Use all data. | ||
180 | QPtrList<Event> events = calendar->events(); | ||
181 | Event *event = events.first(); | ||
182 | if ( !event ) return QString::null; | ||
183 | |||
184 | VObject *vevent = eventToVEvent( event ); | ||
185 | |||
186 | addVObjectProp( vcal, vevent ); | ||
187 | |||
188 | char *buf = writeMemVObject( 0, 0, vcal ); | ||
189 | |||
190 | QString result( buf ); | ||
191 | |||
192 | cleanVObject( vcal ); | ||
193 | |||
194 | return result; | ||
195 | } | ||
196 | |||
197 | VObject *VCalFormat::eventToVTodo(const Todo *anEvent) | ||
198 | { | ||
199 | VObject *vtodo; | ||
200 | QString tmpStr; | ||
201 | QStringList tmpStrList; | ||
202 | |||
203 | vtodo = newVObject(VCTodoProp); | ||
204 | |||
205 | // due date | ||
206 | if (anEvent->hasDueDate()) { | ||
207 | tmpStr = qDateTimeToISO(anEvent->dtDue(), | ||
208 | !anEvent->doesFloat()); | ||
209 | addPropValue(vtodo, VCDueProp, tmpStr.local8Bit()); | ||
210 | } | ||
211 | |||
212 | // start date | ||
213 | if (anEvent->hasStartDate()) { | ||
214 | tmpStr = qDateTimeToISO(anEvent->dtStart(), | ||
215 | !anEvent->doesFloat()); | ||
216 | addPropValue(vtodo, VCDTstartProp, tmpStr.local8Bit()); | ||
217 | } | ||
218 | |||
219 | // creation date | ||
220 | tmpStr = qDateTimeToISO(anEvent->created()); | ||
221 | addPropValue(vtodo, VCDCreatedProp, tmpStr.local8Bit()); | ||
222 | |||
223 | // unique id | ||
224 | addPropValue(vtodo, VCUniqueStringProp, | ||
225 | anEvent->uid().local8Bit()); | ||
226 | |||
227 | // revision | ||
228 | tmpStr.sprintf("%i", anEvent->revision()); | ||
229 | addPropValue(vtodo, VCSequenceProp, tmpStr.local8Bit()); | ||
230 | |||
231 | // last modification date | ||
232 | tmpStr = qDateTimeToISO(anEvent->lastModified()); | ||
233 | addPropValue(vtodo, VCLastModifiedProp, tmpStr.local8Bit()); | ||
234 | |||
235 | // organizer stuff | ||
236 | tmpStr = "MAILTO:" + anEvent->organizer(); | ||
237 | addPropValue(vtodo, ICOrganizerProp, tmpStr.local8Bit()); | ||
238 | |||
239 | // attendees | ||
240 | if (anEvent->attendeeCount() != 0) { | ||
241 | QPtrList<Attendee> al = anEvent->attendees(); | ||
242 | QPtrListIterator<Attendee> ai(al); | ||
243 | Attendee *curAttendee; | ||
244 | |||
245 | for (; ai.current(); ++ai) { | ||
246 | curAttendee = ai.current(); | ||
247 | if (!curAttendee->email().isEmpty() && | ||
248 | !curAttendee->name().isEmpty()) | ||
249 | tmpStr = "MAILTO:" + curAttendee->name() + " <" + | ||
250 | curAttendee->email() + ">"; | ||
251 | else if (curAttendee->name().isEmpty()) | ||
252 | tmpStr = "MAILTO: " + curAttendee->email(); | ||
253 | else if (curAttendee->email().isEmpty()) | ||
254 | tmpStr = "MAILTO: " + curAttendee->name(); | ||
255 | else if (curAttendee->name().isEmpty() && | ||
256 | curAttendee->email().isEmpty()) | ||
257 | kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl; | ||
258 | VObject *aProp = addPropValue(vtodo, VCAttendeeProp, tmpStr.local8Bit()); | ||
259 | addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE"); | ||
260 | addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status())); | ||
261 | } | ||
262 | } | ||
263 | |||
264 | // description BL: | ||
265 | if (!anEvent->description().isEmpty()) { | ||
266 | VObject *d = addPropValue(vtodo, VCDescriptionProp, | ||
267 | anEvent->description().local8Bit()); | ||
268 | if (anEvent->description().find('\n') != -1) | ||
269 | addProp(d, VCQuotedPrintableProp); | ||
270 | } | ||
271 | |||
272 | // summary | ||
273 | if (!anEvent->summary().isEmpty()) | ||
274 | addPropValue(vtodo, VCSummaryProp, anEvent->summary().local8Bit()); | ||
275 | |||
276 | if (!anEvent->location().isEmpty()) | ||
277 | addPropValue(vtodo, VCLocationProp, anEvent->location().local8Bit()); | ||
278 | |||
279 | // completed | ||
280 | // status | ||
281 | // backward compatibility, KOrganizer used to interpret only these two values | ||
282 | addPropValue(vtodo, VCStatusProp, anEvent->isCompleted() ? "COMPLETED" : | ||
283 | "NEEDS_ACTION"); | ||
284 | // completion date | ||
285 | if (anEvent->hasCompletedDate()) { | ||
286 | tmpStr = qDateTimeToISO(anEvent->completed()); | ||
287 | addPropValue(vtodo, VCCompletedProp, tmpStr.local8Bit()); | ||
288 | } | ||
289 | |||
290 | // priority | ||
291 | tmpStr.sprintf("%i",anEvent->priority()); | ||
292 | addPropValue(vtodo, VCPriorityProp, tmpStr.local8Bit()); | ||
293 | |||
294 | // related event | ||
295 | if (anEvent->relatedTo()) { | ||
296 | addPropValue(vtodo, VCRelatedToProp, | ||
297 | anEvent->relatedTo()->uid().local8Bit()); | ||
298 | } | ||
299 | |||
300 | // categories | ||
301 | tmpStrList = anEvent->categories(); | ||
302 | tmpStr = ""; | ||
303 | QString catStr; | ||
304 | for ( QStringList::Iterator it = tmpStrList.begin(); | ||
305 | it != tmpStrList.end(); | ||
306 | ++it ) { | ||
307 | catStr = *it; | ||
308 | if (catStr[0] == ' ') | ||
309 | tmpStr += catStr.mid(1); | ||
310 | else | ||
311 | tmpStr += catStr; | ||
312 | // this must be a ';' character as the vCalendar specification requires! | ||
313 | // vcc.y has been hacked to translate the ';' to a ',' when the vcal is | ||
314 | // read in. | ||
315 | tmpStr += ";"; | ||
316 | } | ||
317 | if (!tmpStr.isEmpty()) { | ||
318 | tmpStr.truncate(tmpStr.length()-1); | ||
319 | addPropValue(vtodo, VCCategoriesProp, tmpStr.local8Bit()); | ||
320 | } | ||
321 | |||
322 | // alarm stuff | ||
323 | kdDebug(5800) << "vcalformat::eventToVTodo was called" << endl; | ||
324 | QPtrList<Alarm> alarms = anEvent->alarms(); | ||
325 | Alarm* alarm; | ||
326 | for (alarm = alarms.first(); alarm; alarm = alarms.next()) { | ||
327 | if (alarm->enabled()) { | ||
328 | VObject *a = addProp(vtodo, VCDAlarmProp); | ||
329 | tmpStr = qDateTimeToISO(alarm->time()); | ||
330 | addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); | ||
331 | addPropValue(a, VCRepeatCountProp, "1"); | ||
332 | addPropValue(a, VCDisplayStringProp, "beep!"); | ||
333 | if (alarm->type() == Alarm::Audio) { | ||
334 | a = addProp(vtodo, VCAAlarmProp); | ||
335 | addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); | ||
336 | addPropValue(a, VCRepeatCountProp, "1"); | ||
337 | addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile())); | ||
338 | } | ||
339 | else if (alarm->type() == Alarm::Procedure) { | ||
340 | a = addProp(vtodo, VCPAlarmProp); | ||
341 | addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); | ||
342 | addPropValue(a, VCRepeatCountProp, "1"); | ||
343 | addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile())); | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | if (anEvent->pilotId()) { | ||
349 | // pilot sync stuff | ||
350 | tmpStr.sprintf("%i",anEvent->pilotId()); | ||
351 | addPropValue(vtodo, KPilotIdProp, tmpStr.local8Bit()); | ||
352 | tmpStr.sprintf("%i",anEvent->syncStatus()); | ||
353 | addPropValue(vtodo, KPilotStatusProp, tmpStr.local8Bit()); | ||
354 | } | ||
355 | |||
356 | return vtodo; | ||
357 | } | ||
358 | |||
359 | VObject* VCalFormat::eventToVEvent(const Event *anEvent) | ||
360 | { | ||
361 | VObject *vevent; | ||
362 | QString tmpStr; | ||
363 | QStringList tmpStrList; | ||
364 | |||
365 | vevent = newVObject(VCEventProp); | ||
366 | |||
367 | // start and end time | ||
368 | tmpStr = qDateTimeToISO(anEvent->dtStart(), | ||
369 | !anEvent->doesFloat()); | ||
370 | addPropValue(vevent, VCDTstartProp, tmpStr.local8Bit()); | ||
371 | |||
372 | // events that have time associated but take up no time should | ||
373 | // not have both DTSTART and DTEND. | ||
374 | if (anEvent->dtStart() != anEvent->dtEnd()) { | ||
375 | tmpStr = qDateTimeToISO(anEvent->dtEnd(), | ||
376 | !anEvent->doesFloat()); | ||
377 | addPropValue(vevent, VCDTendProp, tmpStr.local8Bit()); | ||
378 | } | ||
379 | |||
380 | // creation date | ||
381 | tmpStr = qDateTimeToISO(anEvent->created()); | ||
382 | addPropValue(vevent, VCDCreatedProp, tmpStr.local8Bit()); | ||
383 | |||
384 | // unique id | ||
385 | addPropValue(vevent, VCUniqueStringProp, | ||
386 | anEvent->uid().local8Bit()); | ||
387 | |||
388 | // revision | ||
389 | tmpStr.sprintf("%i", anEvent->revision()); | ||
390 | addPropValue(vevent, VCSequenceProp, tmpStr.local8Bit()); | ||
391 | |||
392 | // last modification date | ||
393 | tmpStr = qDateTimeToISO(anEvent->lastModified()); | ||
394 | addPropValue(vevent, VCLastModifiedProp, tmpStr.local8Bit()); | ||
395 | |||
396 | // attendee and organizer stuff | ||
397 | tmpStr = "MAILTO:" + anEvent->organizer(); | ||
398 | addPropValue(vevent, ICOrganizerProp, tmpStr.local8Bit()); | ||
399 | |||
400 | if (anEvent->attendeeCount() != 0) { | ||
401 | QPtrList<Attendee> al = anEvent->attendees(); | ||
402 | QPtrListIterator<Attendee> ai(al); | ||
403 | Attendee *curAttendee; | ||
404 | |||
405 | // TODO: Put this functionality into Attendee class | ||
406 | for (; ai.current(); ++ai) { | ||
407 | curAttendee = ai.current(); | ||
408 | if (!curAttendee->email().isEmpty() && | ||
409 | !curAttendee->name().isEmpty()) | ||
410 | tmpStr = "MAILTO:" + curAttendee->name() + " <" + | ||
411 | curAttendee->email() + ">"; | ||
412 | else if (curAttendee->name().isEmpty()) | ||
413 | tmpStr = "MAILTO: " + curAttendee->email(); | ||
414 | else if (curAttendee->email().isEmpty()) | ||
415 | tmpStr = "MAILTO: " + curAttendee->name(); | ||
416 | else if (curAttendee->name().isEmpty() && | ||
417 | curAttendee->email().isEmpty()) | ||
418 | kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl; | ||
419 | VObject *aProp = addPropValue(vevent, VCAttendeeProp, tmpStr.local8Bit()); | ||
420 | addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE");; | ||
421 | addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status())); | ||
422 | } | ||
423 | } | ||
424 | |||
425 | // recurrence rule stuff | ||
426 | if (anEvent->recurrence()->doesRecur()) { | ||
427 | // some more variables | ||
428 | QPtrList<Recurrence::rMonthPos> tmpPositions; | ||
429 | QPtrList<int> tmpDays; | ||
430 | int *tmpDay; | ||
431 | Recurrence::rMonthPos *tmpPos; | ||
432 | QString tmpStr2; | ||
433 | int i; | ||
434 | |||
435 | switch(anEvent->recurrence()->doesRecur()) { | ||
436 | case Recurrence::rDaily: | ||
437 | tmpStr.sprintf("D%i ",anEvent->recurrence()->frequency()); | ||
438 | // if (anEvent->rDuration > 0) | ||
439 | //tmpStr += "#"; | ||
440 | break; | ||
441 | case Recurrence::rWeekly: | ||
442 | tmpStr.sprintf("W%i ",anEvent->recurrence()->frequency()); | ||
443 | for (i = 0; i < 7; i++) { | ||
444 | if (anEvent->recurrence()->days().testBit(i)) | ||
445 | tmpStr += dayFromNum(i); | ||
446 | } | ||
447 | break; | ||
448 | case Recurrence::rMonthlyPos: | ||
449 | tmpStr.sprintf("MP%i ", anEvent->recurrence()->frequency()); | ||
450 | // write out all rMonthPos's | ||
451 | tmpPositions = anEvent->recurrence()->monthPositions(); | ||
452 | for (tmpPos = tmpPositions.first(); | ||
453 | tmpPos; | ||
454 | tmpPos = tmpPositions.next()) { | ||
455 | |||
456 | tmpStr2.sprintf("%i", tmpPos->rPos); | ||
457 | if (tmpPos->negative) | ||
458 | tmpStr2 += "- "; | ||
459 | else | ||
460 | tmpStr2 += "+ "; | ||
461 | tmpStr += tmpStr2; | ||
462 | for (i = 0; i < 7; i++) { | ||
463 | if (tmpPos->rDays.testBit(i)) | ||
464 | tmpStr += dayFromNum(i); | ||
465 | } | ||
466 | } // loop for all rMonthPos's | ||
467 | break; | ||
468 | case Recurrence::rMonthlyDay: | ||
469 | tmpStr.sprintf("MD%i ", anEvent->recurrence()->frequency()); | ||
470 | // write out all rMonthDays; | ||
471 | tmpDays = anEvent->recurrence()->monthDays(); | ||
472 | for (tmpDay = tmpDays.first(); | ||
473 | tmpDay; | ||
474 | tmpDay = tmpDays.next()) { | ||
475 | tmpStr2.sprintf("%i ", *tmpDay); | ||
476 | tmpStr += tmpStr2; | ||
477 | } | ||
478 | break; | ||
479 | case Recurrence::rYearlyMonth: | ||
480 | tmpStr.sprintf("YM%i ", anEvent->recurrence()->frequency()); | ||
481 | // write out all the rYearNums; | ||
482 | tmpDays = anEvent->recurrence()->yearNums(); | ||
483 | for (tmpDay = tmpDays.first(); | ||
484 | tmpDay; | ||
485 | tmpDay = tmpDays.next()) { | ||
486 | tmpStr2.sprintf("%i ", *tmpDay); | ||
487 | tmpStr += tmpStr2; | ||
488 | } | ||
489 | break; | ||
490 | case Recurrence::rYearlyDay: | ||
491 | tmpStr.sprintf("YD%i ", anEvent->recurrence()->frequency()); | ||
492 | // write out all the rYearNums; | ||
493 | tmpDays = anEvent->recurrence()->yearNums(); | ||
494 | for (tmpDay = tmpDays.first(); | ||
495 | tmpDay; | ||
496 | tmpDay = tmpDays.next()) { | ||
497 | tmpStr2.sprintf("%i ", *tmpDay); | ||
498 | tmpStr += tmpStr2; | ||
499 | } | ||
500 | break; | ||
501 | default: | ||
502 | kdDebug(5800) << "ERROR, it should never get here in eventToVEvent!" << endl; | ||
503 | break; | ||
504 | } // switch | ||
505 | |||
506 | if (anEvent->recurrence()->duration() > 0) { | ||
507 | tmpStr2.sprintf("#%i",anEvent->recurrence()->duration()); | ||
508 | tmpStr += tmpStr2; | ||
509 | } else if (anEvent->recurrence()->duration() == -1) { | ||
510 | tmpStr += "#0"; // defined as repeat forever | ||
511 | } else { | ||
512 | tmpStr += qDateTimeToISO(anEvent->recurrence()->endDate(), FALSE); | ||
513 | } | ||
514 | addPropValue(vevent,VCRRuleProp, tmpStr.local8Bit()); | ||
515 | |||
516 | } // event repeats | ||
517 | |||
518 | // exceptions to recurrence | ||
519 | DateList dateList = anEvent->exDates(); | ||
520 | DateList::ConstIterator it; | ||
521 | QString tmpStr2; | ||
522 | |||
523 | for (it = dateList.begin(); it != dateList.end(); ++it) { | ||
524 | tmpStr = qDateToISO(*it) + ";"; | ||
525 | tmpStr2 += tmpStr; | ||
526 | } | ||
527 | if (!tmpStr2.isEmpty()) { | ||
528 | tmpStr2.truncate(tmpStr2.length()-1); | ||
529 | addPropValue(vevent, VCExDateProp, tmpStr2.local8Bit()); | ||
530 | } | ||
531 | |||
532 | // description | ||
533 | if (!anEvent->description().isEmpty()) { | ||
534 | VObject *d = addPropValue(vevent, VCDescriptionProp, | ||
535 | anEvent->description().local8Bit()); | ||
536 | if (anEvent->description().find('\n') != -1) | ||
537 | addProp(d, VCQuotedPrintableProp); | ||
538 | } | ||
539 | |||
540 | // summary | ||
541 | if (!anEvent->summary().isEmpty()) | ||
542 | addPropValue(vevent, VCSummaryProp, anEvent->summary().local8Bit()); | ||
543 | |||
544 | if (!anEvent->location().isEmpty()) | ||
545 | addPropValue(vevent, VCLocationProp, anEvent->location().local8Bit()); | ||
546 | |||
547 | // status | ||
548 | // TODO: define Event status | ||
549 | // addPropValue(vevent, VCStatusProp, anEvent->statusStr().local8Bit()); | ||
550 | |||
551 | // secrecy | ||
552 | const char *text = 0; | ||
553 | switch (anEvent->secrecy()) { | ||
554 | case Incidence::SecrecyPublic: | ||
555 | text = "PUBLIC"; | ||
556 | break; | ||
557 | case Incidence::SecrecyPrivate: | ||
558 | text = "PRIVATE"; | ||
559 | break; | ||
560 | case Incidence::SecrecyConfidential: | ||
561 | text = "CONFIDENTIAL"; | ||
562 | break; | ||
563 | } | ||
564 | if (text) { | ||
565 | addPropValue(vevent, VCClassProp, text); | ||
566 | } | ||
567 | |||
568 | // categories | ||
569 | tmpStrList = anEvent->categories(); | ||
570 | tmpStr = ""; | ||
571 | QString catStr; | ||
572 | for ( QStringList::Iterator it = tmpStrList.begin(); | ||
573 | it != tmpStrList.end(); | ||
574 | ++it ) { | ||
575 | catStr = *it; | ||
576 | if (catStr[0] == ' ') | ||
577 | tmpStr += catStr.mid(1); | ||
578 | else | ||
579 | tmpStr += catStr; | ||
580 | // this must be a ';' character as the vCalendar specification requires! | ||
581 | // vcc.y has been hacked to translate the ';' to a ',' when the vcal is | ||
582 | // read in. | ||
583 | tmpStr += ";"; | ||
584 | } | ||
585 | if (!tmpStr.isEmpty()) { | ||
586 | tmpStr.truncate(tmpStr.length()-1); | ||
587 | addPropValue(vevent, VCCategoriesProp, tmpStr.local8Bit()); | ||
588 | } | ||
589 | |||
590 | // attachments | ||
591 | // TODO: handle binary attachments! | ||
592 | QPtrList<Attachment> attachments = anEvent->attachments(); | ||
593 | for ( Attachment *at = attachments.first(); at; at = attachments.next() ) | ||
594 | addPropValue(vevent, VCAttachProp, at->uri().local8Bit()); | ||
595 | |||
596 | // resources | ||
597 | tmpStrList = anEvent->resources(); | ||
598 | tmpStr = tmpStrList.join(";"); | ||
599 | if (!tmpStr.isEmpty()) | ||
600 | addPropValue(vevent, VCResourcesProp, tmpStr.local8Bit()); | ||
601 | |||
602 | // alarm stuff | ||
603 | QPtrList<Alarm> alarms = anEvent->alarms(); | ||
604 | Alarm* alarm; | ||
605 | for (alarm = alarms.first(); alarm; alarm = alarms.next()) { | ||
606 | if (alarm->enabled()) { | ||
607 | VObject *a = addProp(vevent, VCDAlarmProp); | ||
608 | tmpStr = qDateTimeToISO(alarm->time()); | ||
609 | addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); | ||
610 | addPropValue(a, VCRepeatCountProp, "1"); | ||
611 | addPropValue(a, VCDisplayStringProp, "beep!"); | ||
612 | if (alarm->type() == Alarm::Audio) { | ||
613 | a = addProp(vevent, VCAAlarmProp); | ||
614 | addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); | ||
615 | addPropValue(a, VCRepeatCountProp, "1"); | ||
616 | addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile())); | ||
617 | } | ||
618 | if (alarm->type() == Alarm::Procedure) { | ||
619 | a = addProp(vevent, VCPAlarmProp); | ||
620 | addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); | ||
621 | addPropValue(a, VCRepeatCountProp, "1"); | ||
622 | addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile())); | ||
623 | } | ||
624 | } | ||
625 | } | ||
626 | |||
627 | // priority | ||
628 | tmpStr.sprintf("%i",anEvent->priority()); | ||
629 | addPropValue(vevent, VCPriorityProp, tmpStr.local8Bit()); | ||
630 | |||
631 | // transparency | ||
632 | tmpStr.sprintf("%i",anEvent->transparency()); | ||
633 | addPropValue(vevent, VCTranspProp, tmpStr.local8Bit()); | ||
634 | |||
635 | // related event | ||
636 | if (anEvent->relatedTo()) { | ||
637 | addPropValue(vevent, VCRelatedToProp, | ||
638 | anEvent->relatedTo()->uid().local8Bit()); | ||
639 | } | ||
640 | |||
641 | if (anEvent->pilotId()) { | ||
642 | // pilot sync stuff | ||
643 | tmpStr.sprintf("%i",anEvent->pilotId()); | ||
644 | addPropValue(vevent, KPilotIdProp, tmpStr.local8Bit()); | ||
645 | tmpStr.sprintf("%i",anEvent->syncStatus()); | ||
646 | addPropValue(vevent, KPilotStatusProp, tmpStr.local8Bit()); | ||
647 | } | ||
648 | |||
649 | return vevent; | ||
650 | } | ||
651 | |||
652 | Todo *VCalFormat::VTodoToEvent(VObject *vtodo) | ||
653 | { | ||
654 | VObject *vo; | ||
655 | VObjectIterator voi; | ||
656 | char *s; | ||
657 | |||
658 | Todo *anEvent = new Todo; | ||
659 | |||
660 | // creation date | ||
661 | if ((vo = isAPropertyOf(vtodo, VCDCreatedProp)) != 0) { | ||
662 | anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
663 | deleteStr(s); | ||
664 | } | ||
665 | |||
666 | // unique id | ||
667 | vo = isAPropertyOf(vtodo, VCUniqueStringProp); | ||
668 | // while the UID property is preferred, it is not required. We'll use the | ||
669 | // default Event UID if none is given. | ||
670 | if (vo) { | ||
671 | anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo))); | ||
672 | deleteStr(s); | ||
673 | } | ||
674 | |||
675 | // last modification date | ||
676 | if ((vo = isAPropertyOf(vtodo, VCLastModifiedProp)) != 0) { | ||
677 | anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
678 | deleteStr(s); | ||
679 | } | ||
680 | else | ||
681 | anEvent->setLastModified(QDateTime(QDate::currentDate(), | ||
682 | QTime::currentTime())); | ||
683 | |||
684 | // organizer | ||
685 | // if our extension property for the event's ORGANIZER exists, add it. | ||
686 | if ((vo = isAPropertyOf(vtodo, ICOrganizerProp)) != 0) { | ||
687 | anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo))); | ||
688 | deleteStr(s); | ||
689 | } else { | ||
690 | anEvent->setOrganizer(mCalendar->getEmail()); | ||
691 | } | ||
692 | |||
693 | // attendees. | ||
694 | initPropIterator(&voi, vtodo); | ||
695 | while (moreIteration(&voi)) { | ||
696 | vo = nextVObject(&voi); | ||
697 | if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) { | ||
698 | Attendee *a; | ||
699 | VObject *vp; | ||
700 | s = fakeCString(vObjectUStringZValue(vo)); | ||
701 | QString tmpStr = QString::fromLocal8Bit(s); | ||
702 | deleteStr(s); | ||
703 | tmpStr = tmpStr.simplifyWhiteSpace(); | ||
704 | int emailPos1, emailPos2; | ||
705 | if ((emailPos1 = tmpStr.find('<')) > 0) { | ||
706 | // both email address and name | ||
707 | emailPos2 = tmpStr.findRev('>'); | ||
708 | a = new Attendee(tmpStr.left(emailPos1 - 1), | ||
709 | tmpStr.mid(emailPos1 + 1, | ||
710 | emailPos2 - (emailPos1 + 1))); | ||
711 | } else if (tmpStr.find('@') > 0) { | ||
712 | // just an email address | ||
713 | a = new Attendee(0, tmpStr); | ||
714 | } else { | ||
715 | // just a name | ||
716 | QString email = tmpStr.replace( QRegExp(" "), "." ); | ||
717 | a = new Attendee(tmpStr,email); | ||
718 | } | ||
719 | |||
720 | // is there an RSVP property? | ||
721 | if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0) | ||
722 | a->setRSVP(vObjectStringZValue(vp)); | ||
723 | // is there a status property? | ||
724 | if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0) | ||
725 | a->setStatus(readStatus(vObjectStringZValue(vp))); | ||
726 | // add the attendee | ||
727 | anEvent->addAttendee(a); | ||
728 | } | ||
729 | } | ||
730 | |||
731 | // description for todo | ||
732 | if ((vo = isAPropertyOf(vtodo, VCDescriptionProp)) != 0) { | ||
733 | s = fakeCString(vObjectUStringZValue(vo)); | ||
734 | anEvent->setDescription(QString::fromLocal8Bit(s)); | ||
735 | deleteStr(s); | ||
736 | } | ||
737 | |||
738 | // summary | ||
739 | if ((vo = isAPropertyOf(vtodo, VCSummaryProp))) { | ||
740 | s = fakeCString(vObjectUStringZValue(vo)); | ||
741 | anEvent->setSummary(QString::fromLocal8Bit(s)); | ||
742 | deleteStr(s); | ||
743 | } | ||
744 | if ((vo = isAPropertyOf(vtodo, VCLocationProp))) { | ||
745 | s = fakeCString(vObjectUStringZValue(vo)); | ||
746 | anEvent->setLocation(QString::fromLocal8Bit(s)); | ||
747 | deleteStr(s); | ||
748 | } | ||
749 | |||
750 | |||
751 | // completed | ||
752 | // was: status | ||
753 | if ((vo = isAPropertyOf(vtodo, VCStatusProp)) != 0) { | ||
754 | s = fakeCString(vObjectUStringZValue(vo)); | ||
755 | if (strcmp(s,"COMPLETED") == 0) { | ||
756 | anEvent->setCompleted(true); | ||
757 | } else { | ||
758 | anEvent->setCompleted(false); | ||
759 | } | ||
760 | deleteStr(s); | ||
761 | } | ||
762 | else | ||
763 | anEvent->setCompleted(false); | ||
764 | |||
765 | // completion date | ||
766 | if ((vo = isAPropertyOf(vtodo, VCCompletedProp)) != 0) { | ||
767 | anEvent->setCompleted(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
768 | deleteStr(s); | ||
769 | } | ||
770 | |||
771 | // priority | ||
772 | if ((vo = isAPropertyOf(vtodo, VCPriorityProp))) { | ||
773 | anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo)))); | ||
774 | deleteStr(s); | ||
775 | } | ||
776 | |||
777 | // due date | ||
778 | if ((vo = isAPropertyOf(vtodo, VCDueProp)) != 0) { | ||
779 | anEvent->setDtDue(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
780 | deleteStr(s); | ||
781 | anEvent->setHasDueDate(true); | ||
782 | } else { | ||
783 | anEvent->setHasDueDate(false); | ||
784 | } | ||
785 | |||
786 | // start time | ||
787 | if ((vo = isAPropertyOf(vtodo, VCDTstartProp)) != 0) { | ||
788 | anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
789 | // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl; | ||
790 | deleteStr(s); | ||
791 | anEvent->setHasStartDate(true); | ||
792 | } else { | ||
793 | anEvent->setHasStartDate(false); | ||
794 | } | ||
795 | |||
796 | /* alarm stuff */ | ||
797 | //kdDebug(5800) << "vcalformat::VTodoToEvent called" << endl; | ||
798 | if ((vo = isAPropertyOf(vtodo, VCDAlarmProp))) { | ||
799 | Alarm* alarm = anEvent->newAlarm(); | ||
800 | VObject *a; | ||
801 | if ((a = isAPropertyOf(vo, VCRunTimeProp))) { | ||
802 | alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a)))); | ||
803 | deleteStr(s); | ||
804 | } | ||
805 | alarm->setEnabled(true); | ||
806 | if ((vo = isAPropertyOf(vtodo, VCPAlarmProp))) { | ||
807 | if ((a = isAPropertyOf(vo, VCProcedureNameProp))) { | ||
808 | s = fakeCString(vObjectUStringZValue(a)); | ||
809 | alarm->setProcedureAlarm(QFile::decodeName(s)); | ||
810 | deleteStr(s); | ||
811 | } | ||
812 | } | ||
813 | if ((vo = isAPropertyOf(vtodo, VCAAlarmProp))) { | ||
814 | if ((a = isAPropertyOf(vo, VCAudioContentProp))) { | ||
815 | s = fakeCString(vObjectUStringZValue(a)); | ||
816 | alarm->setAudioAlarm(QFile::decodeName(s)); | ||
817 | deleteStr(s); | ||
818 | } | ||
819 | } | ||
820 | } | ||
821 | |||
822 | // related todo | ||
823 | if ((vo = isAPropertyOf(vtodo, VCRelatedToProp)) != 0) { | ||
824 | anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo))); | ||
825 | deleteStr(s); | ||
826 | mTodosRelate.append(anEvent); | ||
827 | } | ||
828 | |||
829 | // categories | ||
830 | QStringList tmpStrList; | ||
831 | int index1 = 0; | ||
832 | int index2 = 0; | ||
833 | if ((vo = isAPropertyOf(vtodo, VCCategoriesProp)) != 0) { | ||
834 | s = fakeCString(vObjectUStringZValue(vo)); | ||
835 | QString categories = QString::fromLocal8Bit(s); | ||
836 | deleteStr(s); | ||
837 | //const char* category; | ||
838 | QString category; | ||
839 | while ((index2 = categories.find(',', index1)) != -1) { | ||
840 | //category = (const char *) categories.mid(index1, (index2 - index1)); | ||
841 | category = categories.mid(index1, (index2 - index1)); | ||
842 | tmpStrList.append(category); | ||
843 | index1 = index2+1; | ||
844 | } | ||
845 | // get last category | ||
846 | category = categories.mid(index1, (categories.length()-index1)); | ||
847 | tmpStrList.append(category); | ||
848 | anEvent->setCategories(tmpStrList); | ||
849 | } | ||
850 | |||
851 | /* PILOT SYNC STUFF */ | ||
852 | if ((vo = isAPropertyOf(vtodo, KPilotIdProp))) { | ||
853 | anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo)))); | ||
854 | deleteStr(s); | ||
855 | } | ||
856 | else | ||
857 | anEvent->setPilotId(0); | ||
858 | |||
859 | if ((vo = isAPropertyOf(vtodo, KPilotStatusProp))) { | ||
860 | anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo)))); | ||
861 | deleteStr(s); | ||
862 | } | ||
863 | else | ||
864 | anEvent->setSyncStatus(Event::SYNCMOD); | ||
865 | |||
866 | return anEvent; | ||
867 | } | ||
868 | |||
869 | Event* VCalFormat::VEventToEvent(VObject *vevent) | ||
870 | { | ||
871 | VObject *vo; | ||
872 | VObjectIterator voi; | ||
873 | char *s; | ||
874 | |||
875 | Event *anEvent = new Event; | ||
876 | |||
877 | // creation date | ||
878 | if ((vo = isAPropertyOf(vevent, VCDCreatedProp)) != 0) { | ||
879 | anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
880 | deleteStr(s); | ||
881 | } | ||
882 | |||
883 | // unique id | ||
884 | vo = isAPropertyOf(vevent, VCUniqueStringProp); | ||
885 | // while the UID property is preferred, it is not required. We'll use the | ||
886 | // default Event UID if none is given. | ||
887 | if (vo) { | ||
888 | anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo))); | ||
889 | deleteStr(s); | ||
890 | } | ||
891 | |||
892 | // revision | ||
893 | // again NSCAL doesn't give us much to work with, so we improvise... | ||
894 | if ((vo = isAPropertyOf(vevent, VCSequenceProp)) != 0) { | ||
895 | anEvent->setRevision(atoi(s = fakeCString(vObjectUStringZValue(vo)))); | ||
896 | deleteStr(s); | ||
897 | } | ||
898 | else | ||
899 | anEvent->setRevision(0); | ||
900 | |||
901 | // last modification date | ||
902 | if ((vo = isAPropertyOf(vevent, VCLastModifiedProp)) != 0) { | ||
903 | anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
904 | deleteStr(s); | ||
905 | } | ||
906 | else | ||
907 | anEvent->setLastModified(QDateTime(QDate::currentDate(), | ||
908 | QTime::currentTime())); | ||
909 | |||
910 | // organizer | ||
911 | // if our extension property for the event's ORGANIZER exists, add it. | ||
912 | if ((vo = isAPropertyOf(vevent, ICOrganizerProp)) != 0) { | ||
913 | anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo))); | ||
914 | deleteStr(s); | ||
915 | } else { | ||
916 | anEvent->setOrganizer(mCalendar->getEmail()); | ||
917 | } | ||
918 | |||
919 | // deal with attendees. | ||
920 | initPropIterator(&voi, vevent); | ||
921 | while (moreIteration(&voi)) { | ||
922 | vo = nextVObject(&voi); | ||
923 | if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) { | ||
924 | Attendee *a; | ||
925 | VObject *vp; | ||
926 | s = fakeCString(vObjectUStringZValue(vo)); | ||
927 | QString tmpStr = QString::fromLocal8Bit(s); | ||
928 | deleteStr(s); | ||
929 | tmpStr = tmpStr.simplifyWhiteSpace(); | ||
930 | int emailPos1, emailPos2; | ||
931 | if ((emailPos1 = tmpStr.find('<')) > 0) { | ||
932 | // both email address and name | ||
933 | emailPos2 = tmpStr.findRev('>'); | ||
934 | a = new Attendee(tmpStr.left(emailPos1 - 1), | ||
935 | tmpStr.mid(emailPos1 + 1, | ||
936 | emailPos2 - (emailPos1 + 1))); | ||
937 | } else if (tmpStr.find('@') > 0) { | ||
938 | // just an email address | ||
939 | a = new Attendee(0, tmpStr); | ||
940 | } else { | ||
941 | // just a name | ||
942 | QString email = tmpStr.replace( QRegExp(" "), "." ); | ||
943 | a = new Attendee(tmpStr,email); | ||
944 | } | ||
945 | |||
946 | // is there an RSVP property? | ||
947 | if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0) | ||
948 | a->setRSVP(vObjectStringZValue(vp)); | ||
949 | // is there a status property? | ||
950 | if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0) | ||
951 | a->setStatus(readStatus(vObjectStringZValue(vp))); | ||
952 | // add the attendee | ||
953 | anEvent->addAttendee(a); | ||
954 | } | ||
955 | } | ||
956 | |||
957 | // This isn't strictly true. An event that doesn't have a start time | ||
958 | // or an end time doesn't "float", it has an anchor in time but it doesn't | ||
959 | // "take up" any time. | ||
960 | /*if ((isAPropertyOf(vevent, VCDTstartProp) == 0) || | ||
961 | (isAPropertyOf(vevent, VCDTendProp) == 0)) { | ||
962 | anEvent->setFloats(TRUE); | ||
963 | } else { | ||
964 | }*/ | ||
965 | |||
966 | anEvent->setFloats(FALSE); | ||
967 | |||
968 | // start time | ||
969 | if ((vo = isAPropertyOf(vevent, VCDTstartProp)) != 0) { | ||
970 | anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
971 | // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl; | ||
972 | deleteStr(s); | ||
973 | if (anEvent->dtStart().time().isNull()) | ||
974 | anEvent->setFloats(TRUE); | ||
975 | } | ||
976 | |||
977 | // stop time | ||
978 | if ((vo = isAPropertyOf(vevent, VCDTendProp)) != 0) { | ||
979 | anEvent->setDtEnd(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); | ||
980 | deleteStr(s); | ||
981 | if (anEvent->dtEnd().time().isNull()) | ||
982 | anEvent->setFloats(TRUE); | ||
983 | } | ||
984 | |||
985 | // at this point, there should be at least a start or end time. | ||
986 | // fix up for events that take up no time but have a time associated | ||
987 | if (!(vo = isAPropertyOf(vevent, VCDTstartProp))) | ||
988 | anEvent->setDtStart(anEvent->dtEnd()); | ||
989 | if (!(vo = isAPropertyOf(vevent, VCDTendProp))) | ||
990 | anEvent->setDtEnd(anEvent->dtStart()); | ||
991 | |||
992 | /////////////////////////////////////////////////////////////////////////// | ||
993 | |||
994 | // repeat stuff | ||
995 | if ((vo = isAPropertyOf(vevent, VCRRuleProp)) != 0) { | ||
996 | QString tmpStr = (s = fakeCString(vObjectUStringZValue(vo))); | ||
997 | deleteStr(s); | ||
998 | tmpStr.simplifyWhiteSpace(); | ||
999 | tmpStr = tmpStr.upper(); | ||
1000 | |||
1001 | /********************************* DAILY ******************************/ | ||
1002 | if (tmpStr.left(1) == "D") { | ||
1003 | int index = tmpStr.find(' '); | ||
1004 | int rFreq = tmpStr.mid(1, (index-1)).toInt(); | ||
1005 | index = tmpStr.findRev(' ') + 1; // advance to last field | ||
1006 | if (tmpStr.mid(index,1) == "#") index++; | ||
1007 | if (tmpStr.find('T', index) != -1) { | ||
1008 | QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); | ||
1009 | anEvent->recurrence()->setDaily(rFreq, rEndDate); | ||
1010 | } else { | ||
1011 | int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); | ||
1012 | if (rDuration == 0) // VEvents set this to 0 forever, we use -1 | ||
1013 | anEvent->recurrence()->setDaily(rFreq, -1); | ||
1014 | else | ||
1015 | anEvent->recurrence()->setDaily(rFreq, rDuration); | ||
1016 | } | ||
1017 | } | ||
1018 | /********************************* WEEKLY ******************************/ | ||
1019 | else if (tmpStr.left(1) == "W") { | ||
1020 | int index = tmpStr.find(' '); | ||
1021 | int last = tmpStr.findRev(' ') + 1; | ||
1022 | int rFreq = tmpStr.mid(1, (index-1)).toInt(); | ||
1023 | index += 1; // advance to beginning of stuff after freq | ||
1024 | QBitArray qba(7); | ||
1025 | QString dayStr; | ||
1026 | if( index == last ) { | ||
1027 | // e.g. W1 #0 | ||
1028 | qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1); | ||
1029 | } | ||
1030 | else { | ||
1031 | // e.g. W1 SU #0 | ||
1032 | while (index < last) { | ||
1033 | dayStr = tmpStr.mid(index, 3); | ||
1034 | int dayNum = numFromDay(dayStr); | ||
1035 | qba.setBit(dayNum); | ||
1036 | index += 3; // advance to next day, or possibly "#" | ||
1037 | } | ||
1038 | } | ||
1039 | index = last; if (tmpStr.mid(index,1) == "#") index++; | ||
1040 | if (tmpStr.find('T', index) != -1) { | ||
1041 | QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); | ||
1042 | anEvent->recurrence()->setWeekly(rFreq, qba, rEndDate); | ||
1043 | } else { | ||
1044 | int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); | ||
1045 | if (rDuration == 0) | ||
1046 | anEvent->recurrence()->setWeekly(rFreq, qba, -1); | ||
1047 | else | ||
1048 | anEvent->recurrence()->setWeekly(rFreq, qba, rDuration); | ||
1049 | } | ||
1050 | } | ||
1051 | /**************************** MONTHLY-BY-POS ***************************/ | ||
1052 | else if (tmpStr.left(2) == "MP") { | ||
1053 | int index = tmpStr.find(' '); | ||
1054 | int last = tmpStr.findRev(' ') + 1; | ||
1055 | int rFreq = tmpStr.mid(2, (index-1)).toInt(); | ||
1056 | index += 1; // advance to beginning of stuff after freq | ||
1057 | QBitArray qba(7); | ||
1058 | short tmpPos; | ||
1059 | if( index == last ) { | ||
1060 | // e.g. MP1 #0 | ||
1061 | tmpPos = anEvent->dtStart().date().day()/7 + 1; | ||
1062 | if( tmpPos == 5 ) | ||
1063 | tmpPos = -1; | ||
1064 | qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1); | ||
1065 | anEvent->recurrence()->addMonthlyPos(tmpPos, qba); | ||
1066 | } | ||
1067 | else { | ||
1068 | // e.g. MP1 1+ SU #0 | ||
1069 | while (index < last) { | ||
1070 | tmpPos = tmpStr.mid(index,1).toShort(); | ||
1071 | index += 1; | ||
1072 | if (tmpStr.mid(index,1) == "-") | ||
1073 | // convert tmpPos to negative | ||
1074 | tmpPos = 0 - tmpPos; | ||
1075 | index += 2; // advance to day(s) | ||
1076 | while (numFromDay(tmpStr.mid(index,3)) >= 0) { | ||
1077 | int dayNum = numFromDay(tmpStr.mid(index,3)); | ||
1078 | qba.setBit(dayNum); | ||
1079 | index += 3; // advance to next day, or possibly pos or "#" | ||
1080 | } | ||
1081 | anEvent->recurrence()->addMonthlyPos(tmpPos, qba); | ||
1082 | qba.detach(); | ||
1083 | qba.fill(FALSE); // clear out | ||
1084 | } // while != "#" | ||
1085 | } | ||
1086 | index = last; if (tmpStr.mid(index,1) == "#") index++; | ||
1087 | if (tmpStr.find('T', index) != -1) { | ||
1088 | QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length() - | ||
1089 | index))).date(); | ||
1090 | anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rEndDate); | ||
1091 | } else { | ||
1092 | int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); | ||
1093 | if (rDuration == 0) | ||
1094 | anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, -1); | ||
1095 | else | ||
1096 | anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rDuration); | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | /**************************** MONTHLY-BY-DAY ***************************/ | ||
1101 | else if (tmpStr.left(2) == "MD") { | ||
1102 | int index = tmpStr.find(' '); | ||
1103 | int last = tmpStr.findRev(' ') + 1; | ||
1104 | int rFreq = tmpStr.mid(2, (index-1)).toInt(); | ||
1105 | index += 1; | ||
1106 | short tmpDay; | ||
1107 | if( index == last ) { | ||
1108 | // e.g. MD1 #0 | ||
1109 | tmpDay = anEvent->dtStart().date().day(); | ||
1110 | anEvent->recurrence()->addMonthlyDay(tmpDay); | ||
1111 | } | ||
1112 | else { | ||
1113 | // e.g. MD1 3 #0 | ||
1114 | while (index < last) { | ||
1115 | int index2 = tmpStr.find(' ', index); | ||
1116 | tmpDay = tmpStr.mid(index, (index2-index)).toShort(); | ||
1117 | index = index2-1; | ||
1118 | if (tmpStr.mid(index, 1) == "-") | ||
1119 | tmpDay = 0 - tmpDay; | ||
1120 | index += 2; // advance the index; | ||
1121 | anEvent->recurrence()->addMonthlyDay(tmpDay); | ||
1122 | } // while != # | ||
1123 | } | ||
1124 | index = last; if (tmpStr.mid(index,1) == "#") index++; | ||
1125 | if (tmpStr.find('T', index) != -1) { | ||
1126 | QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); | ||
1127 | anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rEndDate); | ||
1128 | } else { | ||
1129 | int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); | ||
1130 | if (rDuration == 0) | ||
1131 | anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, -1); | ||
1132 | else | ||
1133 | anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rDuration); | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | /*********************** YEARLY-BY-MONTH *******************************/ | ||
1138 | else if (tmpStr.left(2) == "YM") { | ||
1139 | int index = tmpStr.find(' '); | ||
1140 | int last = tmpStr.findRev(' ') + 1; | ||
1141 | int rFreq = tmpStr.mid(2, (index-1)).toInt(); | ||
1142 | index += 1; | ||
1143 | short tmpMonth; | ||
1144 | if( index == last ) { | ||
1145 | // e.g. YM1 #0 | ||
1146 | tmpMonth = anEvent->dtStart().date().month(); | ||
1147 | anEvent->recurrence()->addYearlyNum(tmpMonth); | ||
1148 | } | ||
1149 | else { | ||
1150 | // e.g. YM1 3 #0 | ||
1151 | while (index < last) { | ||
1152 | int index2 = tmpStr.find(' ', index); | ||
1153 | tmpMonth = tmpStr.mid(index, (index2-index)).toShort(); | ||
1154 | index = index2+1; | ||
1155 | anEvent->recurrence()->addYearlyNum(tmpMonth); | ||
1156 | } // while != # | ||
1157 | } | ||
1158 | index = last; if (tmpStr.mid(index,1) == "#") index++; | ||
1159 | if (tmpStr.find('T', index) != -1) { | ||
1160 | QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); | ||
1161 | anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rEndDate); | ||
1162 | } else { | ||
1163 | int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); | ||
1164 | if (rDuration == 0) | ||
1165 | anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, -1); | ||
1166 | else | ||
1167 | anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rDuration); | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | /*********************** YEARLY-BY-DAY *********************************/ | ||
1172 | else if (tmpStr.left(2) == "YD") { | ||
1173 | int index = tmpStr.find(' '); | ||
1174 | int last = tmpStr.findRev(' ') + 1; | ||
1175 | int rFreq = tmpStr.mid(2, (index-1)).toInt(); | ||
1176 | index += 1; | ||
1177 | short tmpDay; | ||
1178 | if( index == last ) { | ||
1179 | // e.g. YD1 #0 | ||
1180 | tmpDay = anEvent->dtStart().date().dayOfYear(); | ||
1181 | anEvent->recurrence()->addYearlyNum(tmpDay); | ||
1182 | } | ||
1183 | else { | ||
1184 | // e.g. YD1 123 #0 | ||
1185 | while (index < last) { | ||
1186 | int index2 = tmpStr.find(' ', index); | ||
1187 | tmpDay = tmpStr.mid(index, (index2-index)).toShort(); | ||
1188 | index = index2+1; | ||
1189 | anEvent->recurrence()->addYearlyNum(tmpDay); | ||
1190 | } // while != # | ||
1191 | } | ||
1192 | index = last; if (tmpStr.mid(index,1) == "#") index++; | ||
1193 | if (tmpStr.find('T', index) != -1) { | ||
1194 | QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); | ||
1195 | anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rEndDate); | ||
1196 | } else { | ||
1197 | int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); | ||
1198 | if (rDuration == 0) | ||
1199 | anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, -1); | ||
1200 | else | ||
1201 | anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rDuration); | ||
1202 | } | ||
1203 | } else { | ||
1204 | kdDebug(5800) << "we don't understand this type of recurrence!" << endl; | ||
1205 | } // if | ||
1206 | } // repeats | ||
1207 | |||
1208 | |||
1209 | // recurrence exceptions | ||
1210 | if ((vo = isAPropertyOf(vevent, VCExDateProp)) != 0) { | ||
1211 | s = fakeCString(vObjectUStringZValue(vo)); | ||
1212 | QStringList exDates = QStringList::split(",",s); | ||
1213 | QStringList::ConstIterator it; | ||
1214 | for(it = exDates.begin(); it != exDates.end(); ++it ) { | ||
1215 | anEvent->addExDate(ISOToQDate(*it)); | ||
1216 | } | ||
1217 | deleteStr(s); | ||
1218 | } | ||
1219 | |||
1220 | // summary | ||
1221 | if ((vo = isAPropertyOf(vevent, VCSummaryProp))) { | ||
1222 | s = fakeCString(vObjectUStringZValue(vo)); | ||
1223 | anEvent->setSummary(QString::fromLocal8Bit(s)); | ||
1224 | deleteStr(s); | ||
1225 | } | ||
1226 | if ((vo = isAPropertyOf(vevent, VCLocationProp))) { | ||
1227 | s = fakeCString(vObjectUStringZValue(vo)); | ||
1228 | anEvent->setLocation(QString::fromLocal8Bit(s)); | ||
1229 | deleteStr(s); | ||
1230 | } | ||
1231 | |||
1232 | // description | ||
1233 | if ((vo = isAPropertyOf(vevent, VCDescriptionProp)) != 0) { | ||
1234 | s = fakeCString(vObjectUStringZValue(vo)); | ||
1235 | if (!anEvent->description().isEmpty()) { | ||
1236 | anEvent->setDescription(anEvent->description() + "\n" + | ||
1237 | QString::fromLocal8Bit(s)); | ||
1238 | } else { | ||
1239 | anEvent->setDescription(QString::fromLocal8Bit(s)); | ||
1240 | } | ||
1241 | deleteStr(s); | ||
1242 | } | ||
1243 | |||
1244 | // some stupid vCal exporters ignore the standard and use Description | ||
1245 | // instead of Summary for the default field. Correct for this. | ||
1246 | if (anEvent->summary().isEmpty() && | ||
1247 | !(anEvent->description().isEmpty())) { | ||
1248 | QString tmpStr = anEvent->description().simplifyWhiteSpace(); | ||
1249 | anEvent->setDescription(""); | ||
1250 | anEvent->setSummary(tmpStr); | ||
1251 | } | ||
1252 | |||
1253 | #if 0 | ||
1254 | // status | ||
1255 | if ((vo = isAPropertyOf(vevent, VCStatusProp)) != 0) { | ||
1256 | QString tmpStr(s = fakeCString(vObjectUStringZValue(vo))); | ||
1257 | deleteStr(s); | ||
1258 | // TODO: Define Event status | ||
1259 | // anEvent->setStatus(tmpStr); | ||
1260 | } | ||
1261 | else | ||
1262 | // anEvent->setStatus("NEEDS ACTION"); | ||
1263 | #endif | ||
1264 | |||
1265 | // secrecy | ||
1266 | int secrecy = Incidence::SecrecyPublic; | ||
1267 | if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) { | ||
1268 | s = fakeCString(vObjectUStringZValue(vo)); | ||
1269 | if (strcmp(s,"PRIVATE") == 0) { | ||
1270 | secrecy = Incidence::SecrecyPrivate; | ||
1271 | } else if (strcmp(s,"CONFIDENTIAL") == 0) { | ||
1272 | secrecy = Incidence::SecrecyConfidential; | ||
1273 | } | ||
1274 | deleteStr(s); | ||
1275 | } | ||
1276 | anEvent->setSecrecy(secrecy); | ||
1277 | |||
1278 | // categories | ||
1279 | QStringList tmpStrList; | ||
1280 | int index1 = 0; | ||
1281 | int index2 = 0; | ||
1282 | if ((vo = isAPropertyOf(vevent, VCCategoriesProp)) != 0) { | ||
1283 | s = fakeCString(vObjectUStringZValue(vo)); | ||
1284 | QString categories = QString::fromLocal8Bit(s); | ||
1285 | deleteStr(s); | ||
1286 | //const char* category; | ||
1287 | QString category; | ||
1288 | while ((index2 = categories.find(',', index1)) != -1) { | ||
1289 | //category = (const char *) categories.mid(index1, (index2 - index1)); | ||
1290 | category = categories.mid(index1, (index2 - index1)); | ||
1291 | tmpStrList.append(category); | ||
1292 | index1 = index2+1; | ||
1293 | } | ||
1294 | // get last category | ||
1295 | category = categories.mid(index1, (categories.length()-index1)); | ||
1296 | tmpStrList.append(category); | ||
1297 | anEvent->setCategories(tmpStrList); | ||
1298 | } | ||
1299 | |||
1300 | // attachments | ||
1301 | tmpStrList.clear(); | ||
1302 | initPropIterator(&voi, vevent); | ||
1303 | while (moreIteration(&voi)) { | ||
1304 | vo = nextVObject(&voi); | ||
1305 | if (strcmp(vObjectName(vo), VCAttachProp) == 0) { | ||
1306 | s = fakeCString(vObjectUStringZValue(vo)); | ||
1307 | anEvent->addAttachment(new Attachment(QString(s))); | ||
1308 | deleteStr(s); | ||
1309 | } | ||
1310 | } | ||
1311 | |||
1312 | // resources | ||
1313 | if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) { | ||
1314 | QString resources = (s = fakeCString(vObjectUStringZValue(vo))); | ||
1315 | deleteStr(s); | ||
1316 | tmpStrList.clear(); | ||
1317 | index1 = 0; | ||
1318 | index2 = 0; | ||
1319 | QString resource; | ||
1320 | while ((index2 = resources.find(';', index1)) != -1) { | ||
1321 | resource = resources.mid(index1, (index2 - index1)); | ||
1322 | tmpStrList.append(resource); | ||
1323 | index1 = index2; | ||
1324 | } | ||
1325 | anEvent->setResources(tmpStrList); | ||
1326 | } | ||
1327 | |||
1328 | /* alarm stuff */ | ||
1329 | if ((vo = isAPropertyOf(vevent, VCDAlarmProp))) { | ||
1330 | Alarm* alarm = anEvent->newAlarm(); | ||
1331 | VObject *a; | ||
1332 | if ((a = isAPropertyOf(vo, VCRunTimeProp))) { | ||
1333 | alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a)))); | ||
1334 | deleteStr(s); | ||
1335 | } | ||
1336 | alarm->setEnabled(true); | ||
1337 | if ((vo = isAPropertyOf(vevent, VCPAlarmProp))) { | ||
1338 | if ((a = isAPropertyOf(vo, VCProcedureNameProp))) { | ||
1339 | s = fakeCString(vObjectUStringZValue(a)); | ||
1340 | alarm->setProcedureAlarm(QFile::decodeName(s)); | ||
1341 | deleteStr(s); | ||
1342 | } | ||
1343 | } | ||
1344 | if ((vo = isAPropertyOf(vevent, VCAAlarmProp))) { | ||
1345 | if ((a = isAPropertyOf(vo, VCAudioContentProp))) { | ||
1346 | s = fakeCString(vObjectUStringZValue(a)); | ||
1347 | alarm->setAudioAlarm(QFile::decodeName(s)); | ||
1348 | deleteStr(s); | ||
1349 | } | ||
1350 | } | ||
1351 | } | ||
1352 | |||
1353 | // priority | ||
1354 | if ((vo = isAPropertyOf(vevent, VCPriorityProp))) { | ||
1355 | anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo)))); | ||
1356 | deleteStr(s); | ||
1357 | } | ||
1358 | |||
1359 | // transparency | ||
1360 | if ((vo = isAPropertyOf(vevent, VCTranspProp)) != 0) { | ||
1361 | int i = atoi(s = fakeCString(vObjectUStringZValue(vo))); | ||
1362 | anEvent->setTransparency( i == 1 ? Event::Transparent : Event::Opaque ); | ||
1363 | deleteStr(s); | ||
1364 | } | ||
1365 | |||
1366 | // related event | ||
1367 | if ((vo = isAPropertyOf(vevent, VCRelatedToProp)) != 0) { | ||
1368 | anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo))); | ||
1369 | deleteStr(s); | ||
1370 | mEventsRelate.append(anEvent); | ||
1371 | } | ||
1372 | |||
1373 | /* PILOT SYNC STUFF */ | ||
1374 | if ((vo = isAPropertyOf(vevent, KPilotIdProp))) { | ||
1375 | anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo)))); | ||
1376 | deleteStr(s); | ||
1377 | } | ||
1378 | else | ||
1379 | anEvent->setPilotId(0); | ||
1380 | |||
1381 | if ((vo = isAPropertyOf(vevent, KPilotStatusProp))) { | ||
1382 | anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo)))); | ||
1383 | deleteStr(s); | ||
1384 | } | ||
1385 | else | ||
1386 | anEvent->setSyncStatus(Event::SYNCMOD); | ||
1387 | |||
1388 | return anEvent; | ||
1389 | } | ||
1390 | |||
1391 | |||
1392 | QString VCalFormat::qDateToISO(const QDate &qd) | ||
1393 | { | ||
1394 | QString tmpStr; | ||
1395 | |||
1396 | ASSERT(qd.isValid()); | ||
1397 | |||
1398 | tmpStr.sprintf("%.2d%.2d%.2d", | ||
1399 | qd.year(), qd.month(), qd.day()); | ||
1400 | return tmpStr; | ||
1401 | |||
1402 | } | ||
1403 | |||
1404 | QString VCalFormat::qDateTimeToISO(const QDateTime &qdt, bool zulu) | ||
1405 | { | ||
1406 | QString tmpStr; | ||
1407 | |||
1408 | ASSERT(qdt.date().isValid()); | ||
1409 | ASSERT(qdt.time().isValid()); | ||
1410 | if (zulu) { | ||
1411 | QDateTime tmpDT(qdt); | ||
1412 | tmpDT = tmpDT.addSecs(60*(-mCalendar->getTimeZone())); // correct to GMT. | ||
1413 | tmpStr.sprintf("%.2d%.2d%.2dT%.2d%.2d%.2dZ", | ||
1414 | tmpDT.date().year(), tmpDT.date().month(), | ||
1415 | tmpDT.date().day(), tmpDT.time().hour(), | ||
1416 | tmpDT.time().minute(), tmpDT.time().second()); | ||
1417 | } else { | ||
1418 | tmpStr.sprintf("%.2d%.2d%.2dT%.2d%.2d%.2d", | ||
1419 | qdt.date().year(), qdt.date().month(), | ||
1420 | qdt.date().day(), qdt.time().hour(), | ||
1421 | qdt.time().minute(), qdt.time().second()); | ||
1422 | } | ||
1423 | return tmpStr; | ||
1424 | } | ||
1425 | |||
1426 | QDateTime VCalFormat::ISOToQDateTime(const QString & dtStr) | ||
1427 | { | ||
1428 | QDate tmpDate; | ||
1429 | QTime tmpTime; | ||
1430 | QString tmpStr; | ||
1431 | int year, month, day, hour, minute, second; | ||
1432 | |||
1433 | tmpStr = dtStr; | ||
1434 | year = tmpStr.left(4).toInt(); | ||
1435 | month = tmpStr.mid(4,2).toInt(); | ||
1436 | day = tmpStr.mid(6,2).toInt(); | ||
1437 | hour = tmpStr.mid(9,2).toInt(); | ||
1438 | minute = tmpStr.mid(11,2).toInt(); | ||
1439 | second = tmpStr.mid(13,2).toInt(); | ||
1440 | tmpDate.setYMD(year, month, day); | ||
1441 | tmpTime.setHMS(hour, minute, second); | ||
1442 | |||
1443 | ASSERT(tmpDate.isValid()); | ||
1444 | ASSERT(tmpTime.isValid()); | ||
1445 | QDateTime tmpDT(tmpDate, tmpTime); | ||
1446 | // correct for GMT if string is in Zulu format | ||
1447 | if (dtStr.at(dtStr.length()-1) == 'Z') | ||
1448 | tmpDT = tmpDT.addSecs(60*mCalendar->getTimeZone()); | ||
1449 | return tmpDT; | ||
1450 | } | ||
1451 | |||
1452 | QDate VCalFormat::ISOToQDate(const QString &dateStr) | ||
1453 | { | ||
1454 | int year, month, day; | ||
1455 | |||
1456 | year = dateStr.left(4).toInt(); | ||
1457 | month = dateStr.mid(4,2).toInt(); | ||
1458 | day = dateStr.mid(6,2).toInt(); | ||
1459 | |||
1460 | return(QDate(year, month, day)); | ||
1461 | } | ||
1462 | |||
1463 | // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc. | ||
1464 | // and break it down from it's tree-like format into the dictionary format | ||
1465 | // that is used internally in the VCalFormat. | ||
1466 | void VCalFormat::populate(VObject *vcal) | ||
1467 | { | ||
1468 | // this function will populate the caldict dictionary and other event | ||
1469 | // lists. It turns vevents into Events and then inserts them. | ||
1470 | |||
1471 | VObjectIterator i; | ||
1472 | VObject *curVO, *curVOProp; | ||
1473 | Event *anEvent; | ||
1474 | |||
1475 | if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) { | ||
1476 | char *methodType = 0; | ||
1477 | methodType = fakeCString(vObjectUStringZValue(curVO)); | ||
1478 | kdDebug() << "This calendar is an iTIP transaction of type '" | ||
1479 | << methodType << "'" << endl; | ||
1480 | delete methodType; | ||
1481 | } | ||
1482 | |||
1483 | // warn the user that we might have trouble reading non-known calendar. | ||
1484 | if ((curVO = isAPropertyOf(vcal, VCProdIdProp)) != 0) { | ||
1485 | char *s = fakeCString(vObjectUStringZValue(curVO)); | ||
1486 | if (strcmp(productId().local8Bit(), s) != 0) | ||
1487 | kdDebug() << "This vCalendar file was not created by KOrganizer " | ||
1488 | "or any other product we support. Loading anyway..." << endl; | ||
1489 | mLoadedProductId = s; | ||
1490 | deleteStr(s); | ||
1491 | } | ||
1492 | |||
1493 | // warn the user we might have trouble reading this unknown version. | ||
1494 | if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) { | ||
1495 | char *s = fakeCString(vObjectUStringZValue(curVO)); | ||
1496 | if (strcmp(_VCAL_VERSION, s) != 0) | ||
1497 | kdDebug() << "This vCalendar file has version " << s | ||
1498 | << "We only support " << _VCAL_VERSION << endl; | ||
1499 | deleteStr(s); | ||
1500 | } | ||
1501 | |||
1502 | // set the time zone | ||
1503 | if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) { | ||
1504 | char *s = fakeCString(vObjectUStringZValue(curVO)); | ||
1505 | mCalendar->setTimeZone(s); | ||
1506 | deleteStr(s); | ||
1507 | } | ||
1508 | |||
1509 | |||
1510 | // Store all events with a relatedTo property in a list for post-processing | ||
1511 | mEventsRelate.clear(); | ||
1512 | mTodosRelate.clear(); | ||
1513 | |||
1514 | initPropIterator(&i, vcal); | ||
1515 | |||
1516 | // go through all the vobjects in the vcal | ||
1517 | while (moreIteration(&i)) { | ||
1518 | curVO = nextVObject(&i); | ||
1519 | |||
1520 | /************************************************************************/ | ||
1521 | |||
1522 | // now, check to see that the object is an event or todo. | ||
1523 | if (strcmp(vObjectName(curVO), VCEventProp) == 0) { | ||
1524 | |||
1525 | if ((curVOProp = isAPropertyOf(curVO, KPilotStatusProp)) != 0) { | ||
1526 | char *s; | ||
1527 | s = fakeCString(vObjectUStringZValue(curVOProp)); | ||
1528 | // check to see if event was deleted by the kpilot conduit | ||
1529 | if (atoi(s) == Event::SYNCDEL) { | ||
1530 | deleteStr(s); | ||
1531 | kdDebug(5800) << "skipping pilot-deleted event" << endl; | ||
1532 | goto SKIP; | ||
1533 | } | ||
1534 | deleteStr(s); | ||
1535 | } | ||
1536 | |||
1537 | // this code checks to see if we are trying to read in an event | ||
1538 | // that we already find to be in the calendar. If we find this | ||
1539 | // to be the case, we skip the event. | ||
1540 | if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) { | ||
1541 | char *s = fakeCString(vObjectUStringZValue(curVOProp)); | ||
1542 | QString tmpStr(s); | ||
1543 | deleteStr(s); | ||
1544 | |||
1545 | if (mCalendar->event(tmpStr)) { | ||
1546 | goto SKIP; | ||
1547 | } | ||
1548 | if (mCalendar->todo(tmpStr)) { | ||
1549 | goto SKIP; | ||
1550 | } | ||
1551 | } | ||
1552 | |||
1553 | if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) && | ||
1554 | (!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) { | ||
1555 | kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl; | ||
1556 | goto SKIP; | ||
1557 | } | ||
1558 | |||
1559 | anEvent = VEventToEvent(curVO); | ||
1560 | // we now use addEvent instead of insertEvent so that the | ||
1561 | // signal/slot get connected. | ||
1562 | if (anEvent) { | ||
1563 | if ( !anEvent->dtStart().isValid() || !anEvent->dtEnd().isValid() ) { | ||
1564 | kdDebug() << "VCalFormat::populate(): Event has invalid dates." | ||
1565 | << endl; | ||
1566 | } else { | ||
1567 | mCalendar->addEvent(anEvent); | ||
1568 | } | ||
1569 | } else { | ||
1570 | // some sort of error must have occurred while in translation. | ||
1571 | goto SKIP; | ||
1572 | } | ||
1573 | } else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) { | ||
1574 | Todo *aTodo = VTodoToEvent(curVO); | ||
1575 | mCalendar->addTodo(aTodo); | ||
1576 | } else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) || | ||
1577 | (strcmp(vObjectName(curVO), VCProdIdProp) == 0) || | ||
1578 | (strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) { | ||
1579 | // do nothing, we know these properties and we want to skip them. | ||
1580 | // we have either already processed them or are ignoring them. | ||
1581 | ; | ||
1582 | } else { | ||
1583 | kdDebug(5800) << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\"" << endl; | ||
1584 | } | ||
1585 | SKIP: | ||
1586 | ; | ||
1587 | } // while | ||
1588 | |||
1589 | // Post-Process list of events with relations, put Event objects in relation | ||
1590 | Event *ev; | ||
1591 | for ( ev=mEventsRelate.first(); ev != 0; ev=mEventsRelate.next() ) { | ||
1592 | ev->setRelatedTo(mCalendar->event(ev->relatedToUid())); | ||
1593 | } | ||
1594 | Todo *todo; | ||
1595 | for ( todo=mTodosRelate.first(); todo != 0; todo=mTodosRelate.next() ) { | ||
1596 | todo->setRelatedTo(mCalendar->todo(todo->relatedToUid())); | ||
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | const char *VCalFormat::dayFromNum(int day) | ||
1601 | { | ||
1602 | const char *days[7] = { "MO ", "TU ", "WE ", "TH ", "FR ", "SA ", "SU " }; | ||
1603 | |||
1604 | return days[day]; | ||
1605 | } | ||
1606 | |||
1607 | int VCalFormat::numFromDay(const QString &day) | ||
1608 | { | ||
1609 | if (day == "MO ") return 0; | ||
1610 | if (day == "TU ") return 1; | ||
1611 | if (day == "WE ") return 2; | ||
1612 | if (day == "TH ") return 3; | ||
1613 | if (day == "FR ") return 4; | ||
1614 | if (day == "SA ") return 5; | ||
1615 | if (day == "SU ") return 6; | ||
1616 | |||
1617 | return -1; // something bad happened. :) | ||
1618 | } | ||
1619 | |||
1620 | Attendee::PartStat VCalFormat::readStatus(const char *s) const | ||
1621 | { | ||
1622 | QString statStr = s; | ||
1623 | statStr = statStr.upper(); | ||
1624 | Attendee::PartStat status; | ||
1625 | |||
1626 | if (statStr == "X-ACTION") | ||
1627 | status = Attendee::NeedsAction; | ||
1628 | else if (statStr == "NEEDS ACTION") | ||
1629 | status = Attendee::NeedsAction; | ||
1630 | else if (statStr== "ACCEPTED") | ||
1631 | status = Attendee::Accepted; | ||
1632 | else if (statStr== "SENT") | ||
1633 | status = Attendee::NeedsAction; | ||
1634 | else if (statStr== "TENTATIVE") | ||
1635 | status = Attendee::Tentative; | ||
1636 | else if (statStr== "CONFIRMED") | ||
1637 | status = Attendee::Accepted; | ||
1638 | else if (statStr== "DECLINED") | ||
1639 | status = Attendee::Declined; | ||
1640 | else if (statStr== "COMPLETED") | ||
1641 | status = Attendee::Completed; | ||
1642 | else if (statStr== "DELEGATED") | ||
1643 | status = Attendee::Delegated; | ||
1644 | else { | ||
1645 | kdDebug(5800) << "error setting attendee mStatus, unknown mStatus!" << endl; | ||
1646 | status = Attendee::NeedsAction; | ||
1647 | } | ||
1648 | |||
1649 | return status; | ||
1650 | } | ||
1651 | |||
1652 | QCString VCalFormat::writeStatus(Attendee::PartStat status) const | ||
1653 | { | ||
1654 | switch(status) { | ||
1655 | default: | ||
1656 | case Attendee::NeedsAction: | ||
1657 | return "NEEDS ACTION"; | ||
1658 | break; | ||
1659 | case Attendee::Accepted: | ||
1660 | return "ACCEPTED"; | ||
1661 | break; | ||
1662 | case Attendee::Declined: | ||
1663 | return "DECLINED"; | ||
1664 | break; | ||
1665 | case Attendee::Tentative: | ||
1666 | return "TENTATIVE"; | ||
1667 | break; | ||
1668 | case Attendee::Delegated: | ||
1669 | return "DELEGATED"; | ||
1670 | break; | ||
1671 | case Attendee::Completed: | ||
1672 | return "COMPLETED"; | ||
1673 | break; | ||
1674 | case Attendee::InProcess: | ||
1675 | return "NEEDS ACTION"; | ||
1676 | break; | ||
1677 | } | ||
1678 | } | ||