libkcal Library API Documentation

vcalformat.cpp

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