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 Sat May 1 11:36:23 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003