vcalformat.cpp
00001 /* 00002 This file is part of libkcal. 00003 00004 Copyright (c) 1998 Preston Brown <pbrown@kde.org> 00005 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include <tqapplication.h> 00024 #include <tqdatetime.h> 00025 #include <tqstring.h> 00026 #include <tqptrlist.h> 00027 #include <tqregexp.h> 00028 #include <tqclipboard.h> 00029 #include <tqdialog.h> 00030 #include <tqfile.h> 00031 00032 #include <kdebug.h> 00033 #include <tdemessagebox.h> 00034 #include <kiconloader.h> 00035 #include <tdelocale.h> 00036 00037 #include "vcc.h" 00038 #include "vobject.h" 00039 extern "C" { 00040 #include <libical/icaltime.h> 00041 #include <libical/icaltimezone.h> 00042 } 00043 #include "vcaldrag.h" 00044 #include "calendar.h" 00045 00046 #include "vcalformat.h" 00047 00048 using namespace KCal; 00049 00050 VCalFormat::VCalFormat() 00051 { 00052 } 00053 00054 VCalFormat::~VCalFormat() 00055 { 00056 } 00057 00058 bool VCalFormat::load(Calendar *calendar, const TQString &fileName) 00059 { 00060 mCalendar = calendar; 00061 00062 clearException(); 00063 00064 kdDebug(5800) << "VCalFormat::load() " << fileName << endl; 00065 00066 VObject *vcal = 0; 00067 00068 // this is not necessarily only 1 vcal. Could be many vcals, or include 00069 // a vcard... 00070 vcal = Parse_MIME_FromFileName(const_cast<char *>(TQFile::encodeName(fileName).data())); 00071 00072 if (!vcal) { 00073 setException(new ErrorFormat(ErrorFormat::CalVersionUnknown)); 00074 return FALSE; 00075 } 00076 00077 // any other top-level calendar stuff should be added/initialized here 00078 00079 // put all vobjects into their proper places 00080 populate(vcal); 00081 00082 // clean up from vcal API stuff 00083 cleanVObjects(vcal); 00084 cleanStrTbl(); 00085 00086 return true; 00087 } 00088 00089 00090 bool VCalFormat::save(Calendar *calendar, const TQString &fileName) 00091 { 00092 mCalendar = calendar; 00093 00094 TQString tmpStr; 00095 VObject *vcal, *vo; 00096 00097 kdDebug(5800) << "VCalFormat::save(): " << fileName << endl; 00098 00099 vcal = newVObject(VCCalProp); 00100 00101 // addPropValue(vcal,VCLocationProp, "0.0"); 00102 addPropValue(vcal,VCProdIdProp, productId().latin1()); 00103 addPropValue(vcal,VCVersionProp, _VCAL_VERSION); 00104 00105 // TODO STUFF 00106 Todo::List todoList = mCalendar->rawTodos(); 00107 Todo::List::ConstIterator it; 00108 for ( it = todoList.begin(); it != todoList.end(); ++it ) { 00109 vo = eventToVTodo( *it ); 00110 addVObjectProp( vcal, vo ); 00111 } 00112 00113 // EVENT STUFF 00114 Event::List events = mCalendar->rawEvents(); 00115 Event::List::ConstIterator it2; 00116 for( it2 = events.begin(); it2 != events.end(); ++it2 ) { 00117 vo = eventToVEvent( *it2 ); 00118 addVObjectProp( vcal, vo ); 00119 } 00120 00121 writeVObjectToFile(TQFile::encodeName(fileName).data() ,vcal); 00122 cleanVObjects(vcal); 00123 cleanStrTbl(); 00124 00125 if (TQFile::exists(fileName)) { 00126 kdDebug(5800) << "No error" << endl; 00127 return true; 00128 } else { 00129 kdDebug(5800) << "Error" << endl; 00130 return false; // error 00131 } 00132 00133 return false; 00134 } 00135 00136 bool VCalFormat::fromString( Calendar *calendar, const TQString &text ) 00137 { 00138 // TODO: Factor out VCalFormat::fromString() 00139 mCalendar = calendar; 00140 00141 TQCString data = text.utf8(); 00142 00143 if ( !data.size() ) return false; 00144 00145 VObject *vcal = Parse_MIME( data.data(), data.size()); 00146 if ( !vcal ) return false; 00147 00148 VObjectIterator i; 00149 VObject *curvo; 00150 initPropIterator( &i, vcal ); 00151 00152 // we only take the first object. TODO: parse all incidences. 00153 do { 00154 curvo = nextVObject( &i ); 00155 } while ( strcmp( vObjectName( curvo ), VCEventProp ) && 00156 strcmp( vObjectName( curvo ), VCTodoProp ) ); 00157 00158 if ( strcmp( vObjectName( curvo ), VCEventProp ) == 0 ) { 00159 Event *event = VEventToEvent( curvo ); 00160 calendar->addEvent( event ); 00161 } else { 00162 kdDebug(5800) << "VCalFormat::fromString(): Unknown object type." << endl; 00163 deleteVObject( vcal ); 00164 return false; 00165 } 00166 00167 deleteVObject( vcal ); 00168 00169 return true; 00170 } 00171 00172 TQString VCalFormat::toString( Calendar *calendar ) 00173 { 00174 // TODO: Factor out VCalFormat::asString() 00175 mCalendar = calendar; 00176 00177 VObject *vcal = newVObject(VCCalProp); 00178 00179 addPropValue( vcal, VCProdIdProp, CalFormat::productId().latin1() ); 00180 addPropValue( vcal, VCVersionProp, _VCAL_VERSION ); 00181 00182 // TODO: Use all data. 00183 Event::List events = calendar->events(); 00184 Event *event = events.first(); 00185 if ( !event ) { 00186 cleanVObject( vcal ); 00187 return TQString(); 00188 } 00189 00190 VObject *vevent = eventToVEvent( event ); 00191 00192 addVObjectProp( vcal, vevent ); 00193 00194 char *buf = writeMemVObject( 0, 0, vcal ); 00195 00196 TQString result( buf ); 00197 00198 cleanVObject( vcal ); 00199 00200 return result; 00201 } 00202 00203 VObject *VCalFormat::eventToVTodo(const Todo *anEvent) 00204 { 00205 VObject *vtodo; 00206 TQString tmpStr; 00207 00208 vtodo = newVObject(VCTodoProp); 00209 00210 // due date 00211 if (anEvent->hasDueDate()) { 00212 tmpStr = qDateTimeToISO(anEvent->dtDue(), 00213 !anEvent->doesFloat()); 00214 addPropValue(vtodo, VCDueProp, tmpStr.local8Bit()); 00215 } 00216 00217 // start date 00218 if (anEvent->hasStartDate()) { 00219 tmpStr = qDateTimeToISO(anEvent->dtStart(), 00220 !anEvent->doesFloat()); 00221 addPropValue(vtodo, VCDTstartProp, tmpStr.local8Bit()); 00222 } 00223 00224 // creation date 00225 tmpStr = qDateTimeToISO(anEvent->created()); 00226 addPropValue(vtodo, VCDCreatedProp, tmpStr.local8Bit()); 00227 00228 // unique id 00229 addPropValue(vtodo, VCUniqueStringProp, 00230 anEvent->uid().local8Bit()); 00231 00232 // revision 00233 tmpStr.sprintf("%i", anEvent->revision()); 00234 addPropValue(vtodo, VCSequenceProp, tmpStr.local8Bit()); 00235 00236 // last modification date 00237 tmpStr = qDateTimeToISO(anEvent->lastModified()); 00238 addPropValue(vtodo, VCLastModifiedProp, tmpStr.local8Bit()); 00239 00240 // organizer stuff 00241 // @TODO: How about the common name? 00242 tmpStr = "MAILTO:" + anEvent->organizer().email(); 00243 addPropValue(vtodo, ICOrganizerProp, tmpStr.local8Bit()); 00244 00245 // attendees 00246 if ( anEvent->attendeeCount() > 0 ) { 00247 Attendee::List::ConstIterator it; 00248 Attendee *curAttendee; 00249 for ( it = anEvent->attendees().begin(); it != anEvent->attendees().end(); 00250 ++it ) { 00251 curAttendee = *it; 00252 if (!curAttendee->email().isEmpty() && 00253 !curAttendee->name().isEmpty()) 00254 tmpStr = "MAILTO:" + curAttendee->name() + " <" + 00255 curAttendee->email() + ">"; 00256 else if (curAttendee->name().isEmpty()) 00257 tmpStr = "MAILTO: " + curAttendee->email(); 00258 else if (curAttendee->email().isEmpty()) 00259 tmpStr = "MAILTO: " + curAttendee->name(); 00260 else if (curAttendee->name().isEmpty() && 00261 curAttendee->email().isEmpty()) 00262 kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl; 00263 VObject *aProp = addPropValue(vtodo, VCAttendeeProp, tmpStr.local8Bit()); 00264 addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE"); 00265 addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status())); 00266 } 00267 } 00268 00269 // description BL: 00270 if (!anEvent->description().isEmpty()) { 00271 VObject *d = addPropValue(vtodo, VCDescriptionProp, 00272 anEvent->description().local8Bit()); 00273 if (anEvent->description().find('\n') != -1) 00274 addPropValue(d, VCEncodingProp, VCQuotedPrintableProp); 00275 } 00276 00277 // summary 00278 if (!anEvent->summary().isEmpty()) 00279 addPropValue(vtodo, VCSummaryProp, anEvent->summary().local8Bit()); 00280 00281 // location 00282 if (!anEvent->location().isEmpty()) 00283 addPropValue(vtodo, VCLocationProp, anEvent->location().local8Bit()); 00284 00285 // completed 00286 // status 00287 // backward compatibility, KOrganizer used to interpret only these two values 00288 addPropValue(vtodo, VCStatusProp, anEvent->isCompleted() ? "COMPLETED" : 00289 "NEEDS_ACTION"); 00290 // completion date 00291 if (anEvent->hasCompletedDate()) { 00292 tmpStr = qDateTimeToISO(anEvent->completed()); 00293 addPropValue(vtodo, VCCompletedProp, tmpStr.local8Bit()); 00294 } 00295 00296 // priority 00297 tmpStr.sprintf("%i",anEvent->priority()); 00298 addPropValue(vtodo, VCPriorityProp, tmpStr.local8Bit()); 00299 00300 // related event 00301 if (anEvent->relatedTo()) { 00302 addPropValue(vtodo, VCRelatedToProp, 00303 anEvent->relatedTo()->uid().local8Bit()); 00304 } 00305 00306 // categories 00307 TQStringList tmpStrList = anEvent->categories(); 00308 tmpStr = ""; 00309 TQString catStr; 00310 for ( TQStringList::Iterator it = tmpStrList.begin(); 00311 it != tmpStrList.end(); 00312 ++it ) { 00313 catStr = *it; 00314 if (catStr[0] == ' ') 00315 tmpStr += catStr.mid(1); 00316 else 00317 tmpStr += catStr; 00318 // this must be a ';' character as the vCalendar specification requires! 00319 // vcc.y has been hacked to translate the ';' to a ',' when the vcal is 00320 // read in. 00321 tmpStr += ";"; 00322 } 00323 if (!tmpStr.isEmpty()) { 00324 tmpStr.truncate(tmpStr.length()-1); 00325 addPropValue(vtodo, VCCategoriesProp, tmpStr.local8Bit()); 00326 } 00327 00328 // alarm stuff 00329 kdDebug(5800) << "vcalformat::eventToVTodo was called" << endl; 00330 Alarm::List::ConstIterator it; 00331 for ( it = anEvent->alarms().begin(); it != anEvent->alarms().end(); ++it ) { 00332 Alarm *alarm = *it; 00333 if (alarm->enabled()) { 00334 VObject *a = addProp(vtodo, VCDAlarmProp); 00335 tmpStr = qDateTimeToISO(alarm->time()); 00336 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); 00337 addPropValue(a, VCRepeatCountProp, "1"); 00338 addPropValue(a, VCDisplayStringProp, "beep!"); 00339 if (alarm->type() == Alarm::Audio) { 00340 a = addProp(vtodo, VCAAlarmProp); 00341 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); 00342 addPropValue(a, VCRepeatCountProp, "1"); 00343 addPropValue(a, VCAudioContentProp, TQFile::encodeName(alarm->audioFile())); 00344 } 00345 else if (alarm->type() == Alarm::Procedure) { 00346 a = addProp(vtodo, VCPAlarmProp); 00347 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); 00348 addPropValue(a, VCRepeatCountProp, "1"); 00349 addPropValue(a, VCProcedureNameProp, TQFile::encodeName(alarm->programFile())); 00350 } 00351 } 00352 } 00353 00354 if (anEvent->pilotId()) { 00355 // pilot sync stuff 00356 tmpStr.sprintf("%lu",anEvent->pilotId()); 00357 addPropValue(vtodo, KPilotIdProp, tmpStr.local8Bit()); 00358 tmpStr.sprintf("%i",anEvent->syncStatus()); 00359 addPropValue(vtodo, KPiloStatusProp, tmpStr.local8Bit()); 00360 } 00361 00362 return vtodo; 00363 } 00364 00365 VObject* VCalFormat::eventToVEvent(const Event *anEvent) 00366 { 00367 VObject *vevent; 00368 TQString tmpStr; 00369 00370 vevent = newVObject(VCEventProp); 00371 00372 // start and end time 00373 tmpStr = qDateTimeToISO(anEvent->dtStart(), 00374 !anEvent->doesFloat()); 00375 addPropValue(vevent, VCDTstartProp, tmpStr.local8Bit()); 00376 00377 // events that have time associated but take up no time should 00378 // not have both DTSTART and DTEND. 00379 if (anEvent->dtStart() != anEvent->dtEnd()) { 00380 tmpStr = qDateTimeToISO(anEvent->dtEnd(), 00381 !anEvent->doesFloat()); 00382 addPropValue(vevent, VCDTendProp, tmpStr.local8Bit()); 00383 } 00384 00385 // creation date 00386 tmpStr = qDateTimeToISO(anEvent->created()); 00387 addPropValue(vevent, VCDCreatedProp, tmpStr.local8Bit()); 00388 00389 // unique id 00390 addPropValue(vevent, VCUniqueStringProp, 00391 anEvent->uid().local8Bit()); 00392 00393 // revision 00394 tmpStr.sprintf("%i", anEvent->revision()); 00395 addPropValue(vevent, VCSequenceProp, tmpStr.local8Bit()); 00396 00397 // last modification date 00398 tmpStr = qDateTimeToISO(anEvent->lastModified()); 00399 addPropValue(vevent, VCLastModifiedProp, tmpStr.local8Bit()); 00400 00401 // attendee and organizer stuff 00402 // TODO: What to do with the common name? 00403 tmpStr = "MAILTO:" + anEvent->organizer().email(); 00404 addPropValue(vevent, ICOrganizerProp, tmpStr.local8Bit()); 00405 00406 // TODO: Put this functionality into Attendee class 00407 if ( anEvent->attendeeCount() > 0 ) { 00408 Attendee::List::ConstIterator it; 00409 for ( it = anEvent->attendees().begin(); it != anEvent->attendees().end(); 00410 ++it ) { 00411 Attendee *curAttendee = *it; 00412 if (!curAttendee->email().isEmpty() && 00413 !curAttendee->name().isEmpty()) 00414 tmpStr = "MAILTO:" + curAttendee->name() + " <" + 00415 curAttendee->email() + ">"; 00416 else if (curAttendee->name().isEmpty()) 00417 tmpStr = "MAILTO: " + curAttendee->email(); 00418 else if (curAttendee->email().isEmpty()) 00419 tmpStr = "MAILTO: " + curAttendee->name(); 00420 else if (curAttendee->name().isEmpty() && 00421 curAttendee->email().isEmpty()) 00422 kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl; 00423 VObject *aProp = addPropValue(vevent, VCAttendeeProp, tmpStr.local8Bit()); 00424 addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE"); 00425 addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status())); 00426 } 00427 } 00428 00429 // recurrence rule stuff 00430 const Recurrence *recur = anEvent->recurrence(); 00431 if ( recur->doesRecur() ) { 00432 bool validRecur = true; 00433 TQString tmpStr2; 00434 switch ( recur->recurrenceType() ) { 00435 case Recurrence::rDaily: 00436 tmpStr.sprintf("D%i ",recur->frequency()); 00437 break; 00438 case Recurrence::rWeekly: 00439 tmpStr.sprintf("W%i ",recur->frequency()); 00440 for (int i = 0; i < 7; i++ ) { 00441 TQBitArray days ( recur->days() ); 00442 if ( days.testBit(i) ) 00443 tmpStr += dayFromNum(i); 00444 } 00445 break; 00446 case Recurrence::rMonthlyPos: { 00447 tmpStr.sprintf("MP%i ", recur->frequency()); 00448 // write out all rMonthPos's 00449 TQValueList<RecurrenceRule::WDayPos> tmpPositions = recur->monthPositions(); 00450 for ( TQValueListConstIterator<RecurrenceRule::WDayPos> posit = tmpPositions.begin(); 00451 posit != tmpPositions.end(); ++posit ) { 00452 int pos = (*posit).pos(); 00453 tmpStr2.sprintf("%i", (pos>0) ? pos : (-pos) ); 00454 if ( pos < 0) 00455 tmpStr2 += "- "; 00456 else 00457 tmpStr2 += "+ "; 00458 tmpStr += tmpStr2; 00459 tmpStr += dayFromNum( (*posit).day() - 1 ); 00460 } 00461 break; } 00462 case Recurrence::rMonthlyDay: { 00463 tmpStr.sprintf("MD%i ", recur->frequency()); 00464 // write out all rMonthDays; 00465 TQValueList<int> tmpDays = recur->monthDays(); 00466 for ( TQValueListIterator<int> tmpDay = tmpDays.begin(); 00467 tmpDay != tmpDays.end(); ++tmpDay ) { 00468 tmpStr2.sprintf( "%i ", *tmpDay ); 00469 tmpStr += tmpStr2; 00470 } 00471 break; } 00472 case Recurrence::rYearlyMonth: { 00473 tmpStr.sprintf("YM%i ", recur->frequency()); 00474 // write out all the months;' 00475 // TODO: Any way to write out the day within the month??? 00476 TQValueList<int> months = recur->yearMonths(); 00477 for ( TQValueListIterator<int> mit = months.begin(); 00478 mit != months.end(); ++mit ) { 00479 tmpStr2.sprintf( "%i ", *mit ); 00480 tmpStr += tmpStr2; 00481 } 00482 break; } 00483 case Recurrence::rYearlyDay: { 00484 tmpStr.sprintf("YD%i ", recur->frequency()); 00485 // write out all the rYearNums; 00486 TQValueList<int> tmpDays = recur->yearDays(); 00487 for ( TQValueListIterator<int> tmpDay = tmpDays.begin(); 00488 tmpDay != tmpDays.end(); ++tmpDay ) { 00489 tmpStr2.sprintf( "%i ", *tmpDay ); 00490 tmpStr += tmpStr2; 00491 } 00492 break; } 00493 default: 00494 // TODO: Write rYearlyPos and arbitrary rules! 00495 kdDebug(5800) << "ERROR, it should never get here in eventToVEvent!" << endl; 00496 validRecur = false; 00497 break; 00498 } // switch 00499 00500 if (recur->duration() > 0) { 00501 tmpStr2.sprintf("#%i",recur->duration()); 00502 tmpStr += tmpStr2; 00503 } else if (recur->duration() == -1) { 00504 tmpStr += "#0"; // defined as repeat forever 00505 } else { 00506 tmpStr += qDateTimeToISO(recur->endDateTime(), FALSE); 00507 } 00508 // Only write out the rrule if we have a valid recurrence (i.e. a known 00509 // type in thee switch above) 00510 if ( validRecur ) 00511 addPropValue(vevent,VCRRuleProp, tmpStr.local8Bit()); 00512 00513 } // event repeats 00514 00515 // exceptions to recurrence 00516 DateList dateList = recur->exDates(); 00517 DateList::ConstIterator it; 00518 TQString tmpStr2; 00519 00520 for (it = dateList.begin(); it != dateList.end(); ++it) { 00521 tmpStr = qDateToISO(*it) + ";"; 00522 tmpStr2 += tmpStr; 00523 } 00524 if (!tmpStr2.isEmpty()) { 00525 tmpStr2.truncate(tmpStr2.length()-1); 00526 addPropValue(vevent, VCExDateProp, tmpStr2.local8Bit()); 00527 } 00528 00529 // description 00530 if (!anEvent->description().isEmpty()) { 00531 VObject *d = addPropValue(vevent, VCDescriptionProp, 00532 anEvent->description().local8Bit()); 00533 if (anEvent->description().find('\n') != -1) 00534 addPropValue(d, VCEncodingProp, VCQuotedPrintableProp); 00535 } 00536 00537 // summary 00538 if (!anEvent->summary().isEmpty()) 00539 addPropValue(vevent, VCSummaryProp, anEvent->summary().local8Bit()); 00540 00541 // location 00542 if (!anEvent->location().isEmpty()) 00543 addPropValue(vevent, VCLocationProp, anEvent->location().local8Bit()); 00544 00545 // status 00546 // TODO: define Event status 00547 // addPropValue(vevent, VCStatusProp, anEvent->statusStr().local8Bit()); 00548 00549 // secrecy 00550 const char *text = 0; 00551 switch (anEvent->secrecy()) { 00552 case Incidence::SecrecyPublic: 00553 text = "PUBLIC"; 00554 break; 00555 case Incidence::SecrecyPrivate: 00556 text = "PRIVATE"; 00557 break; 00558 case Incidence::SecrecyConfidential: 00559 text = "CONFIDENTIAL"; 00560 break; 00561 } 00562 if (text) { 00563 addPropValue(vevent, VCClassProp, text); 00564 } 00565 00566 // categories 00567 TQStringList tmpStrList = anEvent->categories(); 00568 tmpStr = ""; 00569 TQString catStr; 00570 for ( TQStringList::Iterator it = tmpStrList.begin(); 00571 it != tmpStrList.end(); 00572 ++it ) { 00573 catStr = *it; 00574 if (catStr[0] == ' ') 00575 tmpStr += catStr.mid(1); 00576 else 00577 tmpStr += catStr; 00578 // this must be a ';' character as the vCalendar specification requires! 00579 // vcc.y has been hacked to translate the ';' to a ',' when the vcal is 00580 // read in. 00581 tmpStr += ";"; 00582 } 00583 if (!tmpStr.isEmpty()) { 00584 tmpStr.truncate(tmpStr.length()-1); 00585 addPropValue(vevent, VCCategoriesProp, tmpStr.local8Bit()); 00586 } 00587 00588 // attachments 00589 // TODO: handle binary attachments! 00590 Attachment::List attachments = anEvent->attachments(); 00591 Attachment::List::ConstIterator atIt; 00592 for ( atIt = attachments.begin(); atIt != attachments.end(); ++atIt ) 00593 addPropValue( vevent, VCAttachProp, (*atIt)->uri().local8Bit() ); 00594 00595 // resources 00596 tmpStrList = anEvent->resources(); 00597 tmpStr = tmpStrList.join(";"); 00598 if (!tmpStr.isEmpty()) 00599 addPropValue(vevent, VCResourcesProp, tmpStr.local8Bit()); 00600 00601 // alarm stuff 00602 Alarm::List::ConstIterator it2; 00603 for ( it2 = anEvent->alarms().begin(); it2 != anEvent->alarms().end(); ++it2 ) { 00604 Alarm *alarm = *it2; 00605 if (alarm->enabled()) { 00606 VObject *a = addProp(vevent, VCDAlarmProp); 00607 tmpStr = qDateTimeToISO(alarm->time()); 00608 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); 00609 addPropValue(a, VCRepeatCountProp, "1"); 00610 addPropValue(a, VCDisplayStringProp, "beep!"); 00611 if (alarm->type() == Alarm::Audio) { 00612 a = addProp(vevent, VCAAlarmProp); 00613 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); 00614 addPropValue(a, VCRepeatCountProp, "1"); 00615 addPropValue(a, VCAudioContentProp, TQFile::encodeName(alarm->audioFile())); 00616 } 00617 if (alarm->type() == Alarm::Procedure) { 00618 a = addProp(vevent, VCPAlarmProp); 00619 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); 00620 addPropValue(a, VCRepeatCountProp, "1"); 00621 addPropValue(a, VCProcedureNameProp, TQFile::encodeName(alarm->programFile())); 00622 } 00623 } 00624 } 00625 00626 // priority 00627 tmpStr.sprintf("%i",anEvent->priority()); 00628 addPropValue(vevent, VCPriorityProp, tmpStr.local8Bit()); 00629 00630 // transparency 00631 tmpStr.sprintf("%i",anEvent->transparency()); 00632 addPropValue(vevent, VCTranspProp, tmpStr.local8Bit()); 00633 00634 // related event 00635 if (anEvent->relatedTo()) { 00636 addPropValue(vevent, VCRelatedToProp, 00637 anEvent->relatedTo()->uid().local8Bit()); 00638 } 00639 00640 if (anEvent->pilotId()) { 00641 // pilot sync stuff 00642 tmpStr.sprintf("%lu",anEvent->pilotId()); 00643 addPropValue(vevent, KPilotIdProp, tmpStr.local8Bit()); 00644 tmpStr.sprintf("%i",anEvent->syncStatus()); 00645 addPropValue(vevent, KPiloStatusProp, tmpStr.local8Bit()); 00646 } 00647 00648 return vevent; 00649 } 00650 00651 Todo *VCalFormat::VTodoToEvent(VObject *vtodo) 00652 { 00653 VObject *vo; 00654 VObjectIterator voi; 00655 char *s; 00656 00657 Todo *anEvent = new Todo; 00658 00659 // creation date 00660 if ((vo = isAPropertyOf(vtodo, VCDCreatedProp)) != 0) { 00661 anEvent->setCreated(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00662 deleteStr(s); 00663 } 00664 00665 // unique id 00666 vo = isAPropertyOf(vtodo, VCUniqueStringProp); 00667 // while the UID property is preferred, it is not required. We'll use the 00668 // default Event UID if none is given. 00669 if (vo) { 00670 anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo))); 00671 deleteStr(s); 00672 } 00673 00674 // last modification date 00675 if ((vo = isAPropertyOf(vtodo, VCLastModifiedProp)) != 0) { 00676 anEvent->setLastModified(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00677 deleteStr(s); 00678 } 00679 else 00680 anEvent->setLastModified(TQDateTime(TQDate::currentDate(), 00681 TQTime::currentTime())); 00682 00683 // organizer 00684 // if our extension property for the event's ORGANIZER exists, add it. 00685 if ((vo = isAPropertyOf(vtodo, ICOrganizerProp)) != 0) { 00686 anEvent->setOrganizer( s = fakeCString(vObjectUStringZValue(vo) ) ); 00687 deleteStr(s); 00688 } else { 00689 anEvent->setOrganizer( mCalendar->getOwner() ); 00690 } 00691 00692 // attendees. 00693 initPropIterator(&voi, vtodo); 00694 while (moreIteration(&voi)) { 00695 vo = nextVObject(&voi); 00696 if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) { 00697 Attendee *a; 00698 VObject *vp; 00699 s = fakeCString(vObjectUStringZValue(vo)); 00700 TQString tmpStr = TQString::fromLocal8Bit(s); 00701 deleteStr(s); 00702 tmpStr = tmpStr.simplifyWhiteSpace(); 00703 int emailPos1, emailPos2; 00704 if ((emailPos1 = tmpStr.find('<')) > 0) { 00705 // both email address and name 00706 emailPos2 = tmpStr.findRev('>'); 00707 a = new Attendee(tmpStr.left(emailPos1 - 1), 00708 tmpStr.mid(emailPos1 + 1, 00709 emailPos2 - (emailPos1 + 1))); 00710 } else if (tmpStr.find('@') > 0) { 00711 // just an email address 00712 a = new Attendee(0, tmpStr); 00713 } else { 00714 // just a name 00715 // WTF??? Replacing the spaces of a name and using this as email? 00716 TQString email = tmpStr.replace( ' ', '.' ); 00717 a = new Attendee(tmpStr,email); 00718 } 00719 00720 // is there an RSVP property? 00721 if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0) 00722 a->setRSVP(vObjectStringZValue(vp)); 00723 // is there a status property? 00724 if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0) 00725 a->setStatus(readStatus(vObjectStringZValue(vp))); 00726 // add the attendee 00727 anEvent->addAttendee(a); 00728 } 00729 } 00730 00731 // description for todo 00732 if ((vo = isAPropertyOf(vtodo, VCDescriptionProp)) != 0) { 00733 s = fakeCString(vObjectUStringZValue(vo)); 00734 anEvent->setDescription(TQString::fromLocal8Bit(s)); 00735 deleteStr(s); 00736 } 00737 00738 // summary 00739 if ((vo = isAPropertyOf(vtodo, VCSummaryProp))) { 00740 s = fakeCString(vObjectUStringZValue(vo)); 00741 anEvent->setSummary(TQString::fromLocal8Bit(s)); 00742 deleteStr(s); 00743 } 00744 00745 00746 // location 00747 if ((vo = isAPropertyOf(vtodo, VCLocationProp)) != 0) { 00748 s = fakeCString(vObjectUStringZValue(vo)); 00749 anEvent->setLocation( TQString::fromLocal8Bit(s) ); 00750 deleteStr(s); 00751 } 00752 // completed 00753 // was: status 00754 if ((vo = isAPropertyOf(vtodo, VCStatusProp)) != 0) { 00755 s = fakeCString(vObjectUStringZValue(vo)); 00756 if (strcmp(s,"COMPLETED") == 0) { 00757 anEvent->setCompleted(true); 00758 } else { 00759 anEvent->setCompleted(false); 00760 } 00761 deleteStr(s); 00762 } 00763 else 00764 anEvent->setCompleted(false); 00765 00766 // completion date 00767 if ((vo = isAPropertyOf(vtodo, VCCompletedProp)) != 0) { 00768 anEvent->setCompleted(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00769 deleteStr(s); 00770 } 00771 00772 // priority 00773 if ((vo = isAPropertyOf(vtodo, VCPriorityProp))) { 00774 anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo)))); 00775 deleteStr(s); 00776 } 00777 00778 // due date 00779 if ((vo = isAPropertyOf(vtodo, VCDueProp)) != 0) { 00780 anEvent->setDtDue(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00781 deleteStr(s); 00782 anEvent->setHasDueDate(true); 00783 } else { 00784 anEvent->setHasDueDate(false); 00785 } 00786 00787 // start time 00788 if ((vo = isAPropertyOf(vtodo, VCDTstartProp)) != 0) { 00789 anEvent->setDtStart(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00790 // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl; 00791 deleteStr(s); 00792 anEvent->setHasStartDate(true); 00793 } else { 00794 anEvent->setHasStartDate(false); 00795 } 00796 00797 /* alarm stuff */ 00798 //kdDebug(5800) << "vcalformat::VTodoToEvent called" << endl; 00799 if ((vo = isAPropertyOf(vtodo, VCDAlarmProp))) { 00800 Alarm* alarm = anEvent->newAlarm(); 00801 VObject *a; 00802 if ((a = isAPropertyOf(vo, VCRunTimeProp))) { 00803 alarm->setTime(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(a)))); 00804 deleteStr(s); 00805 } 00806 alarm->setEnabled(true); 00807 if ((vo = isAPropertyOf(vtodo, VCPAlarmProp))) { 00808 if ((a = isAPropertyOf(vo, VCProcedureNameProp))) { 00809 s = fakeCString(vObjectUStringZValue(a)); 00810 alarm->setProcedureAlarm(TQFile::decodeName(s)); 00811 deleteStr(s); 00812 } 00813 } 00814 if ((vo = isAPropertyOf(vtodo, VCAAlarmProp))) { 00815 if ((a = isAPropertyOf(vo, VCAudioContentProp))) { 00816 s = fakeCString(vObjectUStringZValue(a)); 00817 alarm->setAudioAlarm(TQFile::decodeName(s)); 00818 deleteStr(s); 00819 } 00820 } 00821 } 00822 00823 // related todo 00824 if ((vo = isAPropertyOf(vtodo, VCRelatedToProp)) != 0) { 00825 anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo))); 00826 deleteStr(s); 00827 mTodosRelate.append(anEvent); 00828 } 00829 00830 // categories 00831 if ((vo = isAPropertyOf(vtodo, VCCategoriesProp)) != 0) { 00832 s = fakeCString(vObjectUStringZValue(vo)); 00833 TQString categories = TQString::fromLocal8Bit(s); 00834 deleteStr(s); 00835 TQStringList tmpStrList = TQStringList::split( ';', categories ); 00836 anEvent->setCategories(tmpStrList); 00837 } 00838 00839 /* PILOT SYNC STUFF */ 00840 if ((vo = isAPropertyOf(vtodo, KPilotIdProp))) { 00841 anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo)))); 00842 deleteStr(s); 00843 } 00844 else 00845 anEvent->setPilotId(0); 00846 00847 if ((vo = isAPropertyOf(vtodo, KPiloStatusProp))) { 00848 anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo)))); 00849 deleteStr(s); 00850 } 00851 else 00852 anEvent->setSyncStatus(Event::SYNCMOD); 00853 00854 return anEvent; 00855 } 00856 00857 Event* VCalFormat::VEventToEvent(VObject *vevent) 00858 { 00859 VObject *vo; 00860 VObjectIterator voi; 00861 char *s; 00862 00863 Event *anEvent = new Event; 00864 00865 // creation date 00866 if ((vo = isAPropertyOf(vevent, VCDCreatedProp)) != 0) { 00867 anEvent->setCreated(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00868 deleteStr(s); 00869 } 00870 00871 // unique id 00872 vo = isAPropertyOf(vevent, VCUniqueStringProp); 00873 // while the UID property is preferred, it is not required. We'll use the 00874 // default Event UID if none is given. 00875 if (vo) { 00876 anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo))); 00877 deleteStr(s); 00878 } 00879 00880 // revision 00881 // again NSCAL doesn't give us much to work with, so we improvise... 00882 if ((vo = isAPropertyOf(vevent, VCSequenceProp)) != 0) { 00883 anEvent->setRevision(atoi(s = fakeCString(vObjectUStringZValue(vo)))); 00884 deleteStr(s); 00885 } 00886 else 00887 anEvent->setRevision(0); 00888 00889 // last modification date 00890 if ((vo = isAPropertyOf(vevent, VCLastModifiedProp)) != 0) { 00891 anEvent->setLastModified(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00892 deleteStr(s); 00893 } 00894 else 00895 anEvent->setLastModified(TQDateTime(TQDate::currentDate(), 00896 TQTime::currentTime())); 00897 00898 // organizer 00899 // if our extension property for the event's ORGANIZER exists, add it. 00900 if ((vo = isAPropertyOf(vevent, ICOrganizerProp)) != 0) { 00901 // FIXME: Also use the full name, not just the email address 00902 anEvent->setOrganizer( s = fakeCString(vObjectUStringZValue(vo) ) ); 00903 deleteStr(s); 00904 } else { 00905 anEvent->setOrganizer( mCalendar->getOwner() ); 00906 } 00907 00908 // deal with attendees. 00909 initPropIterator(&voi, vevent); 00910 while (moreIteration(&voi)) { 00911 vo = nextVObject(&voi); 00912 if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) { 00913 Attendee *a; 00914 VObject *vp; 00915 s = fakeCString(vObjectUStringZValue(vo)); 00916 TQString tmpStr = TQString::fromLocal8Bit(s); 00917 deleteStr(s); 00918 tmpStr = tmpStr.simplifyWhiteSpace(); 00919 int emailPos1, emailPos2; 00920 if ((emailPos1 = tmpStr.find('<')) > 0) { 00921 // both email address and name 00922 emailPos2 = tmpStr.findRev('>'); 00923 a = new Attendee(tmpStr.left(emailPos1 - 1), 00924 tmpStr.mid(emailPos1 + 1, 00925 emailPos2 - (emailPos1 + 1))); 00926 } else if (tmpStr.find('@') > 0) { 00927 // just an email address 00928 a = new Attendee(0, tmpStr); 00929 } else { 00930 // just a name 00931 TQString email = tmpStr.replace( ' ', '.' ); 00932 a = new Attendee(tmpStr,email); 00933 } 00934 00935 // is there an RSVP property? 00936 if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0) 00937 a->setRSVP(vObjectStringZValue(vp)); 00938 // is there a status property? 00939 if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0) 00940 a->setStatus(readStatus(vObjectStringZValue(vp))); 00941 // add the attendee 00942 anEvent->addAttendee(a); 00943 } 00944 } 00945 00946 // This isn't strictly true. An event that doesn't have a start time 00947 // or an end time doesn't "float", it has an anchor in time but it doesn't 00948 // "take up" any time. 00949 /*if ((isAPropertyOf(vevent, VCDTstartProp) == 0) || 00950 (isAPropertyOf(vevent, VCDTendProp) == 0)) { 00951 anEvent->setFloats(TRUE); 00952 } else { 00953 }*/ 00954 00955 anEvent->setFloats(FALSE); 00956 00957 // start time 00958 if ((vo = isAPropertyOf(vevent, VCDTstartProp)) != 0) { 00959 anEvent->setDtStart(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00960 // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl; 00961 deleteStr(s); 00962 if (anEvent->dtStart().time().isNull()) 00963 anEvent->setFloats(TRUE); 00964 } 00965 00966 // stop time 00967 if ((vo = isAPropertyOf(vevent, VCDTendProp)) != 0) { 00968 anEvent->setDtEnd(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); 00969 deleteStr(s); 00970 if (anEvent->dtEnd().time().isNull()) 00971 anEvent->setFloats(TRUE); 00972 } 00973 00974 // at this point, there should be at least a start or end time. 00975 // fix up for events that take up no time but have a time associated 00976 if (!(vo = isAPropertyOf(vevent, VCDTstartProp))) 00977 anEvent->setDtStart(anEvent->dtEnd()); 00978 if (!(vo = isAPropertyOf(vevent, VCDTendProp))) 00979 anEvent->setDtEnd(anEvent->dtStart()); 00980 00982 00983 // repeat stuff 00984 if ((vo = isAPropertyOf(vevent, VCRRuleProp)) != 0) { 00985 TQString tmpStr = (s = fakeCString(vObjectUStringZValue(vo))); 00986 deleteStr(s); 00987 tmpStr.simplifyWhiteSpace(); 00988 tmpStr = tmpStr.upper(); 00989 // kdDebug() <<" We have a recurrence rule: " << tmpStr<< endl; 00990 00991 // first, read the type of the recurrence 00992 int typelen = 1; 00993 uint type = Recurrence::rNone; 00994 if ( tmpStr.left(1) == "D") { 00995 type = Recurrence::rDaily; 00996 } else if ( tmpStr.left(1) == "W") { 00997 type = Recurrence::rWeekly; 00998 } else { 00999 typelen = 2; 01000 if ( tmpStr.left(2) == "MP") { 01001 type = Recurrence::rMonthlyPos; 01002 } else if ( tmpStr.left(2) == "MD" ) { 01003 type = Recurrence::rMonthlyDay; 01004 } else if ( tmpStr.left(2) == "YM" ) { 01005 type = Recurrence::rYearlyMonth; 01006 } else if ( tmpStr.left(2) == "YD" ) { 01007 type = Recurrence::rYearlyDay; 01008 } 01009 } 01010 01011 if ( type != Recurrence::rNone ) { 01012 // kdDebug() << " It's a supported type " << endl; 01013 01014 // Immediately after the type is the frequency 01015 int index = tmpStr.find(' '); 01016 int last = tmpStr.findRev(' ') + 1; // find last entry 01017 int rFreq = tmpStr.mid(typelen, (index-1)).toInt(); 01018 ++index; // advance to beginning of stuff after freq 01019 01020 // Read the type-specific settings 01021 switch ( type ) { 01022 case Recurrence::rDaily: 01023 anEvent->recurrence()->setDaily(rFreq); 01024 break; 01025 01026 case Recurrence::rWeekly: { 01027 TQBitArray qba(7); 01028 TQString dayStr; 01029 if( index == last ) { 01030 // e.g. W1 #0 01031 qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1); 01032 } 01033 else { 01034 // e.g. W1 SU #0 01035 while (index < last) { 01036 dayStr = tmpStr.mid(index, 3); 01037 int dayNum = numFromDay(dayStr); 01038 qba.setBit(dayNum); 01039 index += 3; // advance to next day, or possibly "#" 01040 } 01041 } 01042 anEvent->recurrence()->setWeekly( rFreq, qba ); 01043 break; } 01044 01045 case Recurrence::rMonthlyPos: { 01046 anEvent->recurrence()->setMonthly( rFreq ); 01047 01048 TQBitArray qba(7); 01049 short tmpPos; 01050 if( index == last ) { 01051 // e.g. MP1 #0 01052 tmpPos = anEvent->dtStart().date().day()/7 + 1; 01053 if( tmpPos == 5 ) 01054 tmpPos = -1; 01055 qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1); 01056 anEvent->recurrence()->addMonthlyPos( tmpPos, qba ); 01057 } 01058 else { 01059 // e.g. MP1 1+ SU #0 01060 while (index < last) { 01061 tmpPos = tmpStr.mid(index,1).toShort(); 01062 index += 1; 01063 if (tmpStr.mid(index,1) == "-") 01064 // convert tmpPos to negative 01065 tmpPos = 0 - tmpPos; 01066 index += 2; // advance to day(s) 01067 while (numFromDay(tmpStr.mid(index,3)) >= 0) { 01068 int dayNum = numFromDay(tmpStr.mid(index,3)); 01069 qba.setBit(dayNum); 01070 index += 3; // advance to next day, or possibly pos or "#" 01071 } 01072 anEvent->recurrence()->addMonthlyPos( tmpPos, qba ); 01073 qba.detach(); 01074 qba.fill(FALSE); // clear out 01075 } // while != "#" 01076 } 01077 break;} 01078 01079 case Recurrence::rMonthlyDay: 01080 anEvent->recurrence()->setMonthly( rFreq ); 01081 if( index == last ) { 01082 // e.g. MD1 #0 01083 short tmpDay = anEvent->dtStart().date().day(); 01084 anEvent->recurrence()->addMonthlyDate( tmpDay ); 01085 } 01086 else { 01087 // e.g. MD1 3 #0 01088 while (index < last) { 01089 int index2 = tmpStr.find(' ', index); 01090 short tmpDay = tmpStr.mid(index, (index2-index)).toShort(); 01091 index = index2-1; 01092 if (tmpStr.mid(index, 1) == "-") 01093 tmpDay = 0 - tmpDay; 01094 index += 2; // advance the index; 01095 anEvent->recurrence()->addMonthlyDate( tmpDay ); 01096 } // while != # 01097 } 01098 break; 01099 01100 case Recurrence::rYearlyMonth: 01101 anEvent->recurrence()->setYearly( rFreq ); 01102 01103 if( index == last ) { 01104 // e.g. YM1 #0 01105 short tmpMonth = anEvent->dtStart().date().month(); 01106 anEvent->recurrence()->addYearlyMonth( tmpMonth ); 01107 } 01108 else { 01109 // e.g. YM1 3 #0 01110 while (index < last) { 01111 int index2 = tmpStr.find(' ', index); 01112 short tmpMonth = tmpStr.mid(index, (index2-index)).toShort(); 01113 index = index2 + 1; 01114 anEvent->recurrence()->addYearlyMonth( tmpMonth ); 01115 } // while != # 01116 } 01117 break; 01118 01119 case Recurrence::rYearlyDay: 01120 anEvent->recurrence()->setYearly( rFreq ); 01121 01122 if( index == last ) { 01123 // e.g. YD1 #0 01124 short tmpDay = anEvent->dtStart().date().dayOfYear(); 01125 anEvent->recurrence()->addYearlyDay( tmpDay ); 01126 } 01127 else { 01128 // e.g. YD1 123 #0 01129 while (index < last) { 01130 int index2 = tmpStr.find(' ', index); 01131 short tmpDay = tmpStr.mid(index, (index2-index)).toShort(); 01132 index = index2+1; 01133 anEvent->recurrence()->addYearlyDay( tmpDay ); 01134 } // while != # 01135 } 01136 break; 01137 01138 default: break; 01139 } 01140 01141 // find the last field, which is either the duration or the end date 01142 index = last; 01143 if ( tmpStr.mid(index,1) == "#") { 01144 // Nr of occurrences 01145 index++; 01146 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); 01147 if ( rDuration > 0 ) 01148 anEvent->recurrence()->setDuration( rDuration ); 01149 } else if ( tmpStr.find('T', index) != -1 ) { 01150 TQDate rEndDate = (ISOToTQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); 01151 anEvent->recurrence()->setEndDateTime( rEndDate ); 01152 } 01153 // anEvent->recurrence()->dump(); 01154 01155 } else { 01156 kdDebug(5800) << "we don't understand this type of recurrence!" << endl; 01157 } // if known recurrence type 01158 } // repeats 01159 01160 01161 // recurrence exceptions 01162 if ((vo = isAPropertyOf(vevent, VCExDateProp)) != 0) { 01163 s = fakeCString(vObjectUStringZValue(vo)); 01164 TQStringList exDates = TQStringList::split(",",s); 01165 TQStringList::ConstIterator it; 01166 for(it = exDates.begin(); it != exDates.end(); ++it ) { 01167 anEvent->recurrence()->addExDate(ISOToTQDate(*it)); 01168 } 01169 deleteStr(s); 01170 } 01171 01172 // summary 01173 if ((vo = isAPropertyOf(vevent, VCSummaryProp))) { 01174 s = fakeCString(vObjectUStringZValue(vo)); 01175 anEvent->setSummary(TQString::fromLocal8Bit(s)); 01176 deleteStr(s); 01177 } 01178 01179 // description 01180 if ((vo = isAPropertyOf(vevent, VCDescriptionProp)) != 0) { 01181 s = fakeCString(vObjectUStringZValue(vo)); 01182 if (!anEvent->description().isEmpty()) { 01183 anEvent->setDescription(anEvent->description() + "\n" + 01184 TQString::fromLocal8Bit(s)); 01185 } else { 01186 anEvent->setDescription(TQString::fromLocal8Bit(s)); 01187 } 01188 deleteStr(s); 01189 } 01190 01191 // location 01192 if ((vo = isAPropertyOf(vevent, VCLocationProp)) != 0) { 01193 s = fakeCString(vObjectUStringZValue(vo)); 01194 anEvent->setLocation( TQString::fromLocal8Bit(s) ); 01195 deleteStr(s); 01196 } 01197 01198 // some stupid vCal exporters ignore the standard and use Description 01199 // instead of Summary for the default field. Correct for this. 01200 if (anEvent->summary().isEmpty() && 01201 !(anEvent->description().isEmpty())) { 01202 TQString tmpStr = anEvent->description().simplifyWhiteSpace(); 01203 anEvent->setDescription(""); 01204 anEvent->setSummary(tmpStr); 01205 } 01206 01207 #if 0 01208 // status 01209 if ((vo = isAPropertyOf(vevent, VCStatusProp)) != 0) { 01210 TQString tmpStr(s = fakeCString(vObjectUStringZValue(vo))); 01211 deleteStr(s); 01212 // TODO: Define Event status 01213 // anEvent->setStatus(tmpStr); 01214 } 01215 else 01216 // anEvent->setStatus("NEEDS ACTION"); 01217 #endif 01218 01219 // secrecy 01220 int secrecy = Incidence::SecrecyPublic; 01221 if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) { 01222 s = fakeCString(vObjectUStringZValue(vo)); 01223 if (strcmp(s,"PRIVATE") == 0) { 01224 secrecy = Incidence::SecrecyPrivate; 01225 } else if (strcmp(s,"CONFIDENTIAL") == 0) { 01226 secrecy = Incidence::SecrecyConfidential; 01227 } 01228 deleteStr(s); 01229 } 01230 anEvent->setSecrecy(secrecy); 01231 01232 // categories 01233 if ((vo = isAPropertyOf(vevent, VCCategoriesProp)) != 0) { 01234 s = fakeCString(vObjectUStringZValue(vo)); 01235 TQString categories = TQString::fromLocal8Bit(s); 01236 deleteStr(s); 01237 TQStringList tmpStrList = TQStringList::split( ',', categories ); 01238 anEvent->setCategories(tmpStrList); 01239 } 01240 01241 // attachments 01242 initPropIterator(&voi, vevent); 01243 while (moreIteration(&voi)) { 01244 vo = nextVObject(&voi); 01245 if (strcmp(vObjectName(vo), VCAttachProp) == 0) { 01246 s = fakeCString(vObjectUStringZValue(vo)); 01247 anEvent->addAttachment(new Attachment(TQString(s))); 01248 deleteStr(s); 01249 } 01250 } 01251 01252 // resources 01253 if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) { 01254 TQString resources = (s = fakeCString(vObjectUStringZValue(vo))); 01255 deleteStr(s); 01256 TQStringList tmpStrList = TQStringList::split( ';', resources ); 01257 anEvent->setResources(tmpStrList); 01258 } 01259 01260 /* alarm stuff */ 01261 if ((vo = isAPropertyOf(vevent, VCDAlarmProp))) { 01262 Alarm* alarm = anEvent->newAlarm(); 01263 VObject *a; 01264 if ((a = isAPropertyOf(vo, VCRunTimeProp))) { 01265 alarm->setTime(ISOToTQDateTime(s = fakeCString(vObjectUStringZValue(a)))); 01266 deleteStr(s); 01267 } 01268 alarm->setEnabled(true); 01269 if ((vo = isAPropertyOf(vevent, VCPAlarmProp))) { 01270 if ((a = isAPropertyOf(vo, VCProcedureNameProp))) { 01271 s = fakeCString(vObjectUStringZValue(a)); 01272 alarm->setProcedureAlarm(TQFile::decodeName(s)); 01273 deleteStr(s); 01274 } 01275 } 01276 if ((vo = isAPropertyOf(vevent, VCAAlarmProp))) { 01277 if ((a = isAPropertyOf(vo, VCAudioContentProp))) { 01278 s = fakeCString(vObjectUStringZValue(a)); 01279 alarm->setAudioAlarm(TQFile::decodeName(s)); 01280 deleteStr(s); 01281 } 01282 } 01283 } 01284 01285 // priority 01286 if ((vo = isAPropertyOf(vevent, VCPriorityProp))) { 01287 anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo)))); 01288 deleteStr(s); 01289 } 01290 01291 // transparency 01292 if ((vo = isAPropertyOf(vevent, VCTranspProp)) != 0) { 01293 int i = atoi(s = fakeCString(vObjectUStringZValue(vo))); 01294 anEvent->setTransparency( i == 1 ? Event::Transparent : Event::Opaque ); 01295 deleteStr(s); 01296 } 01297 01298 // related event 01299 if ((vo = isAPropertyOf(vevent, VCRelatedToProp)) != 0) { 01300 anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo))); 01301 deleteStr(s); 01302 mEventsRelate.append(anEvent); 01303 } 01304 01305 /* PILOT SYNC STUFF */ 01306 if ((vo = isAPropertyOf(vevent, KPilotIdProp))) { 01307 anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo)))); 01308 deleteStr(s); 01309 } 01310 else 01311 anEvent->setPilotId(0); 01312 01313 if ((vo = isAPropertyOf(vevent, KPiloStatusProp))) { 01314 anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo)))); 01315 deleteStr(s); 01316 } 01317 else 01318 anEvent->setSyncStatus(Event::SYNCMOD); 01319 01320 return anEvent; 01321 } 01322 01323 01324 TQString VCalFormat::qDateToISO(const TQDate &qd) 01325 { 01326 TQString tmpStr; 01327 01328 Q_ASSERT(qd.isValid()); 01329 01330 tmpStr.sprintf("%.2d%.2d%.2d", 01331 qd.year(), qd.month(), qd.day()); 01332 return tmpStr; 01333 01334 } 01335 01336 /* Return the offset of the named zone as seconds. tt is a time 01337 indicating the date for which you want the offset */ 01338 int vcaltime_utc_offset( TQDateTime ictt, TQString tzid ) 01339 { 01340 // libical-0.23 stuff: 01341 // struct icaltimetype tt = icaltime_from_timet( ictt.toTime_t(), false ); 01342 // return icaltime_utc_offset( tt, tzid.latin1() ); 01343 int daylight; 01344 struct icaltimetype tt = icaltime_from_timet_with_zone( ictt.toTime_t(), false, NULL); 01345 return icaltimezone_get_utc_offset( 01346 icaltimezone_get_builtin_timezone( tzid.latin1() ), 01347 &tt, &daylight ); 01348 } 01349 01350 TQString VCalFormat::qDateTimeToISO(const TQDateTime &qdt, bool zulu) 01351 { 01352 TQString tmpStr; 01353 01354 Q_ASSERT(qdt.date().isValid()); 01355 Q_ASSERT(qdt.time().isValid()); 01356 if (zulu) { 01357 TQDateTime tmpDT(qdt); 01358 // correct to GMT: 01359 tmpDT = tmpDT.addSecs(-vcaltime_utc_offset( tmpDT, mCalendar->timeZoneId())); 01360 tmpStr.sprintf( "%.2d%.2d%.2dT%.2d%.2d%.2dZ", 01361 tmpDT.date().year(), tmpDT.date().month(), 01362 tmpDT.date().day(), tmpDT.time().hour(), 01363 tmpDT.time().minute(), tmpDT.time().second()); 01364 } else { 01365 tmpStr.sprintf( "%.2d%.2d%.2dT%.2d%.2d%.2d", 01366 qdt.date().year(), qdt.date().month(), 01367 qdt.date().day(), qdt.time().hour(), 01368 qdt.time().minute(), qdt.time().second()); 01369 } 01370 return tmpStr; 01371 } 01372 01373 TQDateTime VCalFormat::ISOToTQDateTime(const TQString & dtStr) 01374 { 01375 TQDate tmpDate; 01376 TQTime tmpTime; 01377 TQString tmpStr; 01378 int year, month, day, hour, minute, second; 01379 01380 tmpStr = dtStr; 01381 year = tmpStr.left(4).toInt(); 01382 month = tmpStr.mid(4,2).toInt(); 01383 day = tmpStr.mid(6,2).toInt(); 01384 hour = tmpStr.mid(9,2).toInt(); 01385 minute = tmpStr.mid(11,2).toInt(); 01386 second = tmpStr.mid(13,2).toInt(); 01387 tmpDate.setYMD(year, month, day); 01388 tmpTime.setHMS(hour, minute, second); 01389 01390 Q_ASSERT(tmpDate.isValid()); 01391 Q_ASSERT(tmpTime.isValid()); 01392 TQDateTime tmpDT(tmpDate, tmpTime); 01393 // correct for GMT if string is in Zulu format 01394 if (dtStr.at(dtStr.length()-1) == 'Z') { 01395 tmpDT = tmpDT.addSecs(vcaltime_utc_offset( tmpDT, mCalendar->timeZoneId())); 01396 } 01397 return tmpDT; 01398 } 01399 01400 TQDate VCalFormat::ISOToTQDate(const TQString &dateStr) 01401 { 01402 int year, month, day; 01403 01404 year = dateStr.left(4).toInt(); 01405 month = dateStr.mid(4,2).toInt(); 01406 day = dateStr.mid(6,2).toInt(); 01407 01408 return(TQDate(year, month, day)); 01409 } 01410 01411 // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc. 01412 // and break it down from it's tree-like format into the dictionary format 01413 // that is used internally in the VCalFormat. 01414 void VCalFormat::populate(VObject *vcal) 01415 { 01416 // this function will populate the caldict dictionary and other event 01417 // lists. It turns vevents into Events and then inserts them. 01418 01419 VObjectIterator i; 01420 VObject *curVO, *curVOProp; 01421 Event *anEvent; 01422 01423 if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) { 01424 char *methodType = 0; 01425 methodType = fakeCString(vObjectUStringZValue(curVO)); 01426 kdDebug(5800) << "This calendar is an iTIP transaction of type '" 01427 << methodType << "'" << endl; 01428 deleteStr(methodType); 01429 } 01430 01431 // warn the user that we might have trouble reading non-known calendar. 01432 if ((curVO = isAPropertyOf(vcal, VCProdIdProp)) != 0) { 01433 char *s = fakeCString(vObjectUStringZValue(curVO)); 01434 if (strcmp(productId().local8Bit(), s) != 0) 01435 kdDebug(5800) << "This vCalendar file was not created by KOrganizer " 01436 "or any other product we support. Loading anyway..." << endl; 01437 mLoadedProductId = s; 01438 deleteStr(s); 01439 } 01440 01441 // warn the user we might have trouble reading this unknown version. 01442 if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) { 01443 char *s = fakeCString(vObjectUStringZValue(curVO)); 01444 if (strcmp(_VCAL_VERSION, s) != 0) 01445 kdDebug(5800) << "This vCalendar file has version " << s 01446 << "We only support " << _VCAL_VERSION << endl; 01447 deleteStr(s); 01448 } 01449 01450 #if 0 01451 // set the time zone (this is a property of the view, so just discard!) 01452 if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) { 01453 char *s = fakeCString(vObjectUStringZValue(curVO)); 01454 mCalendar->setTimeZone(s); 01455 deleteStr(s); 01456 } 01457 #endif 01458 01459 // Store all events with a relatedTo property in a list for post-processing 01460 mEventsRelate.clear(); 01461 mTodosRelate.clear(); 01462 01463 initPropIterator(&i, vcal); 01464 01465 // go through all the vobjects in the vcal 01466 while (moreIteration(&i)) { 01467 curVO = nextVObject(&i); 01468 01469 /************************************************************************/ 01470 01471 // now, check to see that the object is an event or todo. 01472 if (strcmp(vObjectName(curVO), VCEventProp) == 0) { 01473 01474 if ((curVOProp = isAPropertyOf(curVO, KPiloStatusProp)) != 0) { 01475 char *s; 01476 s = fakeCString(vObjectUStringZValue(curVOProp)); 01477 // check to see if event was deleted by the kpilot conduit 01478 if (atoi(s) == Event::SYNCDEL) { 01479 deleteStr(s); 01480 kdDebug(5800) << "skipping pilot-deleted event" << endl; 01481 goto SKIP; 01482 } 01483 deleteStr(s); 01484 } 01485 01486 // this code checks to see if we are trying to read in an event 01487 // that we already find to be in the calendar. If we find this 01488 // to be the case, we skip the event. 01489 if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) { 01490 char *s = fakeCString(vObjectUStringZValue(curVOProp)); 01491 TQString tmpStr(s); 01492 deleteStr(s); 01493 01494 if (mCalendar->incidence(tmpStr)) { 01495 goto SKIP; 01496 } 01497 } 01498 01499 if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) && 01500 (!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) { 01501 kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl; 01502 goto SKIP; 01503 } 01504 01505 anEvent = VEventToEvent(curVO); 01506 // we now use addEvent instead of insertEvent so that the 01507 // signal/slot get connected. 01508 if (anEvent) { 01509 if ( !anEvent->dtStart().isValid() || !anEvent->dtEnd().isValid() ) { 01510 kdDebug(5800) << "VCalFormat::populate(): Event has invalid dates." 01511 << endl; 01512 } else { 01513 mCalendar->addEvent(anEvent); 01514 } 01515 } else { 01516 // some sort of error must have occurred while in translation. 01517 goto SKIP; 01518 } 01519 } else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) { 01520 Todo *aTodo = VTodoToEvent(curVO); 01521 mCalendar->addTodo(aTodo); 01522 } else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) || 01523 (strcmp(vObjectName(curVO), VCProdIdProp) == 0) || 01524 (strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) { 01525 // do nothing, we know these properties and we want to skip them. 01526 // we have either already processed them or are ignoring them. 01527 ; 01528 } else { 01529 kdDebug(5800) << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\"" << endl; 01530 } 01531 SKIP: 01532 ; 01533 } // while 01534 01535 // Post-Process list of events with relations, put Event objects in relation 01536 Event::List::ConstIterator eIt; 01537 for ( eIt = mEventsRelate.begin(); eIt != mEventsRelate.end(); ++eIt ) { 01538 (*eIt)->setRelatedTo( mCalendar->incidence( (*eIt)->relatedToUid() ) ); 01539 } 01540 Todo::List::ConstIterator tIt; 01541 for ( tIt = mTodosRelate.begin(); tIt != mTodosRelate.end(); ++tIt ) { 01542 (*tIt)->setRelatedTo( mCalendar->incidence( (*tIt)->relatedToUid() ) ); 01543 } 01544 } 01545 01546 const char *VCalFormat::dayFromNum(int day) 01547 { 01548 const char *days[7] = { "MO ", "TU ", "WE ", "TH ", "FR ", "SA ", "SU " }; 01549 01550 return days[day]; 01551 } 01552 01553 int VCalFormat::numFromDay(const TQString &day) 01554 { 01555 if (day == "MO ") return 0; 01556 if (day == "TU ") return 1; 01557 if (day == "WE ") return 2; 01558 if (day == "TH ") return 3; 01559 if (day == "FR ") return 4; 01560 if (day == "SA ") return 5; 01561 if (day == "SU ") return 6; 01562 01563 return -1; // something bad happened. :) 01564 } 01565 01566 Attendee::PartStat VCalFormat::readStatus(const char *s) const 01567 { 01568 TQString statStr = s; 01569 statStr = statStr.upper(); 01570 Attendee::PartStat status; 01571 01572 if (statStr == "X-ACTION") 01573 status = Attendee::NeedsAction; 01574 else if (statStr == "NEEDS ACTION") 01575 status = Attendee::NeedsAction; 01576 else if (statStr== "ACCEPTED") 01577 status = Attendee::Accepted; 01578 else if (statStr== "SENT") 01579 status = Attendee::NeedsAction; 01580 else if (statStr== "TENTATIVE") 01581 status = Attendee::Tentative; 01582 else if (statStr== "CONFIRMED") 01583 status = Attendee::Accepted; 01584 else if (statStr== "DECLINED") 01585 status = Attendee::Declined; 01586 else if (statStr== "COMPLETED") 01587 status = Attendee::Completed; 01588 else if (statStr== "DELEGATED") 01589 status = Attendee::Delegated; 01590 else { 01591 kdDebug(5800) << "error setting attendee mStatus, unknown mStatus!" << endl; 01592 status = Attendee::NeedsAction; 01593 } 01594 01595 return status; 01596 } 01597 01598 TQCString VCalFormat::writeStatus(Attendee::PartStat status) const 01599 { 01600 switch(status) { 01601 default: 01602 case Attendee::NeedsAction: 01603 return "NEEDS ACTION"; 01604 break; 01605 case Attendee::Accepted: 01606 return "ACCEPTED"; 01607 break; 01608 case Attendee::Declined: 01609 return "DECLINED"; 01610 break; 01611 case Attendee::Tentative: 01612 return "TENTATIVE"; 01613 break; 01614 case Attendee::Delegated: 01615 return "DELEGATED"; 01616 break; 01617 case Attendee::Completed: 01618 return "COMPLETED"; 01619 break; 01620 case Attendee::InProcess: 01621 return "NEEDS ACTION"; 01622 break; 01623 } 01624 }