author | zautrix <zautrix> | 2004-10-15 14:26:07 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2004-10-15 14:26:07 (UTC) |
commit | 4f276d80bd977401d656851515474cc00c661e5b (patch) (side-by-side diff) | |
tree | 0d3a747bef0431ef791b69876f5bda554f9ca83f /libkcal | |
parent | c2fb960297c4b08980921c818a4d347057732390 (diff) | |
download | kdepimpi-4f276d80bd977401d656851515474cc00c661e5b.zip kdepimpi-4f276d80bd977401d656851515474cc00c661e5b.tar.gz kdepimpi-4f276d80bd977401d656851515474cc00c661e5b.tar.bz2 |
many phone and sync fixes
-rw-r--r-- | libkcal/event.cpp | 46 | ||||
-rw-r--r-- | libkcal/event.h | 2 | ||||
-rw-r--r-- | libkcal/phoneformat.cpp | 104 | ||||
-rw-r--r-- | libkcal/phoneformat.h | 2 | ||||
-rw-r--r-- | libkcal/todo.cpp | 58 | ||||
-rw-r--r-- | libkcal/todo.h | 1 | ||||
-rw-r--r-- | libkcal/vcalformat.cpp | 141 |
7 files changed, 227 insertions, 127 deletions
diff --git a/libkcal/event.cpp b/libkcal/event.cpp index dfa265b..7256f05 100644 --- a/libkcal/event.cpp +++ b/libkcal/event.cpp @@ -1,177 +1,223 @@ /* This file is part of libkcal. Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <kglobal.h> #include <klocale.h> #include <kdebug.h> #include "event.h" using namespace KCal; Event::Event() : mHasEndDate( false ), mTransparency( Opaque ) { } Event::Event(const Event &e) : Incidence(e) { mDtEnd = e.mDtEnd; mHasEndDate = e.mHasEndDate; mTransparency = e.mTransparency; } Event::~Event() { } Incidence *Event::clone() { return new Event(*this); } bool KCal::operator==( const Event& e1, const Event& e2 ) { return operator==( (const Incidence&)e1, (const Incidence&)e2 ) && e1.dtEnd() == e2.dtEnd() && e1.hasEndDate() == e2.hasEndDate() && e1.transparency() == e2.transparency(); } +bool Event::contains ( Event* from ) +{ + + if ( !from->summary().isEmpty() ) + if ( !summary().startsWith( from->summary() )) + return false; + if ( from->dtStart().isValid() ) + if (dtStart() != from->dtStart() ) + return false; + if ( from->dtEnd().isValid() ) + if ( dtEnd() != from->dtEnd() ) + return false; + if ( !from->location().isEmpty() ) + if ( !location().startsWith( from->location() ) ) + return false; + if ( !from->description().isEmpty() ) + if ( !description().startsWith( from->description() )) + return false; + if ( from->alarms().count() ) { + Alarm *a = from->alarms().first(); + if ( a->enabled() ){ + if ( !alarms().count() ) + return false; + Alarm *b = alarms().first(); + if( ! b->enabled() ) + return false; + if ( ! (a->offset() == b->offset() )) + return false; + } + } + QStringList cat = categories(); + QStringList catFrom = from->categories(); + QString nCat; + int iii; + for ( iii = 0; iii < catFrom.count();++iii ) { + nCat = catFrom[iii]; + if ( !nCat.isEmpty() ) + if ( !cat.contains( nCat )) { + return false; + } + } + if ( from->doesRecur() ) + if ( from->doesRecur() != doesRecur() && ! (from->doesRecur()== Recurrence::rYearlyMonth && doesRecur()== Recurrence::rYearlyDay) ) + return false; + return true; +} void Event::setDtEnd(const QDateTime &dtEnd) { if (mReadOnly) return; mDtEnd = getEvenTime( dtEnd ); setHasEndDate(true); setHasDuration(false); updated(); } QDateTime Event::dtEnd() const { if (hasEndDate()) return mDtEnd; if (hasDuration()) return dtStart().addSecs(duration()); kdDebug(5800) << "Warning! Event '" << summary() << "' does have neither end date nor duration." << endl; return dtStart(); } QString Event::dtEndTimeStr() const { return KGlobal::locale()->formatTime(mDtEnd.time()); } QString Event::dtEndDateStr(bool shortfmt) const { return KGlobal::locale()->formatDate(mDtEnd.date(),shortfmt); } QString Event::dtEndStr(bool shortfmt) const { return KGlobal::locale()->formatDateTime(mDtEnd, shortfmt); } void Event::setHasEndDate(bool b) { mHasEndDate = b; } bool Event::hasEndDate() const { return mHasEndDate; } bool Event::isMultiDay() const { bool multi = !(dtStart().date() == dtEnd().date()); return multi; } void Event::setTransparency(Event::Transparency transparency) { if (mReadOnly) return; mTransparency = transparency; updated(); } Event::Transparency Event::transparency() const { return mTransparency; } void Event::setDuration(int seconds) { setHasEndDate(false); Incidence::setDuration(seconds); } QDateTime Event::getNextAlarmDateTime( bool * ok, int * offset ) const { bool yes; QDateTime incidenceStart = getNextOccurence( QDateTime::currentDateTime(), &yes ); if ( ! yes || cancelled() ) { *ok = false; return QDateTime (); } bool enabled = false; Alarm* alarm; int off; QDateTime alarmStart = QDateTime::currentDateTime().addDays( 3650 );; // if ( QDateTime::currentDateTime() > incidenceStart ){ // *ok = false; // return incidenceStart; // } for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) { if (alarm->enabled()) { if ( alarm->hasTime () ) { if ( alarm->time() < alarmStart ) { alarmStart = alarm->time(); enabled = true; off = alarmStart.secsTo( incidenceStart ); } } else { int secs = alarm->startOffset().asSeconds(); if ( incidenceStart.addSecs( secs ) < alarmStart ) { alarmStart = incidenceStart.addSecs( secs ); enabled = true; off = -secs; } } } } if ( enabled ) { if ( alarmStart > QDateTime::currentDateTime() ) { *ok = true; * offset = off; return alarmStart; } } *ok = false; return QDateTime (); } diff --git a/libkcal/event.h b/libkcal/event.h index 2a8bd95..3bc8adc 100644 --- a/libkcal/event.h +++ b/libkcal/event.h @@ -1,88 +1,90 @@ /* This file is part of libkcal. Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef EVENT_H #define EVENT_H // // Event component, representing a VEVENT object // #include "incidence.h" namespace KCal { /** This class provides an Event in the sense of RFC2445. */ class Event : public Incidence { public: enum Transparency { Opaque, Transparent }; typedef ListBase<Event> List; Event(); Event(const Event &); ~Event(); QCString type() const { return "Event"; } Incidence *clone(); QDateTime getNextAlarmDateTime( bool * ok, int * offset ) const; /** for setting an event's ending date/time with a QDateTime. */ void setDtEnd(const QDateTime &dtEnd); /** Return the event's ending date/time as a QDateTime. */ virtual QDateTime dtEnd() const; /** returns an event's end time as a string formatted according to the users locale settings */ QString dtEndTimeStr() const; /** returns an event's end date as a string formatted according to the users locale settings */ QString dtEndDateStr(bool shortfmt=true) const; /** returns an event's end date and time as a string formatted according to the users locale settings */ QString dtEndStr(bool shortfmt=true) const; void setHasEndDate(bool); /** Return whether the event has an end date/time. */ bool hasEndDate() const; /** Return true if the event spans multiple days, otherwise return false. */ bool isMultiDay() const; /** set the event's time transparency level. */ void setTransparency(Transparency transparency); /** get the event's time transparency level. */ Transparency transparency() const; void setDuration(int seconds); + bool contains ( Event*); + private: bool accept(Visitor &v) { return v.visit(this); } QDateTime mDtEnd; bool mHasEndDate; Transparency mTransparency; }; bool operator==( const Event&, const Event& ); } #endif diff --git a/libkcal/phoneformat.cpp b/libkcal/phoneformat.cpp index 281434e..101db57 100644 --- a/libkcal/phoneformat.cpp +++ b/libkcal/phoneformat.cpp @@ -1,634 +1,620 @@ /* This file is part of libkcal. Copyright (c) 2004 Lutz Rogowski <rogowski@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <qdatetime.h> #include <qstring.h> #include <qapplication.h> #include <qptrlist.h> #include <qregexp.h> #include <qmessagebox.h> #include <qclipboard.h> #include <qfile.h> #include <qtextstream.h> #include <qtextcodec.h> #include <qdir.h> #include <qlabel.h> #include <kdebug.h> #include <klocale.h> #include <kglobal.h> #include <kmessagebox.h> #include <phoneaccess.h> #include "calendar.h" #include "alarm.h" #include "recurrence.h" #include "calendarlocal.h" #include "phoneformat.h" #include "syncdefines.h" using namespace KCal; class PhoneParser : public QObject { public: PhoneParser( ) { ; } static QString dtToString( const QDateTime& dti, bool useTZ = false ) { QString datestr; QString timestr; int offset = KGlobal::locale()->localTimeOffset( dti ); QDateTime dt; if (useTZ) dt = dti.addSecs ( -(offset*60)); else dt = dti; if(dt.date().isValid()){ const QDate& date = dt.date(); datestr.sprintf("%04d%02d%02d", date.year(), date.month(), date.day()); } if(dt.time().isValid()){ const QTime& time = dt.time(); timestr.sprintf("T%02d%02d%02d", time.hour(), time.minute(), time.second()); } return datestr + timestr; } }; PhoneFormat::PhoneFormat(QString profileName, QString device,QString connection, QString model ) { mProfileName = profileName; PhoneAccess::writeConfig( device, connection, model ); } PhoneFormat::~PhoneFormat() { } #if 0 int PhoneFormat::initDevice(GSM_StateMachine *s) { GSM_ReadConfig(NULL, &s->Config[0], 0); s->ConfigNum = 1; GSM_Config *cfg = &s->Config[0]; if ( ! mConnection.isEmpty() ) { cfg->Connection = strdup(mConnection.latin1()); cfg->DefaultConnection = false; qDebug("Connection set %s ", cfg->Connection ); } if ( ! mDevice.isEmpty() ) { cfg->Device = strdup(mDevice.latin1()); cfg->DefaultDevice = false; qDebug("Device set %s ", cfg->Device); } if ( ! mModel.isEmpty() ) { strcpy(cfg->Model,mModel.latin1() ); cfg->DefaultModel = false; qDebug("Model set %s ",cfg->Model ); } int error=GSM_InitConnection(s,3); return error; } #endif ulong PhoneFormat::getCsumTodo( Todo* todo ) { QStringList attList; if ( todo->hasDueDate() ) attList << PhoneParser::dtToString ( todo->dtDue() ); attList << todo->summary(); QString completedString = "no"; if ( todo->isCompleted() ) completedString = "yes"; attList << completedString; int prio = todo->priority(); if( prio == 2 ) prio = 1; if (prio == 4 ) prio = 5 ; attList << QString::number( prio ); QString alarmString = "na"; Alarm *alarm; if ( todo->alarms().count() > 0 ) { alarm = todo->alarms().first(); if ( alarm->enabled() ) { alarmString = QString::number(alarm->offset() ); } } attList << alarmString; attList << todo->categoriesStr(); attList << todo->secrecyStr(); return PhoneFormat::getCsum(attList ); } ulong PhoneFormat::getCsumEvent( Event* event ) { QStringList attList; attList << PhoneParser::dtToString ( event->dtStart() ); attList << PhoneParser::dtToString ( event->dtEnd() ); attList << event->summary(); attList << event->location(); QString alarmString = "na"; Alarm *alarm; if ( event->alarms().count() > 0 ) { alarm = event->alarms().first(); if ( alarm->enabled() ) { alarmString = QString::number( alarm->offset() ); } } attList << alarmString; Recurrence* rec = event->recurrence(); QStringList list; bool writeEndDate = false; switch ( rec->doesRecur() ) { case Recurrence::rDaily: // 0 list.append( "0" ); list.append( QString::number( rec->frequency() ));//12 list.append( "0" ); list.append( "0" ); writeEndDate = true; break; case Recurrence::rWeekly:// 1 list.append( "1" ); list.append( QString::number( rec->frequency()) );//12 list.append( "0" ); { int days = 0; QBitArray weekDays = rec->days(); int i; for( i = 1; i <= 7; ++i ) { if ( weekDays[i-1] ) { days += 1 << (i-1); } } list.append( QString::number( days ) ); } //pending weekdays writeEndDate = true; break; case Recurrence::rMonthlyPos:// 2 list.append( "2" ); list.append( QString::number( rec->frequency()) );//12 writeEndDate = true; { int count = 1; QPtrList<Recurrence::rMonthPos> rmp; rmp = rec->monthPositions(); if ( rmp.first()->negative ) count = 5 - rmp.first()->rPos - 1; else count = rmp.first()->rPos - 1; list.append( QString::number( count ) ); } list.append( "0" ); break; case Recurrence::rMonthlyDay:// 3 list.append( "3" ); list.append( QString::number( rec->frequency()) );//12 list.append( "0" ); list.append( "0" ); writeEndDate = true; break; case Recurrence::rYearlyMonth://4 list.append( "4" ); list.append( QString::number( rec->frequency()) );//12 list.append( "0" ); list.append( "0" ); writeEndDate = true; break; default: list.append( "255" ); list.append( QString() ); list.append( "0" ); list.append( QString() ); list.append( "0" ); list.append( "20991231T000000" ); break; } if ( writeEndDate ) { if ( rec->endDate().isValid() ) { // 15 + 16 list.append( "1" ); list.append( PhoneParser::dtToString( rec->endDate()) ); } else { list.append( "0" ); list.append( "20991231T000000" ); } } attList << list.join(""); attList << event->categoriesStr(); //qDebug("csum cat %s", event->categoriesStr().latin1()); attList << event->secrecyStr(); return PhoneFormat::getCsum(attList ); } ulong PhoneFormat::getCsum( const QStringList & attList) { int max = attList.count(); ulong cSum = 0; int j,k,i; int add; for ( i = 0; i < max ; ++i ) { QString s = attList[i]; if ( ! s.isEmpty() ){ j = s.length(); for ( k = 0; k < j; ++k ) { int mul = k +1; add = s[k].unicode (); if ( k < 16 ) mul = mul * mul; int ii = i+1; add = add * mul *ii*ii*ii; cSum += add; } } } //QString dump = attList.join(","); //qDebug("csum: %d %s", cSum,dump.latin1()); return cSum; } //extern "C" GSM_Error GSM_InitConnection(GSM_StateMachine *s, int ReplyNum); #include <stdlib.h> #define DEBUGMODE false bool PhoneFormat::load( Calendar *calendar, Calendar *existingCal) { QString fileName; #ifdef _WIN32_ fileName = locateLocal("tmp", "phonefile.vcs"); #else fileName = "/tmp/phonefile.vcs"; #endif QString command; if ( ! PhoneAccess::readFromPhone( fileName )) { return false; } VCalFormat vfload; vfload.setLocalTime ( true ); qDebug("loading file ..."); if ( ! vfload.load( calendar, fileName ) ) return false; QPtrList<Event> er = calendar->rawEvents(); Event* ev = er.first(); qDebug("reading events... "); while ( ev ) { QStringList cat = ev->categories(); if ( cat.contains( "MeetingDEF" )) { ev->setCategories( QStringList() ); + } else + if ( cat.contains( "Birthday" )) { + ev->setFloats( true ); + QDate da = ev->dtStart().date(); + ev->setDtStart( QDateTime( da) ); + ev->setDtEnd( QDateTime( da.addDays(1)) ); + } + uint cSum; + cSum = PhoneFormat::getCsumEvent( ev ); int id = ev->pilotId(); Event *event; event = existingCal->event( mProfileName ,QString::number( id ) ); if ( event ) { event = (Event*)event->clone(); copyEvent( event, ev ); calendar->deleteEvent( ev ); calendar->addEvent( event); } else event = ev; - uint cSum; - cSum = PhoneFormat::getCsumEvent( event ); event->setCsum( mProfileName, QString::number( cSum )); event->setTempSyncStat( SYNC_TEMPSTATE_NEW_EXTERNAL ); event->setID( mProfileName,QString::number( id ) ); ev = er.next(); } { qDebug("reading todos... "); QPtrList<Todo> tr = calendar->rawTodos(); Todo* ev = tr.first(); while ( ev ) { QStringList cat = ev->categories(); if ( cat.contains( "MeetingDEF" )) { ev->setCategories( QStringList() ); } int id = ev->pilotId(); + uint cSum; + cSum = PhoneFormat::getCsumTodo( ev ); Todo *event; event = existingCal->todo( mProfileName ,QString::number( id ) ); if ( event ) { //qDebug("copy todo %s ", event->summary().latin1()); event = (Todo*)event->clone(); copyTodo( event, ev ); calendar->deleteTodo( ev ); calendar->addTodo( event); } else event = ev; - uint cSum; - cSum = PhoneFormat::getCsumTodo( event ); event->setCsum( mProfileName, QString::number( cSum )); event->setTempSyncStat( SYNC_TEMPSTATE_NEW_EXTERNAL ); event->setID( mProfileName,QString::number( id ) ); ev = tr.next(); } } return true; } void PhoneFormat::copyEvent( Event* to, Event* from ) { if ( from->dtStart().isValid() ) to->setDtStart( from->dtStart() ); if ( from->dtEnd().isValid() ) to->setDtEnd( from->dtEnd() ); if ( !from->location().isEmpty() ) to->setLocation( from->location() ); if ( !from->description().isEmpty() ) to->setDescription( from->description() ); if ( !from->summary().isEmpty() ) to->setSummary( from->summary() ); if ( from->alarms().count() ) { to->clearAlarms(); Alarm *a = from->alarms().first(); Alarm *b = to->newAlarm( ); b->setEnabled( a->enabled() ); - if ( a->hasStartOffset() ) { - b->setStartOffset( a->startOffset() ); - } - if ( a->hasTime() ) - b->setTime( a->time() ); + b->setStartOffset(Duration( a->offset() ) ); } QStringList cat = to->categories(); QStringList catFrom = from->categories(); QString nCat; int iii; for ( iii = 0; iii < catFrom.count();++iii ) { nCat = catFrom[iii]; if ( !nCat.isEmpty() ) if ( !cat.contains( nCat )) { cat << nCat; } } to->setCategories( cat ); - Recurrence * r = new Recurrence( *from->recurrence(),to); - to->setRecurrence( r ) ; + if ( from->doesRecur() ) { + Recurrence * r = new Recurrence( *from->recurrence(),to); + to->setRecurrence( r ) ; + } } void PhoneFormat::copyTodo( Todo* to, Todo* from ) { - if ( from->dtStart().isValid() ) + if ( from->hasStartDate() ) { + to->setHasStartDate( true ); to->setDtStart( from->dtStart() ); - if ( from->dtDue().isValid() ) + } + if ( from->hasDueDate() ){ + to->setHasDueDate( true ); to->setDtDue( from->dtDue() ); + } if ( !from->location().isEmpty() ) to->setLocation( from->location() ); if ( !from->description().isEmpty() ) to->setDescription( from->description() ); if ( !from->summary().isEmpty() ) to->setSummary( from->summary() ); if ( from->alarms().count() ) { to->clearAlarms(); Alarm *a = from->alarms().first(); Alarm *b = to->newAlarm( ); b->setEnabled( a->enabled() ); - if ( a->hasStartOffset() ) - b->setStartOffset( a->startOffset() ); - if ( a->hasTime() ) - b->setTime( a->time() ); + b->setStartOffset(Duration( a->offset() ) ); } QStringList cat = to->categories(); QStringList catFrom = from->categories(); QString nCat; int iii; for ( iii = 0; iii < catFrom.count();++iii ) { nCat = catFrom[iii]; if ( !nCat.isEmpty() ) if ( !cat.contains( nCat )) { cat << nCat; } } to->setCategories( cat ); if ( from->isCompleted() ) { to->setCompleted( true ); if( from->completed().isValid() ) to->setCompleted( from->completed() ); } else { // set percentcomplete only, if to->isCompleted() if ( to->isCompleted() ) to->setPercentComplete(from->percentComplete()); } if( to->priority() == 2 && from->priority() == 1 ) ; //skip else if (to->priority() == 4 && from->priority() == 5 ) ; else to->setPriority(from->priority()); } #include <qcstring.h> -void PhoneFormat::afterSave( Incidence* inc) +void PhoneFormat::afterSave( Incidence* inc,const QString& id ,const QString& csum) { - uint csum; - inc->removeID( mProfileName ); - if ( inc->type() == "Event") - csum = PhoneFormat::getCsumEvent( (Event*) inc ); - else - csum = PhoneFormat::getCsumTodo( (Todo*) inc ); - inc->setCsum( mProfileName, QString::number( csum )); - + inc->setID( mProfileName, id ); + inc->setCsum( mProfileName, csum); inc->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID ); } bool PhoneFormat::writeToPhone( Calendar * calendar) { #ifdef _WIN32_ - QString fileName = locateLocal("tmp", "tempfile.vcs"); + QString fileName = locateLocal("tmp", "phonefile.vcs"); #else - QString fileName = "/tmp/kdepimtemp.vcs"; + QString fileName = "/tmp/phonefile.vcs"; #endif VCalFormat vfsave; vfsave.setLocalTime ( true ); QString id = calendar->timeZoneId(); calendar->setLocalTime(); if ( ! vfsave.save( calendar, fileName ) ) return false; calendar->setTimeZoneId( id ); return PhoneAccess::writeToPhone( fileName ); } bool PhoneFormat::save( Calendar *calendar) { - QLabel status ( i18n(" Opening device ..."), 0 ); - int w = status.sizeHint().width()+20 ; - if ( w < 200 ) w = 230; - int h = status.sizeHint().height()+20 ; - int dw = QApplication::desktop()->width(); - int dh = QApplication::desktop()->height(); - status.setCaption(i18n("Writing to phone...") ); - status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); - status.show(); - status.raise(); - qApp->processEvents(); - QString message; + // 1 remove events which should be deleted QPtrList<Event> er = calendar->rawEvents(); Event* ev = er.first(); while ( ev ) { if ( ev->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { calendar->deleteEvent( ev ); } else { } ev = er.next(); } // 2 remove todos which should be deleted QPtrList<Todo> tl = calendar->rawTodos(); Todo* to = tl.first(); while ( to ) { if ( to->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { calendar->deleteTodo( to ); } else { if ( to->isCompleted()) { calendar->deleteTodo( to ); } } to = tl.next(); } // 3 save file if ( !writeToPhone( calendar ) ) return false; - + QLabel status ( i18n(" Opening device ..."), 0 ); + int w = status.sizeHint().width()+20 ; + if ( w < 200 ) w = 230; + int h = status.sizeHint().height()+20 ; + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + status.setCaption(i18n("Writing to phone...") ); + status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); + QString message; + status.show(); + status.raise(); + qApp->processEvents(); // 5 reread data message = i18n(" Rereading all data ... "); status.setText ( message ); qApp->processEvents(); CalendarLocal* calendarTemp = new CalendarLocal(); calendarTemp->setTimeZoneId( calendar->timeZoneId()); if ( ! load( calendarTemp,calendar) ){ qDebug("error reloading calendar "); delete calendarTemp; return false; } // 6 compare data //algo 6 compare event er = calendar->rawEvents(); ev = er.first(); message = i18n(" Comparing event # "); QPtrList<Event> er1 = calendarTemp->rawEvents(); Event* ev1; int procCount = 0; while ( ev ) { //qDebug("event new ID %s",ev->summary().latin1()); status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); - uint csum; - csum = PhoneFormat::getCsumEvent( ev ); - QString cSum = QString::number( csum ); - //ev->setCsum( mProfileName, cSum ); - //qDebug("Event cSum %s ", cSum.latin1()); ev1 = er1.first(); while ( ev1 ) { - if ( ev1->getCsum( mProfileName ) == cSum ) { + if ( ev->contains( ev1 ) ) { + afterSave( ev ,ev1->getID(mProfileName),ev1->getCsum(mProfileName)); er1.remove( ev1 ); - afterSave( ev ); - ev->setID(mProfileName, ev1->getID(mProfileName) ); - //qDebug("Event found on phone for %s ", ev->summary().latin1()); - break; } ev1 = er1.next(); } if ( ! ev1 ) { // ev->removeID(mProfileName); qDebug("ERROR: No event found on phone for %s ", ev->summary().latin1()); } ev = er.next(); } //algo 6 compare todo tl = calendar->rawTodos(); to = tl.first(); procCount = 0; QPtrList<Todo> tl1 = calendarTemp->rawTodos(); Todo* to1 ; message = i18n(" Comparing todo # "); while ( to ) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); - uint csum; - csum = PhoneFormat::getCsumTodo( to ); - QString cSum = QString::number( csum ); - //to->setCsum( mProfileName, cSum ); - //qDebug("Todo cSum %s ", cSum.latin1()); Todo* to1 = tl1.first(); while ( to1 ) { - if ( to1->getCsum( mProfileName ) == cSum ) { + if ( to->contains( to1 ) ) { + afterSave( to ,to1->getID(mProfileName),to1->getCsum(mProfileName)); tl1.remove( to1 ); - afterSave( to ); - to->setID(mProfileName, to1->getID(mProfileName) ); break; } to1 = tl1.next(); } if ( ! to1 ) { //to->removeID(mProfileName); qDebug("ERROR: No todo found on phone for %s ", to->summary().latin1()); } to = tl.next(); } delete calendarTemp; return true; } QString PhoneFormat::toString( Calendar * ) { return QString::null; } bool PhoneFormat::fromString( Calendar *calendar, const QString & text) { return false; } diff --git a/libkcal/phoneformat.h b/libkcal/phoneformat.h index 001fd81..d11f68b 100644 --- a/libkcal/phoneformat.h +++ b/libkcal/phoneformat.h @@ -1,62 +1,62 @@ /* This file is part of libkcal. Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef PHONEFORMAT_H #define PHONEFORMAT_H #include <qstring.h> #include "scheduler.h" #include "vcalformat.h" #include "calformat.h" namespace KCal { /** This class implements the calendar format used by Phone. */ class Event; class Todo; class PhoneFormat : public QObject { public: /** Create new iCalendar format. */ PhoneFormat(QString profileName, QString device,QString connection, QString model); virtual ~PhoneFormat(); bool load( Calendar * ,Calendar * ); bool save( Calendar * ); bool fromString( Calendar *, const QString & ); QString toString( Calendar * ); static ulong getCsum( const QStringList & ); static ulong getCsumTodo( Todo* to ); static ulong getCsumEvent( Event* ev ); static bool writeToPhone( Calendar * ); private: void copyEvent( Event* to, Event* from ); void copyTodo( Todo* to, Todo* from ); //int initDevice(GSM_StateMachine *s); QString mProfileName; - void afterSave( Incidence* ); + void afterSave( Incidence* ,const QString&,const QString&); }; } #endif diff --git a/libkcal/todo.cpp b/libkcal/todo.cpp index 0c1e3e4..3d2de61 100644 --- a/libkcal/todo.cpp +++ b/libkcal/todo.cpp @@ -1,316 +1,374 @@ /* This file is part of libkcal. Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <kglobal.h> #include <klocale.h> #include <kdebug.h> #include "todo.h" using namespace KCal; Todo::Todo(): Incidence() { // mStatus = TENTATIVE; mHasDueDate = false; setHasStartDate( false ); mCompleted = getEvenTime(QDateTime::currentDateTime()); mHasCompletedDate = false; mPercentComplete = 0; } Todo::Todo(const Todo &t) : Incidence(t) { mDtDue = t.mDtDue; mHasDueDate = t.mHasDueDate; mCompleted = t.mCompleted; mHasCompletedDate = t.mHasCompletedDate; mPercentComplete = t.mPercentComplete; } Todo::~Todo() { } Incidence *Todo::clone() { return new Todo(*this); } +bool Todo::contains ( Todo* from ) +{ + if ( !from->summary().isEmpty() ) + if ( !summary().startsWith( from->summary() )) + return false; + if ( from->hasStartDate() ) { + if ( !hasStartDate() ) + return false; + if ( from->dtStart() != dtStart()) + return false; + } + if ( from->hasDueDate() ){ + if ( !hasDueDate() ) + return false; + if ( from->dtDue() != dtDue()) + return false; + } + if ( !from->location().isEmpty() ) + if ( !location().startsWith( from->location() ) ) + return false; + if ( !from->description().isEmpty() ) + if ( !description().startsWith( from->description() )) + return false; + if ( from->alarms().count() ) { + Alarm *a = from->alarms().first(); + if ( a->enabled() ){ + if ( !alarms().count() ) + return false; + Alarm *b = alarms().first(); + if( ! b->enabled() ) + return false; + if ( ! (a->offset() == b->offset() )) + return false; + } + } + + QStringList cat = categories(); + QStringList catFrom = from->categories(); + QString nCat; + int iii; + for ( iii = 0; iii < catFrom.count();++iii ) { + nCat = catFrom[iii]; + if ( !nCat.isEmpty() ) + if ( !cat.contains( nCat )) { + return false; + } + } + if ( from->isCompleted() ) { + if ( !isCompleted() ) + return false; + } + if( priority() != from->priority() ) + return false; + + + return true; + +} bool KCal::operator==( const Todo& t1, const Todo& t2 ) { bool ret = operator==( (const Incidence&)t1, (const Incidence&)t2 ); if ( ! ret ) return false; if ( t1.hasDueDate() == t2.hasDueDate() ) { if ( t1.hasDueDate() ) { if ( t1.doesFloat() == t2.doesFloat() ) { if ( t1.doesFloat() ) { if ( t1.dtDue().date() != t2.dtDue().date() ) return false; } else if ( t1.dtDue() != t2.dtDue() ) return false; } else return false;// float != } } else return false; if ( t1.percentComplete() != t2.percentComplete() ) return false; if ( t1.isCompleted() ) { if ( t1.hasCompletedDate() == t2.hasCompletedDate() ) { if ( t1.hasCompletedDate() ) { if ( t1.completed() != t2.completed() ) return false; } } else return false; } return true; } void Todo::setDtDue(const QDateTime &dtDue) { //int diffsecs = mDtDue.secsTo(dtDue); /*if (mReadOnly) return; const QPtrList<Alarm>& alarms = alarms(); for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next()) { if (alarm->enabled()) { alarm->setTime(alarm->time().addSecs(diffsecs)); } }*/ mDtDue = getEvenTime(dtDue); //kdDebug(5800) << "setDtDue says date is " << mDtDue.toString() << endl; /*const QPtrList<Alarm>& alarms = alarms(); for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next()) alarm->setAlarmStart(mDtDue);*/ updated(); } QDateTime Todo::dtDue() const { return mDtDue; } QString Todo::dtDueTimeStr() const { return KGlobal::locale()->formatTime(mDtDue.time()); } QString Todo::dtDueDateStr(bool shortfmt) const { return KGlobal::locale()->formatDate(mDtDue.date(),shortfmt); } QString Todo::dtDueStr(bool shortfmt) const { return KGlobal::locale()->formatDateTime(mDtDue, shortfmt); } bool Todo::hasDueDate() const { return mHasDueDate; } void Todo::setHasDueDate(bool f) { if (mReadOnly) return; mHasDueDate = f; updated(); } #if 0 void Todo::setStatus(const QString &statStr) { if (mReadOnly) return; QString ss(statStr.upper()); if (ss == "X-ACTION") mStatus = NEEDS_ACTION; else if (ss == "NEEDS ACTION") mStatus = NEEDS_ACTION; else if (ss == "ACCEPTED") mStatus = ACCEPTED; else if (ss == "SENT") mStatus = SENT; else if (ss == "TENTATIVE") mStatus = TENTATIVE; else if (ss == "CONFIRMED") mStatus = CONFIRMED; else if (ss == "DECLINED") mStatus = DECLINED; else if (ss == "COMPLETED") mStatus = COMPLETED; else if (ss == "DELEGATED") mStatus = DELEGATED; updated(); } void Todo::setStatus(int status) { if (mReadOnly) return; mStatus = status; updated(); } int Todo::status() const { return mStatus; } QString Todo::statusStr() const { switch(mStatus) { case NEEDS_ACTION: return QString("NEEDS ACTION"); break; case ACCEPTED: return QString("ACCEPTED"); break; case SENT: return QString("SENT"); break; case TENTATIVE: return QString("TENTATIVE"); break; case CONFIRMED: return QString("CONFIRMED"); break; case DECLINED: return QString("DECLINED"); break; case COMPLETED: return QString("COMPLETED"); break; case DELEGATED: return QString("DELEGATED"); break; } return QString(""); } #endif bool Todo::isCompleted() const { if (mPercentComplete == 100) return true; else return false; } void Todo::setCompleted(bool completed) { if (completed) mPercentComplete = 100; else mPercentComplete = 0; updated(); } QDateTime Todo::completed() const { return mCompleted; } QString Todo::completedStr() const { return KGlobal::locale()->formatDateTime(mCompleted); } void Todo::setCompleted(const QDateTime &completed) { mHasCompletedDate = true; mPercentComplete = 100; mCompleted = getEvenTime(completed); updated(); } bool Todo::hasCompletedDate() const { return mHasCompletedDate; } int Todo::percentComplete() const { return mPercentComplete; } void Todo::setPercentComplete(int v) { mPercentComplete = v; updated(); } QDateTime Todo::getNextAlarmDateTime( bool * ok, int * offset ) const { if ( isCompleted() || ! hasDueDate() || cancelled() ) { *ok = false; return QDateTime (); } QDateTime incidenceStart; incidenceStart = dtDue(); bool enabled = false; Alarm* alarm; int off; QDateTime alarmStart = QDateTime::currentDateTime().addDays( 3650 );; // if ( QDateTime::currentDateTime() > incidenceStart ){ // *ok = false; // return incidenceStart; // } for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) { if (alarm->enabled()) { if ( alarm->hasTime () ) { if ( alarm->time() < alarmStart ) { alarmStart = alarm->time(); enabled = true; off = alarmStart.secsTo( incidenceStart ); } } else { int secs = alarm->startOffset().asSeconds(); if ( incidenceStart.addSecs( secs ) < alarmStart ) { alarmStart = incidenceStart.addSecs( secs ); enabled = true; off = -secs; } } } } if ( enabled ) { if ( alarmStart > QDateTime::currentDateTime() ) { *ok = true; * offset = off; return alarmStart; } } *ok = false; return QDateTime (); } diff --git a/libkcal/todo.h b/libkcal/todo.h index 9aa92f8..0f22c59 100644 --- a/libkcal/todo.h +++ b/libkcal/todo.h @@ -1,121 +1,122 @@ /* This file is part of libkcal. Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef TODO_H #define TODO_H // // Todo component, representing a VTODO object // #include "incidence.h" namespace KCal { /** This class provides a Todo in the sense of RFC2445. */ class Todo : public Incidence { public: Todo(); Todo(const Todo &); ~Todo(); typedef ListBase<Todo> List; QCString type() const { return "Todo"; } /** Return an exact copy of this todo. */ Incidence *clone(); QDateTime getNextAlarmDateTime( bool * ok, int * offset ) const; /** for setting the todo's due date/time with a QDateTime. */ void setDtDue(const QDateTime &dtDue); /** returns an event's Due date/time as a QDateTime. */ QDateTime dtDue() const; /** returns an event's due time as a string formatted according to the users locale settings */ QString dtDueTimeStr() const; /** returns an event's due date as a string formatted according to the users locale settings */ QString dtDueDateStr(bool shortfmt=true) const; /** returns an event's due date and time as a string formatted according to the users locale settings */ QString dtDueStr(bool shortfmt=true) const; /** returns TRUE or FALSE depending on whether the todo has a due date */ bool hasDueDate() const; /** sets the event's hasDueDate value. */ void setHasDueDate(bool f); /** sets the event's status to the string specified. The string * must be a recognized value for the status field, i.e. a string * equivalent of the possible status enumerations previously described. */ // void setStatus(const QString &statStr); /** sets the event's status to the value specified. See the enumeration * above for possible values. */ // void setStatus(int); /** return the event's status. */ // int status() const; /** return the event's status in string format. */ // QString statusStr() const; /** return, if this todo is completed */ bool isCompleted() const; /** set completed state of this todo */ void setCompleted(bool); /** Return how many percent of the task are completed. Returns a value between 0 and 100. */ int percentComplete() const; /** Set how many percent of the task are completed. Valid values are in the range from 0 to 100. */ void setPercentComplete(int); /** return date and time when todo was completed */ QDateTime completed() const; QString completedStr() const; /** set date and time of completion */ void setCompleted(const QDateTime &completed); /** Return true, if todo has a date associated with completion */ bool hasCompletedDate() const; + bool contains ( Todo*); private: bool accept(Visitor &v) { return v.visit(this); } QDateTime mDtDue; // due date of todo bool mHasDueDate; // if todo has associated due date // int mStatus; // confirmed/delegated/tentative/etc QDateTime mCompleted; bool mHasCompletedDate; int mPercentComplete; }; bool operator==( const Todo&, const Todo& ); } #endif diff --git a/libkcal/vcalformat.cpp b/libkcal/vcalformat.cpp index a6ae1bc..df93209 100644 --- a/libkcal/vcalformat.cpp +++ b/libkcal/vcalformat.cpp @@ -1,477 +1,479 @@ /* This file is part of libkcal. Copyright (c) 1998 Preston Brwon Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <qapplication.h> #include <qdatetime.h> #include <qstring.h> #include <qptrlist.h> #include <qregexp.h> #include <qclipboard.h> #include <qdialog.h> #include <qfile.h> #include <kdebug.h> #include <kglobal.h> #include <kmessagebox.h> #include <kiconloader.h> #include <klocale.h> #include "vcc.h" #include "vobject.h" #include "vcaldrag.h" #include "calendar.h" #include "vcalformat.h" using namespace KCal; VCalFormat::VCalFormat() { mCalendar = 0; useLocalTime = false; } VCalFormat::~VCalFormat() { } void VCalFormat::setLocalTime ( bool b ) { useLocalTime = b; } bool VCalFormat::load(Calendar *calendar, const QString &fileName) { mCalendar = calendar; clearException(); - useLocalTime = mCalendar->isLocalTime(); + if ( ! useLocalTime ) + useLocalTime = mCalendar->isLocalTime(); VObject *vcal = 0; // this is not necessarily only 1 vcal. Could be many vcals, or include // a vcard... vcal = Parse_MIME_FromFileName(const_cast<char *>(QFile::encodeName(fileName).data())); if (!vcal) { setException(new ErrorFormat(ErrorFormat::CalVersionUnknown)); return FALSE; } // any other top-level calendar stuff should be added/initialized here // put all vobjects into their proper places populate(vcal); // clean up from vcal API stuff cleanVObjects(vcal); cleanStrTbl(); return true; } bool VCalFormat::save(Calendar *calendar, const QString &fileName) { mCalendar = calendar; - useLocalTime = mCalendar->isLocalTime(); + if ( ! useLocalTime ) + useLocalTime = mCalendar->isLocalTime(); QString tmpStr; VObject *vcal, *vo; vcal = newVObject(VCCalProp); // addPropValue(vcal,VCLocationProp, "0.0"); addPropValue(vcal,VCProdIdProp, productId()); tmpStr = mCalendar->getTimeZoneStr(); //qDebug("mCalendar->getTimeZoneStr() %s",tmpStr.latin1() ); addPropValue(vcal,VCTimeZoneProp, tmpStr.local8Bit()); addPropValue(vcal,VCVersionProp, _VCAL_VERSION); // TODO STUFF QPtrList<Todo> todoList = mCalendar->rawTodos(); QPtrListIterator<Todo> qlt(todoList); for (; qlt.current(); ++qlt) { vo = eventToVTodo(qlt.current()); addVObjectProp(vcal, vo); } // EVENT STUFF QPtrList<Event> events = mCalendar->rawEvents(); Event *ev; for(ev=events.first();ev;ev=events.next()) { vo = eventToVEvent(ev); addVObjectProp(vcal, vo); } writeVObjectToFile(QFile::encodeName(fileName).data() ,vcal); cleanVObjects(vcal); cleanStrTbl(); if (QFile::exists(fileName)) { return true; } else { return false; // error } } bool VCalFormat::fromString( Calendar *calendar, const QString &text ) { // TODO: Factor out VCalFormat::fromString() QCString data = text.utf8(); if ( !data.size() ) return false; VObject *vcal = Parse_MIME( data.data(), data.size()); if ( !vcal ) return false; VObjectIterator i; VObject *curvo; initPropIterator( &i, vcal ); // we only take the first object. TODO: parse all incidences. do { curvo = nextVObject( &i ); } while ( strcmp( vObjectName( curvo ), VCEventProp ) && strcmp( vObjectName( curvo ), VCTodoProp ) ); if ( strcmp( vObjectName( curvo ), VCEventProp ) == 0 ) { Event *event = VEventToEvent( curvo ); calendar->addEvent( event ); } else { qDebug("VCalFormat::fromString(): Unknown object type. "); deleteVObject( vcal ); return false; } deleteVObject( vcal ); return true; } QString VCalFormat::eventToString( Event * event, Calendar *calendar, bool useLocal) { if ( !event ) return QString::null; bool useL = useLocalTime; useLocalTime = useLocal; mCalendar = calendar; VObject *vevent = eventToVEvent( event ); char *buf = writeMemVObject( 0, 0, vevent ); QString result( buf ); cleanVObject( vevent ); useLocalTime = useL; return result; } QString VCalFormat::todoToString( Todo * todo, Calendar *calendar, bool useLocal ) { if ( !todo ) return QString::null; bool useL = useLocalTime; useLocalTime = useLocal; mCalendar = calendar; VObject *vevent = eventToVTodo( todo ); char *buf = writeMemVObject( 0, 0, vevent ); QString result( buf ); cleanVObject( vevent ); useLocalTime = useL; return result; } QString VCalFormat::toString( Calendar *calendar ) { // TODO: Factor out VCalFormat::asString() VObject *vcal = newVObject(VCCalProp); addPropValue( vcal, VCProdIdProp, CalFormat::productId() ); QString tmpStr = mCalendar->getTimeZoneStr(); addPropValue( vcal, VCTimeZoneProp, tmpStr.local8Bit() ); addPropValue( vcal, VCVersionProp, _VCAL_VERSION ); // TODO: Use all data. QPtrList<Event> events = calendar->events(); Event *event = events.first(); if ( !event ) return QString::null; VObject *vevent = eventToVEvent( event ); addVObjectProp( vcal, vevent ); char *buf = writeMemVObject( 0, 0, vcal ); QString result( buf ); cleanVObject( vcal ); return result; } VObject *VCalFormat::eventToVTodo(const Todo *anEvent) { VObject *vtodo; QString tmpStr; QStringList tmpStrList; vtodo = newVObject(VCTodoProp); // due date if (anEvent->hasDueDate()) { tmpStr = qDateTimeToISO(anEvent->dtDue(), !anEvent->doesFloat()); addPropValue(vtodo, VCDueProp, tmpStr.local8Bit()); } // start date if (anEvent->hasStartDate()) { tmpStr = qDateTimeToISO(anEvent->dtStart(), !anEvent->doesFloat()); addPropValue(vtodo, VCDTstartProp, tmpStr.local8Bit()); } // creation date tmpStr = qDateTimeToISO(anEvent->created()); addPropValue(vtodo, VCDCreatedProp, tmpStr.local8Bit()); // unique id addPropValue(vtodo, VCUniqueStringProp, anEvent->uid().local8Bit()); // revision tmpStr.sprintf("%i", anEvent->revision()); addPropValue(vtodo, VCSequenceProp, tmpStr.local8Bit()); // last modification date tmpStr = qDateTimeToISO(anEvent->lastModified()); addPropValue(vtodo, VCLastModifiedProp, tmpStr.local8Bit()); // organizer stuff tmpStr = "MAILTO:" + anEvent->organizer(); addPropValue(vtodo, ICOrganizerProp, tmpStr.local8Bit()); // attendees if (anEvent->attendeeCount() != 0) { QPtrList<Attendee> al = anEvent->attendees(); QPtrListIterator<Attendee> ai(al); Attendee *curAttendee; for (; ai.current(); ++ai) { curAttendee = ai.current(); if (!curAttendee->email().isEmpty() && !curAttendee->name().isEmpty()) tmpStr = "MAILTO:" + curAttendee->name() + " <" + curAttendee->email() + ">"; else if (curAttendee->name().isEmpty()) tmpStr = "MAILTO: " + curAttendee->email(); else if (curAttendee->email().isEmpty()) tmpStr = "MAILTO: " + curAttendee->name(); else if (curAttendee->name().isEmpty() && curAttendee->email().isEmpty()) kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl; VObject *aProp = addPropValue(vtodo, VCAttendeeProp, tmpStr.local8Bit()); addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE"); addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status())); } } // description BL: if (!anEvent->description().isEmpty()) { VObject *d = addPropValue(vtodo, VCDescriptionProp, anEvent->description().local8Bit()); if (anEvent->description().find('\n') != -1) addProp(d, VCQuotedPrintableProp); } // summary if (!anEvent->summary().isEmpty()) addPropValue(vtodo, VCSummaryProp, anEvent->summary().local8Bit()); if (!anEvent->location().isEmpty()) addPropValue(vtodo, VCLocationProp, anEvent->location().local8Bit()); // completed // status // backward compatibility, KOrganizer used to interpret only these two values addPropValue(vtodo, VCStatusProp, anEvent->isCompleted() ? "COMPLETED" : "NEEDS_ACTION"); // completion date if (anEvent->hasCompletedDate()) { tmpStr = qDateTimeToISO(anEvent->completed()); addPropValue(vtodo, VCCompletedProp, tmpStr.local8Bit()); } // priority tmpStr.sprintf("%i",anEvent->priority()); addPropValue(vtodo, VCPriorityProp, tmpStr.local8Bit()); // related event if (anEvent->relatedTo()) { addPropValue(vtodo, VCRelatedToProp, anEvent->relatedTo()->uid().local8Bit()); } // categories tmpStrList = anEvent->categories(); tmpStr = ""; QString catStr; for ( QStringList::Iterator it = tmpStrList.begin(); it != tmpStrList.end(); ++it ) { catStr = *it; if (catStr[0] == ' ') tmpStr += catStr.mid(1); else tmpStr += catStr; // this must be a ';' character as the vCalendar specification requires! // vcc.y has been hacked to translate the ';' to a ',' when the vcal is // read in. tmpStr += ";"; } if (!tmpStr.isEmpty()) { tmpStr.truncate(tmpStr.length()-1); addPropValue(vtodo, VCCategoriesProp, tmpStr.local8Bit()); } // alarm stuff kdDebug(5800) << "vcalformat::eventToVTodo was called" << endl; QPtrList<Alarm> alarms = anEvent->alarms(); Alarm* alarm; for (alarm = alarms.first(); alarm; alarm = alarms.next()) { if (alarm->enabled()) { VObject *a; tmpStr = qDateTimeToISO(alarm->time()); if (alarm->type() == Alarm::Audio) { a = addProp(vtodo, VCAAlarmProp); addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); addPropValue(a, VCRepeatCountProp, "1"); addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile())); } else if (alarm->type() == Alarm::Procedure) { a = addProp(vtodo, VCPAlarmProp); addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); addPropValue(a, VCRepeatCountProp, "1"); addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile())); } else { a = addProp(vtodo, VCDAlarmProp); addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); addPropValue(a, VCRepeatCountProp, "1"); addPropValue(a, VCDisplayStringProp, "beep!"); } } } if (anEvent->pilotId()) { // pilot sync stuff tmpStr.sprintf("%i",anEvent->pilotId()); addPropValue(vtodo, XPilotIdProp, tmpStr.local8Bit()); tmpStr.sprintf("%i",anEvent->syncStatus()); addPropValue(vtodo, XPilotStatusProp, tmpStr.local8Bit()); } return vtodo; } VObject* VCalFormat::eventToVEvent(const Event *anEvent) { VObject *vevent; QString tmpStr; QStringList tmpStrList; vevent = newVObject(VCEventProp); // start and end time tmpStr = qDateTimeToISO(anEvent->dtStart(), !anEvent->doesFloat()); addPropValue(vevent, VCDTstartProp, tmpStr.local8Bit()); // events that have time associated but take up no time should // not have both DTSTART and DTEND. if (anEvent->dtStart() != anEvent->dtEnd()) { tmpStr = qDateTimeToISO(anEvent->dtEnd(), !anEvent->doesFloat()); addPropValue(vevent, VCDTendProp, tmpStr.local8Bit()); } // creation date tmpStr = qDateTimeToISO(anEvent->created()); addPropValue(vevent, VCDCreatedProp, tmpStr.local8Bit()); // unique id addPropValue(vevent, VCUniqueStringProp, anEvent->uid().local8Bit()); // revision tmpStr.sprintf("%i", anEvent->revision()); addPropValue(vevent, VCSequenceProp, tmpStr.local8Bit()); // last modification date tmpStr = qDateTimeToISO(anEvent->lastModified()); addPropValue(vevent, VCLastModifiedProp, tmpStr.local8Bit()); // attendee and organizer stuff tmpStr = "MAILTO:" + anEvent->organizer(); addPropValue(vevent, ICOrganizerProp, tmpStr.local8Bit()); if (anEvent->attendeeCount() != 0) { QPtrList<Attendee> al = anEvent->attendees(); QPtrListIterator<Attendee> ai(al); Attendee *curAttendee; // TODO: Put this functionality into Attendee class for (; ai.current(); ++ai) { curAttendee = ai.current(); if (!curAttendee->email().isEmpty() && !curAttendee->name().isEmpty()) tmpStr = "MAILTO:" + curAttendee->name() + " <" + curAttendee->email() + ">"; else if (curAttendee->name().isEmpty()) tmpStr = "MAILTO: " + curAttendee->email(); else if (curAttendee->email().isEmpty()) tmpStr = "MAILTO: " + curAttendee->name(); else if (curAttendee->name().isEmpty() && curAttendee->email().isEmpty()) kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl; VObject *aProp = addPropValue(vevent, VCAttendeeProp, tmpStr.local8Bit()); addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE");; addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status())); } } // recurrence rule stuff if (anEvent->recurrence()->doesRecur()) { // some more variables QPtrList<Recurrence::rMonthPos> tmpPositions; QPtrList<int> tmpDays; int *tmpDay; Recurrence::rMonthPos *tmpPos; QString tmpStr2; int i; switch(anEvent->recurrence()->doesRecur()) { case Recurrence::rDaily: tmpStr.sprintf("D%i ",anEvent->recurrence()->frequency()); // if (anEvent->rDuration > 0) // tmpStr += "#"; break; case Recurrence::rWeekly: tmpStr.sprintf("W%i ",anEvent->recurrence()->frequency()); for (i = 0; i < 7; i++) { if (anEvent->recurrence()->days().testBit(i)) @@ -791,923 +793,928 @@ Todo *VCalFormat::VTodoToEvent(VObject *vtodo) if (strcmp(s,"COMPLETED") == 0) { anEvent->setCompleted(true); } else { anEvent->setCompleted(false); } deleteStr(s); } else anEvent->setCompleted(false); // completion date if ((vo = isAPropertyOf(vtodo, VCCompletedProp)) != 0) { anEvent->setCompleted(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } // priority if ((vo = isAPropertyOf(vtodo, VCPriorityProp))) { anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } // due date if ((vo = isAPropertyOf(vtodo, VCDueProp)) != 0) { anEvent->setDtDue(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); anEvent->setHasDueDate(true); } else { anEvent->setHasDueDate(false); } // start time if ((vo = isAPropertyOf(vtodo, VCDTstartProp)) != 0) { anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl; deleteStr(s); anEvent->setHasStartDate(true); } else { anEvent->setHasStartDate(false); } /* alarm stuff */ //kdDebug(5800) << "vcalformat::VTodoToEvent called" << endl; if ((vo = isAPropertyOf(vtodo, VCDAlarmProp))) { Alarm* alarm = anEvent->newAlarm(); VObject *a; if ((a = isAPropertyOf(vo, VCRunTimeProp))) { alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a)))); deleteStr(s); } alarm->setEnabled(true); if ((vo = isAPropertyOf(vtodo, VCPAlarmProp))) { if ((a = isAPropertyOf(vo, VCProcedureNameProp))) { s = fakeCString(vObjectUStringZValue(a)); alarm->setProcedureAlarm(QFile::decodeName(s)); deleteStr(s); } } if ((vo = isAPropertyOf(vtodo, VCAAlarmProp))) { if ((a = isAPropertyOf(vo, VCAudioContentProp))) { s = fakeCString(vObjectUStringZValue(a)); alarm->setAudioAlarm(QFile::decodeName(s)); deleteStr(s); } } } // related todo if ((vo = isAPropertyOf(vtodo, VCRelatedToProp)) != 0) { anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo))); deleteStr(s); mTodosRelate.append(anEvent); } // categories QStringList tmpStrList; int index1 = 0; int index2 = 0; if ((vo = isAPropertyOf(vtodo, VCCategoriesProp)) != 0) { s = fakeCString(vObjectUStringZValue(vo)); QString categories = QString::fromLocal8Bit(s); deleteStr(s); //const char* category; QString category; while ((index2 = categories.find(',', index1)) != -1) { //category = (const char *) categories.mid(index1, (index2 - index1)); category = categories.mid(index1, (index2 - index1)); tmpStrList.append(category); index1 = index2+1; } // get last category category = categories.mid(index1, (categories.length()-index1)); tmpStrList.append(category); anEvent->setCategories(tmpStrList); } /* PILOT SYNC STUFF */ if ((vo = isAPropertyOf(vtodo, XPilotIdProp))) { anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } else anEvent->setPilotId(0); if ((vo = isAPropertyOf(vtodo, XPilotStatusProp))) { anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } else anEvent->setSyncStatus(Event::SYNCMOD); return anEvent; } Event* VCalFormat::VEventToEvent(VObject *vevent) { VObject *vo; VObjectIterator voi; char *s; Event *anEvent = new Event; // creation date if ((vo = isAPropertyOf(vevent, VCDCreatedProp)) != 0) { anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } // unique id vo = isAPropertyOf(vevent, VCUniqueStringProp); // while the UID property is preferred, it is not required. We'll use the // default Event UID if none is given. if (vo) { anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo))); deleteStr(s); } // revision // again NSCAL doesn't give us much to work with, so we improvise... if ((vo = isAPropertyOf(vevent, VCSequenceProp)) != 0) { anEvent->setRevision(atoi(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } else anEvent->setRevision(0); // last modification date if ((vo = isAPropertyOf(vevent, VCLastModifiedProp)) != 0) { anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } else anEvent->setLastModified(QDateTime(QDate::currentDate(), QTime::currentTime())); // organizer // if our extension property for the event's ORGANIZER exists, add it. if ((vo = isAPropertyOf(vevent, ICOrganizerProp)) != 0) { anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo))); deleteStr(s); } else { anEvent->setOrganizer(mCalendar->getEmail()); } // deal with attendees. initPropIterator(&voi, vevent); while (moreIteration(&voi)) { vo = nextVObject(&voi); if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) { Attendee *a; VObject *vp; s = fakeCString(vObjectUStringZValue(vo)); QString tmpStr = QString::fromLocal8Bit(s); deleteStr(s); tmpStr = tmpStr.simplifyWhiteSpace(); int emailPos1, emailPos2; if ((emailPos1 = tmpStr.find('<')) > 0) { // both email address and name emailPos2 = tmpStr.findRev('>'); a = new Attendee(tmpStr.left(emailPos1 - 1), tmpStr.mid(emailPos1 + 1, emailPos2 - (emailPos1 + 1))); } else if (tmpStr.find('@') > 0) { // just an email address a = new Attendee(0, tmpStr); } else { // just a name QString email = tmpStr.replace( QRegExp(" "), "." ); a = new Attendee(tmpStr,email); } // is there an RSVP property? if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0) a->setRSVP(vObjectStringZValue(vp)); // is there a status property? if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0) a->setStatus(readStatus(vObjectStringZValue(vp))); // add the attendee anEvent->addAttendee(a); } } // This isn't strictly true. An event that doesn't have a start time // or an end time doesn't "float", it has an anchor in time but it doesn't // "take up" any time. /*if ((isAPropertyOf(vevent, VCDTstartProp) == 0) || (isAPropertyOf(vevent, VCDTendProp) == 0)) { anEvent->setFloats(TRUE); } else { }*/ anEvent->setFloats(FALSE); // start time if ((vo = isAPropertyOf(vevent, VCDTstartProp)) != 0) { anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl; deleteStr(s); if (anEvent->dtStart().time().isNull()) anEvent->setFloats(TRUE); } // stop time if ((vo = isAPropertyOf(vevent, VCDTendProp)) != 0) { anEvent->setDtEnd(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); if (anEvent->dtEnd().time().isNull()) anEvent->setFloats(TRUE); } // at this point, there should be at least a start or end time. // fix up for events that take up no time but have a time associated if (!(vo = isAPropertyOf(vevent, VCDTstartProp))) anEvent->setDtStart(anEvent->dtEnd()); if (!(vo = isAPropertyOf(vevent, VCDTendProp))) anEvent->setDtEnd(anEvent->dtStart()); /////////////////////////////////////////////////////////////////////////// // repeat stuff if ((vo = isAPropertyOf(vevent, VCRRuleProp)) != 0) { QString tmpStr = (s = fakeCString(vObjectUStringZValue(vo))); deleteStr(s); tmpStr.simplifyWhiteSpace(); tmpStr = tmpStr.upper(); /********************************* DAILY ******************************/ if (tmpStr.left(1) == "D") { int index = tmpStr.find(' '); int rFreq = tmpStr.mid(1, (index-1)).toInt(); index = tmpStr.findRev(' ') + 1; // advance to last field if (tmpStr.mid(index,1) == "#") index++; if (tmpStr.find('T', index) != -1) { QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); anEvent->recurrence()->setDaily(rFreq, rEndDate); } else { int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); if (rDuration == 0) // VEvents set this to 0 forever, we use -1 anEvent->recurrence()->setDaily(rFreq, -1); else anEvent->recurrence()->setDaily(rFreq, rDuration); } } /********************************* WEEKLY ******************************/ else if (tmpStr.left(1) == "W") { int index = tmpStr.find(' '); int last = tmpStr.findRev(' ') + 1; int rFreq = tmpStr.mid(1, (index-1)).toInt(); index += 1; // advance to beginning of stuff after freq QBitArray qba(7); QString dayStr; if( index == last ) { // e.g. W1 #0 qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1); } else { // e.g. W1 SU #0 while (index < last) { dayStr = tmpStr.mid(index, 3); int dayNum = numFromDay(dayStr); qba.setBit(dayNum); index += 3; // advance to next day, or possibly "#" } } index = last; if (tmpStr.mid(index,1) == "#") index++; if (tmpStr.find('T', index) != -1) { QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); anEvent->recurrence()->setWeekly(rFreq, qba, rEndDate); } else { int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); if (rDuration == 0) anEvent->recurrence()->setWeekly(rFreq, qba, -1); else anEvent->recurrence()->setWeekly(rFreq, qba, rDuration); } } /**************************** MONTHLY-BY-POS ***************************/ else if (tmpStr.left(2) == "MP") { int index = tmpStr.find(' '); int last = tmpStr.findRev(' ') + 1; int rFreq = tmpStr.mid(2, (index-1)).toInt(); index += 1; // advance to beginning of stuff after freq QBitArray qba(7); short tmpPos; if( index == last ) { // e.g. MP1 #0 tmpPos = anEvent->dtStart().date().day()/7 + 1; if( tmpPos == 5 ) tmpPos = -1; qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1); anEvent->recurrence()->addMonthlyPos(tmpPos, qba); } else { // e.g. MP1 1+ SU #0 while (index < last) { tmpPos = tmpStr.mid(index,1).toShort(); index += 1; if (tmpStr.mid(index,1) == "-") // convert tmpPos to negative tmpPos = 0 - tmpPos; index += 2; // advance to day(s) while (numFromDay(tmpStr.mid(index,3)) >= 0) { int dayNum = numFromDay(tmpStr.mid(index,3)); qba.setBit(dayNum); index += 3; // advance to next day, or possibly pos or "#" } anEvent->recurrence()->addMonthlyPos(tmpPos, qba); qba.detach(); qba.fill(FALSE); // clear out } // while != "#" } index = last; if (tmpStr.mid(index,1) == "#") index++; if (tmpStr.find('T', index) != -1) { QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length() - index))).date(); anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rEndDate); } else { int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); if (rDuration == 0) anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, -1); else anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rDuration); } } /**************************** MONTHLY-BY-DAY ***************************/ else if (tmpStr.left(2) == "MD") { int index = tmpStr.find(' '); int last = tmpStr.findRev(' ') + 1; int rFreq = tmpStr.mid(2, (index-1)).toInt(); index += 1; short tmpDay; if( index == last ) { // e.g. MD1 #0 tmpDay = anEvent->dtStart().date().day(); anEvent->recurrence()->addMonthlyDay(tmpDay); } else { // e.g. MD1 3 #0 while (index < last) { int index2 = tmpStr.find(' ', index); tmpDay = tmpStr.mid(index, (index2-index)).toShort(); index = index2-1; if (tmpStr.mid(index, 1) == "-") tmpDay = 0 - tmpDay; index += 2; // advance the index; anEvent->recurrence()->addMonthlyDay(tmpDay); } // while != # } index = last; if (tmpStr.mid(index,1) == "#") index++; if (tmpStr.find('T', index) != -1) { QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rEndDate); } else { int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); if (rDuration == 0) anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, -1); else anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rDuration); } } /*********************** YEARLY-BY-MONTH *******************************/ else if (tmpStr.left(2) == "YM") { - int index = tmpStr.find(' '); - int last = tmpStr.findRev(' ') + 1; - int rFreq = tmpStr.mid(2, (index-1)).toInt(); - index += 1; - short tmpMonth; - if( index == last ) { - // e.g. YM1 #0 - tmpMonth = anEvent->dtStart().date().month(); - anEvent->recurrence()->addYearlyNum(tmpMonth); - } - else { - // e.g. YM1 3 #0 - while (index < last) { - int index2 = tmpStr.find(' ', index); - tmpMonth = tmpStr.mid(index, (index2-index)).toShort(); - index = index2+1; - anEvent->recurrence()->addYearlyNum(tmpMonth); - } // while != # - } - index = last; if (tmpStr.mid(index,1) == "#") index++; - if (tmpStr.find('T', index) != -1) { - QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); - anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rEndDate); - } else { - int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); - if (rDuration == 0) - anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, -1); - else - anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rDuration); - } + // we have to set this such that recurrence accepts addYearlyNum(tmpDay); + anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, 1, -1); + int index = tmpStr.find(' '); + int last = tmpStr.findRev(' ') + 1; + int rFreq = tmpStr.mid(2, (index-1)).toInt(); + index += 1; + short tmpMonth; + if( index == last ) { + // e.g. YM1 #0 + tmpMonth = anEvent->dtStart().date().month(); + anEvent->recurrence()->addYearlyNum(tmpMonth); + } + else { + // e.g. YM1 3 #0 + while (index < last) { + int index2 = tmpStr.find(' ', index); + tmpMonth = tmpStr.mid(index, (index2-index)).toShort(); + index = index2+1; + anEvent->recurrence()->addYearlyNum(tmpMonth); + } // while != # + } + index = last; if (tmpStr.mid(index,1) == "#") index++; + if (tmpStr.find('T', index) != -1) { + QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); + anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rEndDate); + } else { + int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); + if (rDuration == 0) + anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, -1); + else + anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rDuration); + } } /*********************** YEARLY-BY-DAY *********************************/ else if (tmpStr.left(2) == "YD") { - int index = tmpStr.find(' '); - int last = tmpStr.findRev(' ') + 1; - int rFreq = tmpStr.mid(2, (index-1)).toInt(); - index += 1; - short tmpDay; - if( index == last ) { - // e.g. YD1 #0 - tmpDay = anEvent->dtStart().date().dayOfYear(); - anEvent->recurrence()->addYearlyNum(tmpDay); - } - else { - // e.g. YD1 123 #0 - while (index < last) { - int index2 = tmpStr.find(' ', index); - tmpDay = tmpStr.mid(index, (index2-index)).toShort(); - index = index2+1; - anEvent->recurrence()->addYearlyNum(tmpDay); - } // while != # - } - index = last; if (tmpStr.mid(index,1) == "#") index++; - if (tmpStr.find('T', index) != -1) { - QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); - anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rEndDate); - } else { - int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); - if (rDuration == 0) - anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, -1); - else - anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rDuration); - } + // we have to set this such that recurrence accepts addYearlyNum(tmpDay); + anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, 1, -1); + int index = tmpStr.find(' '); + int last = tmpStr.findRev(' ') + 1; + int rFreq = tmpStr.mid(2, (index-1)).toInt(); + index += 1; + short tmpDay; + if( index == last ) { + // e.g. YD1 #0 + tmpDay = anEvent->dtStart().date().dayOfYear(); + anEvent->recurrence()->addYearlyNum(tmpDay); + } + else { + // e.g. YD1 123 #0 + while (index < last) { + int index2 = tmpStr.find(' ', index); + tmpDay = tmpStr.mid(index, (index2-index)).toShort(); + index = index2+1; + anEvent->recurrence()->addYearlyNum(tmpDay); + } // while != # + } + index = last; if (tmpStr.mid(index,1) == "#") index++; + if (tmpStr.find('T', index) != -1) { + QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date(); + anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rEndDate); + } else { + int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt(); + if (rDuration == 0) + anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, -1); + else + anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rDuration); + } } else { - kdDebug(5800) << "we don't understand this type of recurrence!" << endl; + kdDebug(5800) << "we don't understand this type of recurrence!" << endl; } // if } // repeats // recurrence exceptions if ((vo = isAPropertyOf(vevent, VCExpDateProp)) != 0) { s = fakeCString(vObjectUStringZValue(vo)); QStringList exDates = QStringList::split(",",s); QStringList::ConstIterator it; for(it = exDates.begin(); it != exDates.end(); ++it ) { anEvent->addExDate(ISOToQDate(*it)); } deleteStr(s); } // summary if ((vo = isAPropertyOf(vevent, VCSummaryProp))) { s = fakeCString(vObjectUStringZValue(vo)); anEvent->setSummary(QString::fromLocal8Bit(s)); deleteStr(s); } if ((vo = isAPropertyOf(vevent, VCLocationProp))) { s = fakeCString(vObjectUStringZValue(vo)); anEvent->setLocation(QString::fromLocal8Bit(s)); deleteStr(s); } // description if ((vo = isAPropertyOf(vevent, VCDescriptionProp)) != 0) { s = fakeCString(vObjectUStringZValue(vo)); if (!anEvent->description().isEmpty()) { anEvent->setDescription(anEvent->description() + "\n" + QString::fromLocal8Bit(s)); } else { anEvent->setDescription(QString::fromLocal8Bit(s)); } deleteStr(s); } // some stupid vCal exporters ignore the standard and use Description // instead of Summary for the default field. Correct for this. if (anEvent->summary().isEmpty() && !(anEvent->description().isEmpty())) { QString tmpStr = anEvent->description().simplifyWhiteSpace(); anEvent->setDescription(""); anEvent->setSummary(tmpStr); } #if 0 // status if ((vo = isAPropertyOf(vevent, VCStatusProp)) != 0) { QString tmpStr(s = fakeCString(vObjectUStringZValue(vo))); deleteStr(s); // TODO: Define Event status // anEvent->setStatus(tmpStr); } else // anEvent->setStatus("NEEDS ACTION"); #endif // secrecy int secrecy = Incidence::SecrecyPublic; if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) { s = fakeCString(vObjectUStringZValue(vo)); if (strcmp(s,"PRIVATE") == 0) { secrecy = Incidence::SecrecyPrivate; } else if (strcmp(s,"CONFIDENTIAL") == 0) { secrecy = Incidence::SecrecyConfidential; } deleteStr(s); } anEvent->setSecrecy(secrecy); // categories QStringList tmpStrList; int index1 = 0; int index2 = 0; if ((vo = isAPropertyOf(vevent, VCCategoriesProp)) != 0) { s = fakeCString(vObjectUStringZValue(vo)); QString categories = QString::fromLocal8Bit(s); deleteStr(s); //const char* category; QString category; while ((index2 = categories.find(',', index1)) != -1) { //category = (const char *) categories.mid(index1, (index2 - index1)); category = categories.mid(index1, (index2 - index1)); tmpStrList.append(category); index1 = index2+1; } // get last category category = categories.mid(index1, (categories.length()-index1)); tmpStrList.append(category); anEvent->setCategories(tmpStrList); } // attachments tmpStrList.clear(); initPropIterator(&voi, vevent); while (moreIteration(&voi)) { vo = nextVObject(&voi); if (strcmp(vObjectName(vo), VCAttachProp) == 0) { s = fakeCString(vObjectUStringZValue(vo)); anEvent->addAttachment(new Attachment(QString(s))); deleteStr(s); } } // resources if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) { QString resources = (s = fakeCString(vObjectUStringZValue(vo))); deleteStr(s); tmpStrList.clear(); index1 = 0; index2 = 0; QString resource; while ((index2 = resources.find(';', index1)) != -1) { resource = resources.mid(index1, (index2 - index1)); tmpStrList.append(resource); index1 = index2; } anEvent->setResources(tmpStrList); } /* alarm stuff */ if ((vo = isAPropertyOf(vevent, VCDAlarmProp))) { Alarm* alarm = anEvent->newAlarm(); VObject *a; if ((a = isAPropertyOf(vo, VCRunTimeProp))) { alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a)))); deleteStr(s); } alarm->setEnabled(true); if ((vo = isAPropertyOf(vevent, VCPAlarmProp))) { if ((a = isAPropertyOf(vo, VCProcedureNameProp))) { s = fakeCString(vObjectUStringZValue(a)); alarm->setProcedureAlarm(QFile::decodeName(s)); deleteStr(s); } } if ((vo = isAPropertyOf(vevent, VCAAlarmProp))) { if ((a = isAPropertyOf(vo, VCAudioContentProp))) { s = fakeCString(vObjectUStringZValue(a)); alarm->setAudioAlarm(QFile::decodeName(s)); deleteStr(s); } } } // priority if ((vo = isAPropertyOf(vevent, VCPriorityProp))) { anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } // transparency if ((vo = isAPropertyOf(vevent, VCTranspProp)) != 0) { int i = atoi(s = fakeCString(vObjectUStringZValue(vo))); anEvent->setTransparency( i == 1 ? Event::Transparent : Event::Opaque ); deleteStr(s); } // related event if ((vo = isAPropertyOf(vevent, VCRelatedToProp)) != 0) { anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo))); deleteStr(s); mEventsRelate.append(anEvent); } /* PILOT SYNC STUFF */ if ((vo = isAPropertyOf(vevent, XPilotIdProp))) { anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } else anEvent->setPilotId(0); if ((vo = isAPropertyOf(vevent, XPilotStatusProp))) { anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } else anEvent->setSyncStatus(Event::SYNCMOD); return anEvent; } QString VCalFormat::qDateToISO(const QDate &qd) { QString tmpStr; ASSERT(qd.isValid()); tmpStr.sprintf("%.2d%.2d%.2d", qd.year(), qd.month(), qd.day()); return tmpStr; } QString VCalFormat::qDateTimeToISO(const QDateTime &qdt, bool zulu) { QString tmpStr; ASSERT(qdt.date().isValid()); ASSERT(qdt.time().isValid()); if (zulu && !useLocalTime ) { QDateTime tmpDT = qdt.addSecs ( -KGlobal::locale()->localTimeOffset( qdt )*60); tmpStr.sprintf("%.2d%.2d%.2dT%.2d%.2d%.2dZ", tmpDT.date().year(), tmpDT.date().month(), tmpDT.date().day(), tmpDT.time().hour(), tmpDT.time().minute(), tmpDT.time().second()); } else { tmpStr.sprintf("%.2d%.2d%.2dT%.2d%.2d%.2d", qdt.date().year(), qdt.date().month(), qdt.date().day(), qdt.time().hour(), qdt.time().minute(), qdt.time().second()); } return tmpStr; } QDateTime VCalFormat::ISOToQDateTime(const QString & dtStr) { QDate tmpDate; QTime tmpTime; QString tmpStr; int year, month, day, hour, minute, second; tmpStr = dtStr; year = tmpStr.left(4).toInt(); month = tmpStr.mid(4,2).toInt(); day = tmpStr.mid(6,2).toInt(); hour = tmpStr.mid(9,2).toInt(); minute = tmpStr.mid(11,2).toInt(); second = tmpStr.mid(13,2).toInt(); tmpDate.setYMD(year, month, day); tmpTime.setHMS(hour, minute, second); ASSERT(tmpDate.isValid()); ASSERT(tmpTime.isValid()); QDateTime tmpDT(tmpDate, tmpTime); // correct for GMT if string is in Zulu format if (dtStr.at(dtStr.length()-1) == 'Z') tmpDT = tmpDT.addSecs (KGlobal::locale()->localTimeOffset( tmpDT )*60); return tmpDT; } QDate VCalFormat::ISOToQDate(const QString &dateStr) { int year, month, day; year = dateStr.left(4).toInt(); month = dateStr.mid(4,2).toInt(); day = dateStr.mid(6,2).toInt(); return(QDate(year, month, day)); } // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc. // and break it down from it's tree-like format into the dictionary format // that is used internally in the VCalFormat. void VCalFormat::populate(VObject *vcal) { // this function will populate the caldict dictionary and other event // lists. It turns vevents into Events and then inserts them. VObjectIterator i; VObject *curVO, *curVOProp; Event *anEvent; if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) { char *methodType = 0; methodType = fakeCString(vObjectUStringZValue(curVO)); kdDebug() << "This calendar is an iTIP transaction of type '" << methodType << "'" << endl; delete methodType; } // warn the user that we might have trouble reading non-known calendar. if ((curVO = isAPropertyOf(vcal, VCProdIdProp)) != 0) { char *s = fakeCString(vObjectUStringZValue(curVO)); if (strcmp(productId().local8Bit(), s) != 0) kdDebug() << "This vCalendar file was not created by KOrganizer " "or any other product we support. Loading anyway..." << endl; mLoadedProductId = s; deleteStr(s); } // warn the user we might have trouble reading this unknown version. if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) { char *s = fakeCString(vObjectUStringZValue(curVO)); if (strcmp(_VCAL_VERSION, s) != 0) kdDebug() << "This vCalendar file has version " << s << "We only support " << _VCAL_VERSION << endl; deleteStr(s); } // set the time zone if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) { - char *s = fakeCString(vObjectUStringZValue(curVO)); - mCalendar->setTimeZone(s); - deleteStr(s); + if ( vObjectUStringZValue(curVO) != 0 ) { + char *s = fakeCString(vObjectUStringZValue(curVO)); + mCalendar->setTimeZone(s); + deleteStr(s); + } } - // Store all events with a relatedTo property in a list for post-processing mEventsRelate.clear(); mTodosRelate.clear(); initPropIterator(&i, vcal); // go through all the vobjects in the vcal while (moreIteration(&i)) { curVO = nextVObject(&i); /************************************************************************/ // now, check to see that the object is an event or todo. if (strcmp(vObjectName(curVO), VCEventProp) == 0) { if ((curVOProp = isAPropertyOf(curVO, XPilotStatusProp)) != 0) { char *s; s = fakeCString(vObjectUStringZValue(curVOProp)); // check to see if event was deleted by the kpilot conduit if (atoi(s) == Event::SYNCDEL) { deleteStr(s); kdDebug(5800) << "skipping pilot-deleted event" << endl; goto SKIP; } deleteStr(s); } // this code checks to see if we are trying to read in an event // that we already find to be in the calendar. If we find this // to be the case, we skip the event. if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) { char *s = fakeCString(vObjectUStringZValue(curVOProp)); QString tmpStr(s); deleteStr(s); if (mCalendar->event(tmpStr)) { goto SKIP; } if (mCalendar->todo(tmpStr)) { goto SKIP; } } if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) && (!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) { kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl; goto SKIP; } anEvent = VEventToEvent(curVO); // we now use addEvent instead of insertEvent so that the // signal/slot get connected. if (anEvent) { if ( !anEvent->dtStart().isValid() || !anEvent->dtEnd().isValid() ) { kdDebug() << "VCalFormat::populate(): Event has invalid dates." << endl; } else { mCalendar->addEvent(anEvent); } } else { // some sort of error must have occurred while in translation. goto SKIP; } } else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) { Todo *aTodo = VTodoToEvent(curVO); mCalendar->addTodo(aTodo); } else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) || (strcmp(vObjectName(curVO), VCProdIdProp) == 0) || (strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) { // do nothing, we know these properties and we want to skip them. // we have either already processed them or are ignoring them. ; } else { kdDebug(5800) << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\"" << endl; } SKIP: ; } // while // Post-Process list of events with relations, put Event objects in relation Event *ev; for ( ev=mEventsRelate.first(); ev != 0; ev=mEventsRelate.next() ) { ev->setRelatedTo(mCalendar->event(ev->relatedToUid())); } Todo *todo; for ( todo=mTodosRelate.first(); todo != 0; todo=mTodosRelate.next() ) { todo->setRelatedTo(mCalendar->todo(todo->relatedToUid())); } } const char *VCalFormat::dayFromNum(int day) { const char *days[7] = { "MO ", "TU ", "WE ", "TH ", "FR ", "SA ", "SU " }; return days[day]; } int VCalFormat::numFromDay(const QString &day) { if (day == "MO ") return 0; if (day == "TU ") return 1; if (day == "WE ") return 2; if (day == "TH ") return 3; if (day == "FR ") return 4; if (day == "SA ") return 5; if (day == "SU ") return 6; return -1; // something bad happened. :) } Attendee::PartStat VCalFormat::readStatus(const char *s) const { QString statStr = s; statStr = statStr.upper(); Attendee::PartStat status; if (statStr == "X-ACTION") status = Attendee::NeedsAction; else if (statStr == "NEEDS ACTION") status = Attendee::NeedsAction; else if (statStr== "ACCEPTED") status = Attendee::Accepted; else if (statStr== "SENT") status = Attendee::NeedsAction; else if (statStr== "TENTATIVE") status = Attendee::Tentative; else if (statStr== "CONFIRMED") status = Attendee::Accepted; else if (statStr== "DECLINED") status = Attendee::Declined; else if (statStr== "COMPLETED") status = Attendee::Completed; else if (statStr== "DELEGATED") status = Attendee::Delegated; else { kdDebug(5800) << "error setting attendee mStatus, unknown mStatus!" << endl; status = Attendee::NeedsAction; } return status; } QCString VCalFormat::writeStatus(Attendee::PartStat status) const { switch(status) { default: case Attendee::NeedsAction: return "NEEDS ACTION"; break; case Attendee::Accepted: return "ACCEPTED"; break; case Attendee::Declined: return "DECLINED"; break; case Attendee::Tentative: return "TENTATIVE"; break; case Attendee::Delegated: return "DELEGATED"; break; case Attendee::Completed: return "COMPLETED"; break; case Attendee::InProcess: return "NEEDS ACTION"; break; } } |