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