libkcal Library API Documentation

vcalformat.cpp

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