author | zautrix <zautrix> | 2004-08-20 04:28:28 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2004-08-20 04:28:28 (UTC) |
commit | 93decd4185adc7197008e8397cf753a5ab674d99 (patch) (side-by-side diff) | |
tree | 0d701d0a687c22cfe2894121f8540d60a5fbe7a9 /libkcal | |
parent | f7a401f03c18ef96eb40dc5540b31cd10880e845 (diff) | |
download | kdepimpi-93decd4185adc7197008e8397cf753a5ab674d99.zip kdepimpi-93decd4185adc7197008e8397cf753a5ab674d99.tar.gz kdepimpi-93decd4185adc7197008e8397cf753a5ab674d99.tar.bz2 |
Bugfixes for syncing
-rw-r--r-- | libkcal/phoneformat.cpp | 328 | ||||
-rw-r--r-- | libkcal/sharpformat.cpp | 2 | ||||
-rw-r--r-- | libkcal/vcalformat.cpp | 21 |
3 files changed, 294 insertions, 57 deletions
diff --git a/libkcal/phoneformat.cpp b/libkcal/phoneformat.cpp index 6bbc0a3..6276498 100644 --- a/libkcal/phoneformat.cpp +++ b/libkcal/phoneformat.cpp @@ -1,1427 +1,1659 @@ /* 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. */ #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 <qxml.h> #include <qlabel.h> #include <kdebug.h> #include <klocale.h> #include <kglobal.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( Calendar *calendar, QString profileName ) : mCalendar( calendar ), mProfileName ( profileName ) { ; } bool readTodo( Calendar *existingCalendar,GSM_ToDoEntry *ToDo, GSM_StateMachine* s) { int id = ToDo->Location; Todo *todo; todo = existingCalendar->todo( mProfileName ,QString::number( id ) ); if (todo ) todo = (Todo *)todo->clone(); else todo = new Todo; todo->setID( mProfileName,QString::number( id ) ); todo->setTempSyncStat(SYNC_TEMPSTATE_NEW_EXTERNAL ); int priority; switch (ToDo->Priority) { case GSM_Priority_Low : priority = 5; break; case GSM_Priority_Medium : priority = 3; break; case GSM_Priority_High : priority = 1; break; default :priority = 3 ; break; } todo->setPriority( priority ); GSM_Phone_Functions *Phone; Phone=s->Phone.Functions; int j; GSM_DateTime* dtp; bool alarm = false; QDateTime alarmDt; GSM_Category Category; int error; for (j=0;j<ToDo->EntriesNum;j++) { //qDebug(" for todo %d",ToDo->Location ); switch (ToDo->Entries[j].EntryType) { case TODO_END_DATETIME: dtp = &ToDo->Entries[j].Date ; todo->setDtDue (fromGSM ( dtp )); break; case TODO_COMPLETED: if ( ToDo->Entries[j].Number == 1 ) { todo->setCompleted( true ); } else { todo->setCompleted( false ); } break; case TODO_ALARM_DATETIME: dtp = &ToDo->Entries[j].Date ; alarm = true; alarmDt = fromGSM ( dtp ); break; case TODO_SILENT_ALARM_DATETIME: dtp = &ToDo->Entries[j].Date ; alarm = true; alarmDt = fromGSM ( dtp ); break; case TODO_TEXT: //qDebug(" text *%s* ", (const char*) DecodeUnicodeConsole(ToDo->Entries[j].Text )); todo->setSummary( QString::fromUtf8 ( (const char*)DecodeUnicodeConsole(ToDo->Entries[j].Text ))); break; case TODO_PRIVATE: if ( ToDo->Entries[j].Number == 1 ) todo->setSecrecy( Incidence::SecrecyPrivate ); else todo->setSecrecy( Incidence::SecrecyPublic ); break; case TODO_CATEGORY: Category.Location = ToDo->Entries[j].Number; Category.Type = Category_ToDo; error=Phone->GetCategory(s, &Category); if (error == ERR_NONE) { QStringList cat = todo->categories(); QString nCat = QString ( (const char*)Category.Name ); if ( !nCat.isEmpty() ) if ( !cat.contains( nCat )) { cat << nCat; todo->setCategories( cat ); } } break; case TODO_CONTACTID: #if 0 // not supported entry.Location = ToDo->Entries[j].Number; entry.MemoryType = MEM_ME; error=Phone->GetMemory(s, &entry); if (error == ERR_NONE) { name = GSM_PhonebookGetEntryName(&entry); if (name != NULL) { printmsg("Contact ID : \"%s\" (%d)\n", DecodeUnicodeConsole(name), ToDo->Entries[j].Number); } else { printmsg("Contact ID : %d\n",ToDo->Entries[j].Number); } } else { printmsg("Contact : %d\n",ToDo->Entries[j].Number); } #endif break; case TODO_PHONE: #if 0 // not supported printmsg("Phone : \"%s\"\n",DecodeUnicodeConsole(ToDo->Entries[j].Text)); #endif break; } } QString alarmString = "na"; if ( alarm ) { Alarm *alarm; if ( todo->alarms().count() > 0 ) alarm = todo->alarms().first(); else { alarm = new Alarm( todo ); todo->addAlarm( alarm ); } alarm->setType( Alarm::Audio ); alarm->setEnabled( true ); int alarmOffset = alarmDt.secsTo( todo->dtStart() ); alarm->setStartOffset( -alarmOffset ); alarmString = QString::number( alarmOffset ); } else { Alarm *alarm; if ( todo->alarms().count() > 0 ) { alarm = todo->alarms().first(); alarm->setType( Alarm::Audio ); alarm->setStartOffset( -60*15 ); alarm->setEnabled( false ); } } // csum ***************************************** uint cSum; cSum = PhoneFormat::getCsumTodo( todo ); todo->setCsum( mProfileName, QString::number( cSum )); todo->setTempSyncStat( SYNC_TEMPSTATE_NEW_EXTERNAL ); mCalendar->addTodo( todo); return true; } bool readEvent( Calendar *existingCalendar, GSM_CalendarEntry* Note) { int id = Note->Location; Event *event; event = existingCalendar->event( mProfileName ,QString::number( id ) ); if ( event ) event = (Event*)event->clone(); else event = new Event; event->setID( mProfileName,QString::number( id ) ); event->setTempSyncStat(SYNC_TEMPSTATE_NEW_EXTERNAL ); int i = 0; bool repeating = false; int repeat_dayofweek = -1; int repeat_day = -1; int repeat_weekofmonth = -1; int repeat_month = -1; int repeat_frequency = -1; int rec_type = -1; GSM_DateTime repeat_startdate = {0,0,0,0,0,0,0}; GSM_DateTime repeat_stopdate = {0,0,0,0,0,0,0}; GSM_DateTime* dtp; bool alarm = false; QDateTime alarmDt; repeat_startdate.Day = 0; repeat_stopdate.Day = 0; for (i=0;i<Note->EntriesNum;i++) { //qDebug(" for ev"); switch (Note->Entries[i].EntryType) { case CAL_START_DATETIME: dtp = &Note->Entries[i].Date ; if ( dtp->Hour > 24 ) { event->setFloats( true ); event->setDtStart( QDateTime (datefromGSM ( dtp ), QTime(0,0,0 ))); } else { event->setDtStart (fromGSM ( dtp )); } //Note->Entries[i].Date.Hour = 5; break; case CAL_END_DATETIME: dtp = &Note->Entries[i].Date ; if ( dtp->Hour > 24 ) { event->setFloats( true ); event->setDtEnd( QDateTime (datefromGSM ( dtp ), QTime(0,0,0 ))); } else { event->setDtEnd (fromGSM ( dtp )); } break; case CAL_ALARM_DATETIME: dtp = &Note->Entries[i].Date ; alarm = true; alarmDt = fromGSM ( dtp ); break; case CAL_SILENT_ALARM_DATETIME: dtp = &Note->Entries[i].Date ; alarm = true; alarmDt = fromGSM ( dtp ); break; case CAL_RECURRANCE: rec_type = Note->Entries[i].Number; //printmsg("Repeat : %d day%s\n",Note->Entries[i].Number/24,((Note->Entries[i].Number/24)>1) ? "s":"" ); break; case CAL_TEXT: //qDebug(" ev text %s", DecodeUnicodeConsole(Note->Entries[i].Text) ); event->setSummary( QString::fromUtf8 ( (const char*)DecodeUnicodeConsole( Note->Entries[i].Text ))); break; case CAL_LOCATION: event->setLocation(QString::fromUtf8 ((const char*) DecodeUnicodeConsole(Note->Entries[i].Text) )); break; case CAL_PHONE: //printmsg("Phone : \"%s\"\n",DecodeUnicodeConsole(Note->Entries[i].Text)); break; case CAL_PRIVATE: if ( Note->Entries[i].Number == 1 ) event->setSecrecy( Incidence::SecrecyPrivate ); else event->setSecrecy( Incidence::SecrecyPublic ); break; case CAL_CONTACTID: #if 0 entry.Location = Note->Entries[i].Number; entry.MemoryType = MEM_ME; error=Phone->GetMemory(&s, &entry); if (error == ERR_NONE) { name = GSM_PhonebookGetEntryName(&entry); if (name != NULL) { //printmsg("Contact ID : \"%s\" (%d)\n", DecodeUnicodeConsole(name), Note->Entries[i].Number); } else { //printmsg("Contact ID : %d\n",Note->Entries[i].Number); } } else { //printmsg("Contact ID : %d\n",Note->Entries[i].Number); } #endif break; case CAL_REPEAT_DAYOFWEEK: repeat_dayofweek = Note->Entries[i].Number; repeating = true; break; case CAL_REPEAT_DAY: repeat_day = Note->Entries[i].Number; repeating = true; break; case CAL_REPEAT_WEEKOFMONTH: repeat_weekofmonth = Note->Entries[i].Number; repeating = true; break; case CAL_REPEAT_MONTH: repeat_month = Note->Entries[i].Number; repeating = true; break; case CAL_REPEAT_FREQUENCY: repeat_frequency = Note->Entries[i].Number; repeating = true; break; case CAL_REPEAT_STARTDATE: repeat_startdate = Note->Entries[i].Date; repeating = true; break; case CAL_REPEAT_STOPDATE: repeat_stopdate = Note->Entries[i].Date; repeating = true; break; } } #if 0 event->setDescription( attList[4] ); bool repeating = false; int repeat_dayofweek = -1; int repeat_day = -1; int repeat_weekofmonth = -1; int repeat_month = -1; int repeat_frequency = -1; GSM_DateTime repeat_startdate = {0,0,0,0,0,0,0}; GSM_DateTime repeat_stopdate = {0,0,0,0,0,0,0}; #endif QString recurString = "no"; if ( repeating && repeat_frequency != -1) { recurString = "y"; if ( repeat_dayofweek >= 0 ) recurString += "dow" + QString::number (repeat_dayofweek); if ( repeat_day >= 0 ) recurString += "d" + QString::number (repeat_day); if ( repeat_weekofmonth >= 0 ) recurString += "w" + QString::number (repeat_weekofmonth); if ( repeat_month >= 0 ) recurString += "m" + QString::number ( repeat_month ); if ( repeat_frequency >= 0 ) recurString += "f" + QString::number (repeat_frequency ); int rtype = 0; // qDebug("recurs "); QDate startDate, endDate; if ( repeat_startdate.Day > 0 ) { startDate = datefromGSM ( &repeat_startdate ); event->setDtStart(QDateTime ( startDate, event->dtStart().time())); } else { startDate = event->dtStart().date(); } int freq = repeat_frequency; bool hasEndDate = false; if ( repeat_stopdate.Day > 0 ) { endDate = datefromGSM ( &repeat_stopdate ); hasEndDate = true; } uint weekDaysNum = repeat_dayofweek ; // 1 == monday, 7 == sunday QBitArray weekDays( 7 ); int i; int bb = 1; for( i = 1; i <= 7; ++i ) { weekDays.setBit( i - 1, ( bb & weekDaysNum )); bb = 2 << (i-1); //qDebug(" %d bit %d ",i-1,weekDays.at(i-1) ); } // qDebug("next "); int pos = 0; Recurrence *r = event->recurrence(); /* 0 daily; 1 weekly;x 2 monthpos;x 3 monthlyday; 4 rYearlyMont bool repeating = false; int repeat_dayofweek = -1; int repeat_day = -1; int repeat_weekofmonth = -1; int repeat_month = -1; int repeat_frequency = -1; */ int dayOfWeek = startDate.dayOfWeek(); if ( repeat_weekofmonth >= 0 ) { rtype = 2; // ************************ 2 MonthlyPos pos = repeat_weekofmonth; if ( repeat_dayofweek >= 0 ) dayOfWeek = repeat_dayofweek; if (repeat_month > 0) { if ( repeat_month != event->dtStart().date().month() ) { QDate date (event->dtStart().date().year(),repeat_month,event->dtStart().date().day() ); event->setDtStart(QDateTime ( date , event->dtStart().time()) ); } if ( freq == 1 ) freq = 12; } } else if ( repeat_dayofweek >= 0 ) { rtype = 1;// ************************ 1 Weekly } else if ( repeat_day >= 0 ) { if ( repeat_month > 0) { rtype = 4; } else { rtype = 3; } } else { rtype = 0 ; } if ( rtype == 0 ) { if ( hasEndDate ) r->setDaily( freq, endDate ); else r->setDaily( freq, -1 ); } else if ( rtype == 1 ) { if ( hasEndDate ) r->setWeekly( freq, weekDays, endDate ); else r->setWeekly( freq, weekDays, -1 ); } else if ( rtype == 3 ) { if ( hasEndDate ) r->setMonthly( Recurrence::rMonthlyDay, freq, endDate ); else r->setMonthly( Recurrence::rMonthlyDay, freq, -1 ); r->addMonthlyDay( startDate.day() ); } else if ( rtype == 2 ) { if ( hasEndDate ) r->setMonthly( Recurrence::rMonthlyPos, freq, endDate ); else r->setMonthly( Recurrence::rMonthlyPos, freq, -1 ); QBitArray days( 7 ); days.fill( false ); days.setBit( dayOfWeek - 1 ); r->addMonthlyPos( pos, days ); } else if ( rtype == 4 ) { if ( hasEndDate ) r->setYearly( Recurrence::rYearlyMonth, freq, endDate ); else r->setYearly( Recurrence::rYearlyMonth, freq, -1 ); r->addYearlyNum( startDate.month() ); } } else { event->recurrence()->unsetRecurs(); } QStringList categoryList; categoryList << getCategory( Note ); event->setCategories( categoryList ); // strange 0 semms to mean: alarm enabled if ( alarm ) { Alarm *alarm; if ( event->alarms().count() > 0 ) alarm = event->alarms().first(); else { alarm = new Alarm( event ); event->addAlarm( alarm ); } alarm->setType( Alarm::Audio ); alarm->setEnabled( true ); int alarmOffset = alarmDt.secsTo( event->dtStart() ); alarm->setStartOffset( -alarmOffset ); } else { Alarm *alarm; if ( event->alarms().count() > 0 ) { alarm = event->alarms().first(); alarm->setType( Alarm::Audio ); alarm->setStartOffset( -60*15 ); alarm->setEnabled( false ); } } // csum ***************************************** uint cSum; cSum = PhoneFormat::getCsumEvent( event ); event->setCsum( mProfileName, QString::number( cSum )); event->setTempSyncStat( SYNC_TEMPSTATE_NEW_EXTERNAL ); mCalendar->addEvent( event); return true; } - QDateTime fromGSM ( GSM_DateTime* dtp, bool useTz = true ) { + QDateTime fromGSM ( GSM_DateTime* dtp, bool useTz = false ) { QDateTime dt; int y,m,t,h,min,sec; y = dtp->Year; m = dtp->Month; t = dtp->Day; h = dtp->Hour; min = dtp->Minute; sec = dtp->Second; dt = QDateTime(QDate(y,m,t), QTime(h,min,sec)); // dtp->Timezone: offset in hours int offset = KGlobal::locale()->localTimeOffset( dt ); if ( useTz ) dt = dt.addSecs ( offset*60); return dt; } 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; } QDate datefromGSM ( GSM_DateTime* dtp ) { return QDate ( dtp->Year, dtp->Month, dtp->Day ); } QString getCategory( GSM_CalendarEntry* Note) { QString CATEGORY; switch (Note->Type) { case GSM_CAL_REMINDER : CATEGORY = QString("Reminder"); break; case GSM_CAL_CALL : CATEGORY = QString("Call"); break; case GSM_CAL_MEETING : CATEGORY = QString("Meeting"); break; case GSM_CAL_BIRTHDAY : CATEGORY = QString("Birthday"); break; case GSM_CAL_MEMO : CATEGORY = QString("Memo"); break; case GSM_CAL_TRAVEL : CATEGORY = QString("Travel"); break; case GSM_CAL_VACATION : CATEGORY = QString("Vacation"); break; case GSM_CAL_ALARM : CATEGORY = QString("Alarm"); break; case GSM_CAL_DAILY_ALARM : CATEGORY = QString("Daily alarm"); break; case GSM_CAL_T_ATHL : CATEGORY = QString("Training/Athletism"); break; case GSM_CAL_T_BALL : CATEGORY = QString("Training/Ball Games"); break; case GSM_CAL_T_CYCL : CATEGORY = QString("Training/Cycling"); break; case GSM_CAL_T_BUDO : CATEGORY = QString("Training/Budo"); break; case GSM_CAL_T_DANC : CATEGORY = QString("Training/Dance"); break; case GSM_CAL_T_EXTR : CATEGORY = QString("Training/Extreme Sports"); break; case GSM_CAL_T_FOOT : CATEGORY = QString("Training/Football"); break; case GSM_CAL_T_GOLF : CATEGORY = QString("Training/Golf"); break; case GSM_CAL_T_GYM : CATEGORY = QString("Training/Gym"); break; case GSM_CAL_T_HORS : CATEGORY = QString("Training/Horse Races"); break; case GSM_CAL_T_HOCK : CATEGORY = QString("Training/Hockey"); break; case GSM_CAL_T_RACE : CATEGORY = QString("Training/Races"); break; case GSM_CAL_T_RUGB : CATEGORY = QString("Training/Rugby"); break; case GSM_CAL_T_SAIL : CATEGORY = QString("Training/Sailing"); break; case GSM_CAL_T_STRE : CATEGORY = QString("Training/Street Games"); break; case GSM_CAL_T_SWIM : CATEGORY = QString("Training/Swimming"); break; case GSM_CAL_T_TENN : CATEGORY = QString("Training/Tennis"); break; case GSM_CAL_T_TRAV : CATEGORY = QString("Training/Travels"); break; case GSM_CAL_T_WINT : CATEGORY = QString("Training/Winter Games"); break; default : CATEGORY = QString(""); } return CATEGORY; } protected: private: Calendar *mCalendar; QString mProfileName ; }; PhoneFormat::PhoneFormat(QString profileName, QString device,QString connection, QString model ) { mProfileName = profileName; mDevice = device; mConnection = connection; mModel = model; } PhoneFormat::~PhoneFormat() { } 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; } 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; attList << QString::number( todo->priority() ); QString alarmString = "na"; Alarm *alarm; if ( todo->alarms().count() > 0 ) { alarm = todo->alarms().first(); if ( alarm->enabled() ) { alarmString = QString::number(alarm->startOffset().asSeconds() ); } } 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->startOffset().asSeconds() ); } } 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(); attList << event->secrecyStr(); return PhoneFormat::getCsum(attList ); } ulong PhoneFormat::getCsum( const QStringList & attList) { int max = attList.count() -1; ulong cSum = 0; int j,k,i; int add; for ( i = 1; 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; add = add * mul *i*i*i; cSum += add; } } } 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) { GSM_StateMachine s; qDebug(" load "); s.opened = false; s.msg = NULL; s.ConfigNum = 0; 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("Reading phone...") ); status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); status.show(); status.raise(); qApp->processEvents(); -#if 0 - static char *cp; - static INI_Section *cfg = NULL; - cfg=GSM_FindGammuRC(); - int i; - for (i = 0; i <= MAX_CONFIG_NUM; i++) { - if (cfg!=NULL) { - cp = (char *)INI_GetValue(cfg, (unsigned char*) "gammu", (unsigned char*)"gammucoding", false); - if (cp) di.coding = cp; - - s.Config[i].Localize = (char *)INI_GetValue(cfg, (unsigned char*) "gammu", (unsigned char*) "gammuloc", false); - if (s.Config[i].Localize) { - s.msg=INI_ReadFile(s.Config[i].Localize, true); - } else { -#if !defined(WIN32) && defined(LOCALE_PATH) - locale = setlocale(LC_MESSAGES, NULL); - if (locale != NULL) { - snprintf(locale_file, 200, "%s/gammu_%c%c.txt", - LOCALE_PATH, - tolower(locale[0]), - tolower(locale[1])); - s.msg = INI_ReadFile(locale_file, true); - } -#endif - } - } - - /* Wanted user specific configuration? */ - - if (!GSM_ReadConfig(cfg, &s.Config[i], i) && i != 0) break; - - s.ConfigNum++; - - /* We want to use only one file descriptor for global and state machine debug output */ - s.Config[i].UseGlobalDebugFile = true; - - - /* We wanted to read just user specified configuration. */ - {break;} - } - -#endif int error=initDevice(&s); qDebug("GSM Init %d (no error is %d)", error, ERR_NONE); if ( error != ERR_NONE ) return false; GSM_Phone_Functions *Phone; GSM_CalendarEntry note; bool start = true; Phone=s.Phone.Functions; bool gshutdown = false; PhoneParser handler( calendar, mProfileName ); int ccc = 0; QString message = i18n(" Reading event # "); int procCount = 0; qDebug("Debug: only 10 calender items are downloaded "); while (!gshutdown && ccc++ < 10) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); qDebug("readEvent %d ", ccc); error=Phone->GetNextCalendar(&s,¬e,start); if (error == ERR_EMPTY) break; start = false; handler.readEvent( existingCal, ¬e ); qDebug("Org loc %d ",note.Location); //note.Location = 0; error=Phone->SetCalendar(&s,¬e); qDebug("new loc %d ",note.Location); } start = true; GSM_ToDoEntry ToDo; ccc = 0; message = i18n(" Reading todo # "); procCount = 0; while (!gshutdown && ccc++ < 10) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); error = Phone->GetNextToDo(&s, &ToDo, start); if (error == ERR_EMPTY) break; start = false; qDebug("ReadTodo %d ", ccc); handler.readTodo( existingCal, &ToDo, &s); } error=GSM_TerminateConnection(&s); return true; } #include <qcstring.h> void PhoneFormat::event2GSM( Calendar *cal,Event* ev, GSM_CalendarEntry*Note ) { QString eText = vfconverter.eventToString( ev, cal ); int pos = 0; GSM_ToDoEntry dummy; qDebug( "Convert event"); QByteArray ba; QDataStream s ( ba, IO_WriteOnly ); s << eText.utf8(); GSM_DecodeVCALENDAR_VTODO( (unsigned char*) ba.data(), &pos, Note , &dummy, Nokia_VCalendar, Nokia_VToDo ); qDebug( "Convert event done"); Note->Location = 0; QString loc = ev->getID(mProfileName); if ( !loc.isEmpty() ){ Note->Location = loc.toInt(); } } void PhoneFormat::todo2GSM( Calendar *cal, Todo* todo, GSM_ToDoEntry *gsmTodo ) { qDebug( "Convert todo1"); QString tText = vfconverter.todoToString( todo, cal ); int pos = 0; GSM_CalendarEntry dummy; QByteArray ba; QDataStream s ( ba, IO_WriteOnly ); s << tText.utf8(); GSM_DecodeVCALENDAR_VTODO( (unsigned char*) ba.data(), &pos, &dummy, gsmTodo, Nokia_VCalendar, Nokia_VToDo ); qDebug( "Convert todo done "); gsmTodo->Location = 0; QString loc = todo->getID(mProfileName); if ( !loc.isEmpty() ){ gsmTodo->Location = loc.toInt(); } } void PhoneFormat::afterSave( Incidence* inc) { 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->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID ); } bool PhoneFormat::save( Calendar *calendar) { - return true; + GSM_StateMachine s; qDebug(" save "); s.opened = false; s.msg = NULL; s.ConfigNum = 0; 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(); int error=initDevice(&s); qDebug("GSM Init %d (no error is %d)", error, ERR_NONE); if ( error != ERR_NONE ) return false; GSM_Phone_Functions *Phone; GSM_CalendarEntry Note; bool start = true; Phone=s.Phone.Functions; bool gshutdown = false; QPtrList<Event> er = calendar->rawEvents(); Event* ev = er.first(); - QString message = i18n(" Processing event # "); + QString message = i18n(" Deleting event # "); int procCount = 0; - bool planB = true;// false; + int diffProc = 0; + bool setPossible = true; +#ifdef _WIN32_ + QString fileName = locateLocal("data", "korganizer") + "\\tempfile.vcs"; +#else + QString fileName = "/tmp/kdepimtemp.vcs"; +#endif + //algo 1 delete event + while ( ev ) { + if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { // event was changed during sync or is a new one + + status.setText ( message + QString::number ( ++procCount ) ); + qApp->processEvents(); + qDebug("del event1 %d ", procCount); + //event2GSM( calendar, ev, &Note ); + if ( ev->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete + + QString loc = ev->getID(mProfileName); + if ( !loc.isEmpty() ){ + Note.Location = loc.toInt(); + } else { + qDebug("error: loc is empty "); + } + error = Phone->DeleteCalendar(&s, &Note); + if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { + qDebug(" e error delete1 planB %d ", error); + break; + } + } + else if ( ev->getID(mProfileName).isEmpty() ) { // add new + // we have to do this later after deleting + + } + else { // change existing + + QString loc = ev->getID(mProfileName); + if ( !loc.isEmpty() ){ + Note.Location = loc.toInt(); + } else { + qDebug("error3: loc is empty "); + } + error = Phone->DeleteCalendar(&s, &Note); + if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { + qDebug(" e error delete2 planB %d ", error); + break; + } + ev->removeID( mProfileName ); + } + } + ev = er.next(); + } + //algo 1 delete todo + GSM_ToDoEntry ToDoEntry; + QPtrList<Todo> tl = calendar->rawTodos(); + Todo* to = tl.first(); + message = i18n(" Deleting todo # "); + procCount = 0; + while ( to ) { + if ( to->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { + qDebug("todo3 %d ", procCount); + status.setText ( message + QString::number ( ++procCount ) ); + qApp->processEvents(); + qDebug("todo5 %d ", procCount); + // todo2GSM( calendar, to, &ToDoEntry ); + QString loc = to->getID(mProfileName); + if ( !loc.isEmpty() ){ + ToDoEntry.Location = loc.toInt(); + } else { + qDebug("error2: loc is empty "); + } + if ( to->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete + error=Phone->DeleteToDo(&s,&ToDoEntry); + if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { + qDebug("delete planB %d ", error); + } + } + else if ( to->getID(mProfileName).isEmpty() ) { // add new + ; + } + else { // change existing + error=Phone->DeleteToDo(&s,&ToDoEntry); + if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { + qDebug("set planB %d ", error); + } + to->removeID( mProfileName ); + } + } + to = tl.next(); + } + //algo 2 add event + ev = er.first(); + QString filec; + message = i18n(" Preparing event # "); + procCount = 0; + while ( ev ) { + if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL && ev->tempSyncStat() != SYNC_TEMPSTATE_DELETE) { + if ( ev->getID(mProfileName).isEmpty() ) { + status.setText ( message + QString::number ( ++procCount ) ); + qApp->processEvents(); + filec += vfconverter.eventToString( ev, calendar )+ "\n"; + afterSave ( ev ); + + } + } + ev = er.next(); + } + //algo 2 add todo + to = tl.first(); + procCount = 0; + message = i18n(" Preparing todo # "); + while ( to ) { + qDebug("todo2 %d ", procCount); + if ( to->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL && to->tempSyncStat() != SYNC_TEMPSTATE_DELETE) { + qDebug("todo4 %d ", procCount); + if ( to->getID(mProfileName).isEmpty() ) { + status.setText ( message + QString::number ( ++procCount ) ); + qApp->processEvents(); + filec += vfconverter.todoToString( to, calendar )+ "\n"; + afterSave ( to ); + } + } + to = tl.next(); + } + if ( filec.isEmpty() ) { + qDebug("Nothing to write back.Finished. "); + error=GSM_TerminateConnection(&s); + return true; + } + //algo 3 saving file + message = i18n(" Saving temp file ... "); + status.setText ( message ); + qApp->processEvents(); + QFile file( fileName ); + if (!file.open( IO_WriteOnly ) ) { + qDebug("error open file "); + error=GSM_TerminateConnection(&s); + return false; + } + QTextStream ts( &file ); + ts.setCodec( QTextCodec::codecForName("utf8") ); + ts << filec ; + file.close(); + + + message = i18n(" Parsing temp file ... "); + status.setText ( message ); + qApp->processEvents(); + GSM_Backup Backup; + error=GSM_ReadBackupFile( (char*) fileName.latin1() ,&Backup); + qDebug("Read file result %d ",error ); + //algo 4 writing event + int max, i; + procCount = 0; + message = i18n(" Writing event # "); + if (Backup.Calendar[0] != NULL) { + max = 0; + while (Backup.Calendar[max]!=NULL) max++; + for (i=0;i<max;i++) { + status.setText ( message + QString::number ( ++procCount ) ); + qApp->processEvents(); + Note = *Backup.Calendar[i]; + Note.Location = 0; + error=Phone->AddCalendar(&s,&Note); + qDebug("add event %d %d", error, Note.Location ); + } + } + //algo 4 writing todo + procCount = 0; + message = i18n(" Writing todo # "); + if (Backup.ToDo[0] != NULL) { + max = 0; + while (Backup.ToDo[max]!=NULL) max++; + for (i=0;i<max;i++) { + status.setText ( message + QString::number ( ++procCount ) ); + qApp->processEvents(); + ToDoEntry = *Backup.ToDo[i]; + error = Phone->AddToDo(&s,&ToDoEntry); + qDebug("add todo %d ", error); + } + } + //algo 5 reread + message = i18n(" Rereading all data ... "); + status.setText ( message ); + qApp->processEvents(); + error=GSM_TerminateConnection(&s); + CalendarLocal* calendarTemp = new CalendarLocal(); + calendarTemp->setTimeZoneId( calendar->timeZoneId()); + if ( ! load( calendarTemp,calendar) ){ + qDebug("error reloading calendar "); + delete calendarTemp; + return false; + } + + + //algo 6 compare event + ev = er.first(); + message = i18n(" Comparing event # "); + QPtrList<Event> er1 = calendarTemp->rawEvents(); + Event* ev1; + procCount = 0; + while ( ev ) { + if ( ev->tempSyncStat() == SYNC_TEMPSTATE_NEW_ID) { + qDebug("event new ID "); + status.setText ( message + QString::number ( ++procCount ) ); + qApp->processEvents(); + QString cSum = ev->getCsum(mProfileName); + ev1 = er1.first(); + while ( ev1 ) { + if ( ev1->getCsum( mProfileName ) == cSum ) { + er1.remove( ev1 ); + ev->setID(mProfileName, ev1->getID(mProfileName) ); + break; + } + ev1 = er1.next(); + } + if ( ! ev1 ) { + ev->removeID(mProfileName); + qDebug("ERROR: No event found on phone for %s ", ev->summary().latin1()); + qDebug("Probably writing back of events not supported "); + } + + } + ev = er.next(); + } + //algo 6 compare todo + to = tl.first(); + procCount = 0; + QPtrList<Todo> tl1 = calendarTemp->rawTodos(); + Todo* to1 ; + message = i18n(" Comparing todo # "); + while ( to ) { + qDebug("todo2 %d ", procCount); + if ( to->tempSyncStat() == SYNC_TEMPSTATE_NEW_ID) { + status.setText ( message + QString::number ( ++procCount ) ); + qApp->processEvents(); + QString cSum = to->getCsum(mProfileName); + Todo* to1 = tl1.first(); + while ( to1 ) { + if ( to1->getCsum( mProfileName ) == cSum ) { + tl1.remove( to1 ); + 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()); + qDebug("Probably writing back of todos not supported "); + } + } + to = tl.next(); + } + delete calendarTemp; + return true; + // ******************************************************************* + // ******************************************************************* + // ******************************************************************* +#if 0 while ( ev && ! planB) { if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { // event was changed during sync or is a new one status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); qDebug("event1 %d ", procCount); event2GSM( calendar, ev, &Note ); if ( ev->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete error = Phone->DeleteCalendar(&s, &Note); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { planB = true; - qDebug(" e delete planB %d ", error); + qDebug(" e delete1 planB %d ", error); break; } } else if ( ev->getID(mProfileName).isEmpty() ) { // add new // we have to do this later after deleting } else { // change existing + if ( setPossible ) { error = Phone->SetCalendar(&s, &Note); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { + setPossible = false; + ++diffProc; + qDebug("Set cal not supported %d ", error); + break; + } + } + if ( ! setPossible) { + ++diffProc; + error = Phone->DeleteCalendar(&s, &Note); + if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { planB = true; - qDebug(" e change planB %d ", error); + qDebug(" e delete2 planB %d ", error); break; } + ev->removeID( mProfileName ); + } qDebug("Change Calendar. Location %d status: %d",Note.Location, error ); } } ev = er.next(); } ev = er.first(); // pending get empty slots int loc = 0; + procCount -= diffProc; while ( ev && ! planB) { if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL && ev->tempSyncStat() != SYNC_TEMPSTATE_DELETE) { qDebug("event2 %d ", procCount); if ( ev->getID(mProfileName).isEmpty() ) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); //int newID ;//= pending //ev->setID(mProfileName, QString::number( newID )); event2GSM( calendar, ev, &Note ); ++loc; Note.Location = loc; error = Phone->AddCalendar(&s, &Note); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { planB = true; qDebug(" e add planB %d ", error); break; } ev->setID( mProfileName, QString::number( Note.Location ) ); qDebug("New Calendar. Location %d stat %d %d",Note.Location ,error, ERR_UNKNOWN); afterSave( ev ); } else { afterSave( ev ); // setting temp sync stat for changed items } } ev = er.next(); } if ( planB ) { qDebug("delete all calendar..."); status.setText ( i18n("Deleting all calendar...")); qApp->processEvents(); error=Phone->DeleteAllCalendar(&s); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { message = i18n(" Deleting event # "); procCount = 0; while (1) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); qDebug("deleting event ... %d", procCount); error = Phone->GetNextCalendar(&s,&Note,true); if (error != ERR_NONE) break; error = Phone->DeleteCalendar(&s,&Note); } qDebug("deleting calendar ... finished"); } else { status.setText ( i18n("All calendar deleted!")); qDebug("all cal deleted"); } bool planC = false; ev = er.first(); procCount = 0; message = i18n(" Writing event # "); while ( ev && ! planC) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); event2GSM( calendar, ev, &Note ); Note.Location = procCount; error=Phone->AddCalendar(&s,&Note); if (error != ERR_NONE ) { // we have currently no planC :-( // planC = true; //qDebug("add planC %d ", error); //break; // we remove the ID such that this todo is not deleted after next sync ev->removeID(mProfileName); ev->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID ); qDebug("error :cal adding loc %d planB stat %d ", Note.Location ,error); } else { qDebug("cal adding loc %d planB stat %d ", Note.Location ,error); ev->setID(mProfileName, QString::number( Note.Location )); afterSave( ev ); } ev = er.next(); } if ( planC ) { qDebug("writing cal went wrong..."); // we have currently no planC :-( } } GSM_ToDoEntry ToDoEntry; QPtrList<Todo> tl = calendar->rawTodos(); Todo* to = tl.first(); message = i18n(" Processing todo # "); procCount = 0; planB = false; while ( to && ! planB ) { if ( to->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { qDebug("todo3 %d ", procCount); status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); qDebug("todo5 %d ", procCount); todo2GSM( calendar, to, &ToDoEntry ); if ( to->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete error=Phone->DeleteToDo(&s,&ToDoEntry); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { planB = true; qDebug("delete planB %d ", error); } } else if ( to->getID(mProfileName).isEmpty() ) { // add new ; } else { // change existing error=Phone->SetToDo(&s,&ToDoEntry); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { planB = true; qDebug("set planB %d ", error); } qDebug("Old Todo. Location %d %d",ToDoEntry.Location , error ); } } to = tl.next(); } // pending get empty slots to = tl.first(); while ( to && ! planB ) { qDebug("todo2 %d ", procCount); if ( to->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL && to->tempSyncStat() != SYNC_TEMPSTATE_DELETE) { qDebug("todo4 %d ", procCount); if ( to->getID(mProfileName).isEmpty() ) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); //int newID ;//= pending //to->setID(mProfileName, QString::number( newID )); todo2GSM( calendar,to, &ToDoEntry ); ToDoEntry.Location = 0; error=Phone->AddToDo(&s,&ToDoEntry); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { planB = true; qDebug("new planB %d ", error); } to->setID(mProfileName, QString::number( ToDoEntry.Location )); afterSave( to ); qDebug("New Todo. Location %d %d",ToDoEntry.Location, error ); } else { afterSave( to ); } } to = tl.next(); } if ( planB ) { qDebug("delete all ..."); error=Phone->DeleteAllToDo(&s); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { while (1) { qDebug("deleting todo ..."); error = Phone->GetNextToDo(&s,&ToDoEntry,true); if (error != ERR_NONE) break; error = Phone->DeleteToDo(&s,&ToDoEntry); } qDebug("deleting todo ... finished"); } else { qDebug("all todo deleted"); } bool planC = false; to = tl.first(); while ( to && ! planC ) { todo2GSM( calendar,to, &ToDoEntry ); ToDoEntry.Location = 0; error=Phone->AddToDo(&s,&ToDoEntry); if (error == ERR_NOTSUPPORTED || error == ERR_NOTIMPLEMENTED) { // we have currently no planC :-( // planC = true; //qDebug("add planC %d ", error); //break; // we remove the ID such that this todo is not deleted after next sync to->removeID(mProfileName); to->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID ); } else { qDebug("adding %d planB %d ", ToDoEntry.Location ,error); to->setID(mProfileName, QString::number( ToDoEntry.Location )); afterSave( to ); } to = tl.next(); } if ( planC ) { // we have currently no planC :-( } } return true; +#endif } QString PhoneFormat::dtToGSM( const QDateTime& dti, bool useTZ ) { 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; } QString PhoneFormat::getEventString( Event* event ) { #if 0 QStringList list; list.append( QString::number(event->zaurusId() ) ); list.append( event->categories().join(",") ); if ( !event->summary().isEmpty() ) list.append( event->summary() ); else list.append("" ); if ( !event->location().isEmpty() ) list.append( event->location() ); else list.append("" ); if ( !event->description().isEmpty() ) list.append( event->description() ); else list.append( "" ); if ( event->doesFloat () ) { list.append( dtToString( QDateTime(event->dtStart().date(), QTime(0,0,0)), false )); list.append( dtToString( QDateTime(event->dtEnd().date(),QTime(23,59,59)), false )); //6 list.append( "1" ); } else { list.append( dtToString( event->dtStart()) ); list.append( dtToString( event->dtEnd()) ); //6 list.append( "0" ); } bool noAlarm = true; if ( event->alarms().count() > 0 ) { Alarm * al = event->alarms().first(); if ( al->enabled() ) { noAlarm = false; list.append( "0" ); // yes, 0 == alarm list.append( QString::number( al->startOffset().asSeconds()/(-60) ) ); if ( al->type() == Alarm::Audio ) list.append( "1" ); // type audio else list.append( "0" ); // type silent } } if ( noAlarm ) { list.append( "1" ); // yes, 1 == no alarm list.append( "0" ); // no alarm offset list.append( "1" ); // type } // next is: 11 // next is: 11-16 are recurrence Recurrence* rec = event->recurrence(); 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( dtToString( rec->endDate()) ); } else { list.append( "0" ); list.append( "20991231T000000" ); } } if ( event->doesFloat () ) { list.append( dtToString( event->dtStart(), false ).left( 8 )); list.append( dtToString( event->dtEnd(), false ).left( 8 )); //6 } else { list.append( QString() ); list.append( QString() ); } if (event->dtStart().date() == event->dtEnd().date() ) list.append( "0" ); else list.append( "1" ); for(QStringList::Iterator it=list.begin(); it!=list.end(); ++it){ QString& s = (*it); s.replace(QRegExp("\""), "\"\""); if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){ s.prepend('\"'); s.append('\"'); } else if(s.isEmpty() && !s.isNull()){ s = "\"\""; } } return list.join(","); #endif return QString(); } QString PhoneFormat::getTodoString( Todo* todo ) { #if 0 QStringList list; list.append( QString::number( todo->zaurusId() ) ); list.append( todo->categories().join(",") ); if ( todo->hasStartDate() ) { list.append( dtToString( todo->dtStart()) ); } else list.append( QString() ); if ( todo->hasDueDate() ) { QTime tim; if ( todo->doesFloat()) { list.append( dtToString( QDateTime(todo->dtDue().date(),QTime( 0,0,0 )), false)) ; } else { list.append( dtToString(todo->dtDue() ) ); } } else list.append( QString() ); if ( todo->isCompleted() ) { list.append( dtToString( todo->completed()) ); list.append( "0" ); // yes 0 == completed } else { list.append( dtToString( todo->completed()) ); list.append( "1" ); } list.append( QString::number( todo->priority() )); if( ! todo->summary().isEmpty() ) list.append( todo->summary() ); else list.append( "" ); if (! todo->description().isEmpty() ) list.append( todo->description() ); else list.append( "" ); for(QStringList::Iterator it=list.begin(); it!=list.end(); ++it){ QString& s = (*it); s.replace(QRegExp("\""), "\"\""); if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){ s.prepend('\"'); s.append('\"'); } else if(s.isEmpty() && !s.isNull()){ s = "\"\""; } } return list.join(","); #endif return QString(); } QString PhoneFormat::toString( Calendar * ) { return QString::null; } bool PhoneFormat::fromString( Calendar *calendar, const QString & text) { return false; } diff --git a/libkcal/sharpformat.cpp b/libkcal/sharpformat.cpp index defdb09..820d068 100644 --- a/libkcal/sharpformat.cpp +++ b/libkcal/sharpformat.cpp @@ -1,1018 +1,1018 @@ /* 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. */ #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 <qxml.h> #include <qlabel.h> #include <kdebug.h> #include <klocale.h> #include <kglobal.h> #include "calendar.h" #include "alarm.h" #include "recurrence.h" #include "calendarlocal.h" #include "sharpformat.h" #include "syncdefines.h" using namespace KCal; //CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 //ARSD silentalarm = 0 // 11 RTYP 225 no /0 dialy/ 1 weekly/ 3 month by date/ 2 month by day(pos)/ yearly // 12 RFRQ // 13 RPOS pos = 4. monday in month // 14 RDYS days: 1 mon/ 2 tue .. 64 sun // 15 REND 0 = no end/ 1 = end // 16 REDT rec end dt //ALSD //ALED //MDAY class SharpParser : public QObject { public: SharpParser( Calendar *calendar ) : mCalendar( calendar ) { oldCategories = 0; } bool startElement( Calendar *existingCalendar, const QStringList & attList, QString qName ) { int i = 1; bool skip = true; int max = attList.count() -2; while ( i < max ) { if ( !attList[i].isEmpty() ) { skip = false; break; } ++i ; } if ( skip ) return false; ulong cSum = SharpFormat::getCsum(attList ); if ( qName == "Event" ) { Event *event; event = existingCalendar->event( "Sharp_DTM",attList[0] ); if ( event ) event = (Event*)event->clone(); else event = new Event; event->setID("Sharp_DTM", attList[0] ); event->setCsum( "Sharp_DTM", QString::number( cSum )); event->setTempSyncStat(SYNC_TEMPSTATE_NEW_EXTERNAL ); event->setSummary( attList[2] ); event->setLocation( attList[3] ); event->setDescription( attList[4] ); if ( attList[7] == "1" ) { event->setDtStart( QDateTime(fromString( attList[17]+"T000000", false ).date(),QTime(0,0,0 ) )); event->setDtEnd( QDateTime(fromString( attList[18]+"T000000", false ).date(),QTime(0,0,0 ))); event->setFloats( true ); } else { event->setFloats( false ); event->setDtStart( fromString( attList[5] ) ); event->setDtEnd( fromString( attList[6] )); } QString rtype = attList[11]; if ( rtype != "255" ) { // qDebug("recurs "); QDate startDate = event->dtStart().date(); QString freqStr = attList[12]; int freq = freqStr.toInt(); QString hasEndDateStr = attList[15] ; bool hasEndDate = hasEndDateStr == "1"; QString endDateStr = attList[16]; QDate endDate = fromString( endDateStr ).date(); QString weekDaysStr = attList[14]; uint weekDaysNum = weekDaysStr.toInt(); QBitArray weekDays( 7 ); int i; int bb = 1; for( i = 1; i <= 7; ++i ) { weekDays.setBit( i - 1, ( bb & weekDaysNum )); bb = 2 << (i-1); //qDebug(" %d bit %d ",i-1,weekDays.at(i-1) ); } // qDebug("next "); QString posStr = attList[13]; int pos = posStr.toInt(); Recurrence *r = event->recurrence(); if ( rtype == "0" ) { if ( hasEndDate ) r->setDaily( freq, endDate ); else r->setDaily( freq, -1 ); } else if ( rtype == "1" ) { if ( hasEndDate ) r->setWeekly( freq, weekDays, endDate ); else r->setWeekly( freq, weekDays, -1 ); } else if ( rtype == "3" ) { if ( hasEndDate ) r->setMonthly( Recurrence::rMonthlyDay, freq, endDate ); else r->setMonthly( Recurrence::rMonthlyDay, freq, -1 ); r->addMonthlyDay( startDate.day() ); } else if ( rtype == "2" ) { if ( hasEndDate ) r->setMonthly( Recurrence::rMonthlyPos, freq, endDate ); else r->setMonthly( Recurrence::rMonthlyPos, freq, -1 ); QBitArray days( 7 ); days.fill( false ); days.setBit( startDate.dayOfWeek() - 1 ); r->addMonthlyPos( pos, days ); } else if ( rtype == "4" ) { if ( hasEndDate ) r->setYearly( Recurrence::rYearlyMonth, freq, endDate ); else r->setYearly( Recurrence::rYearlyMonth, freq, -1 ); r->addYearlyNum( startDate.month() ); } } else { event->recurrence()->unsetRecurs(); } QString categoryList = attList[1] ; event->setCategories( lookupCategories( categoryList ) ); // strange 0 semms to mean: alarm enabled if ( attList[8] == "0" ) { Alarm *alarm; if ( event->alarms().count() > 0 ) alarm = event->alarms().first(); else { alarm = new Alarm( event ); event->addAlarm( alarm ); } alarm->setType( Alarm::Audio ); alarm->setEnabled( true ); int alarmOffset = attList[9].toInt(); alarm->setStartOffset( alarmOffset * -60 ); } else { Alarm *alarm; if ( event->alarms().count() > 0 ) { alarm = event->alarms().first(); alarm->setType( Alarm::Audio ); alarm->setStartOffset( -60*15 ); alarm->setEnabled( false ); } } mCalendar->addEvent( event); } else if ( qName == "Todo" ) { Todo *todo; todo = existingCalendar->todo( "Sharp_DTM", attList[0] ); if (todo ) todo = (Todo*)todo->clone(); else todo = new Todo; //CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1 // 0 1 2 3 4 5 6 7 8 //1,,,,,1,4,Loch zumachen,"" //3,Privat,20040317T000000,20040318T000000,20040319T000000,0,5,Call bbb,"notes123 bbb gggg ""bb "" " //2,"Familie,Freunde,Holiday",20040318T000000,20040324T000000,20040317T000000,1,2,tod2,notes todo->setID( "Sharp_DTM", attList[0]); todo->setCsum( "Sharp_DTM", QString::number( cSum )); todo->setTempSyncStat( SYNC_TEMPSTATE_NEW_EXTERNAL ); todo->setSummary( attList[7] ); todo->setDescription( attList[8]); int priority = attList[6].toInt(); if ( priority == 0 ) priority = 3; todo->setPriority( priority ); QString categoryList = attList[1]; todo->setCategories( lookupCategories( categoryList ) ); QString hasDateStr = attList[3]; // due if ( !hasDateStr.isEmpty() ) { if ( hasDateStr.right(6) == "000000" ) { todo->setDtDue( QDateTime(fromString( hasDateStr, false ).date(), QTime(0,0,0 )) ); todo->setFloats( true ); } else { todo->setDtDue( fromString( hasDateStr ) ); todo->setFloats( false ); } todo->setHasDueDate( true ); } hasDateStr = attList[2];//start if ( !hasDateStr.isEmpty() ) { todo->setDtStart( fromString( hasDateStr ) ); todo->setHasStartDate( true); } else todo->setHasStartDate( false ); hasDateStr = attList[4];//completed if ( !hasDateStr.isEmpty() ) { todo->setCompleted(fromString( hasDateStr ) ); } QString completedStr = attList[5]; if ( completedStr == "0" ) todo->setCompleted( true ); else todo->setCompleted( false ); mCalendar->addTodo( todo ); } else if ( qName == "Category" ) { /* QString id = attributes.value( "id" ); QString name = attributes.value( "name" ); setCategory( id, name ); */ } //qDebug("end "); return true; } void setCategoriesList ( QStringList * c ) { oldCategories = c; } QDateTime fromString ( QString s, bool useTz = true ) { QDateTime dt; int y,m,t,h,min,sec; y = s.mid(0,4).toInt(); m = s.mid(4,2).toInt(); t = s.mid(6,2).toInt(); h = s.mid(9,2).toInt(); min = s.mid(11,2).toInt(); sec = s.mid(13,2).toInt(); dt = QDateTime(QDate(y,m,t), QTime(h,min,sec)); int offset = KGlobal::locale()->localTimeOffset( dt ); if ( useTz ) dt = dt.addSecs ( offset*60); return dt; } protected: QDateTime toDateTime( const QString &value ) { QDateTime dt; dt.setTime_t( value.toUInt() ); return dt; } QStringList lookupCategories( const QString &categoryList ) { QStringList categoryIds = QStringList::split( ";", categoryList ); QStringList categories; QStringList::ConstIterator it; for( it = categoryIds.begin(); it != categoryIds.end(); ++it ) { QString cate = category( *it ); if ( oldCategories ) { if ( ! oldCategories->contains( cate ) ) oldCategories->append( cate ); } categories.append(cate ); } return categories; } private: Calendar *mCalendar; QStringList * oldCategories; static QString category( const QString &id ) { QMap<QString,QString>::ConstIterator it = mCategoriesMap.find( id ); if ( it == mCategoriesMap.end() ) return id; else return *it; } static void setCategory( const QString &id, const QString &name ) { mCategoriesMap.insert( id, name ); } static QMap<QString,QString> mCategoriesMap; }; QMap<QString,QString> SharpParser::mCategoriesMap; SharpFormat::SharpFormat() { mCategories = 0; } SharpFormat::~SharpFormat() { } ulong SharpFormat::getCsum( const QStringList & attList) { int max = attList.count() -1; ulong cSum = 0; int j,k,i; int add; for ( i = 1; 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; add = add * mul *i*i*i; cSum += add; } } } return cSum; } #include <stdlib.h> #define DEBUGMODE false bool SharpFormat::load( Calendar *calendar, Calendar *existngCal ) { bool debug = DEBUGMODE; //debug = true; QString text; QString codec = "utf8"; QLabel status ( i18n("Reading events ..."), 0 ); int w = status.sizeHint().width()+20 ; if ( w < 200 ) w = 200; int h = status.sizeHint().height()+20 ; int dw = QApplication::desktop()->width(); int dh = QApplication::desktop()->height(); status.setCaption(i18n("Reading DTM Data") ); status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); status.show(); status.raise(); qApp->processEvents(); QString fileName; if ( ! debug ) { fileName = "/tmp/kopitempout"; QString command ="db2file datebook -r -c "+ codec + " > " + fileName; system ( command.latin1() ); } else { fileName = "/tmp/events.txt"; } QFile file( fileName ); if (!file.open( IO_ReadOnly ) ) { return false; } QTextStream ts( &file ); ts.setCodec( QTextCodec::codecForName("utf8") ); text = ts.read(); file.close(); status.setText( i18n("Processing events ...") ); status.raise(); qApp->processEvents(); fromString2Cal( calendar, existngCal, text, "Event" ); status.setText( i18n("Reading todos ...") ); qApp->processEvents(); if ( ! debug ) { fileName = "/tmp/kopitempout"; QString command = "db2file todo -r -c " + codec+ " > " + fileName; system ( command.latin1() ); } else { fileName = "/tmp/todo.txt"; } file.setName( fileName ); if (!file.open( IO_ReadOnly ) ) { return false; } ts.setDevice( &file ); text = ts.read(); file.close(); status.setText( i18n("Processing todos ...") ); status.raise(); qApp->processEvents(); fromString2Cal( calendar, existngCal, text, "Todo" ); return true; } int SharpFormat::getNumFromRecord( QString answer, Incidence* inc ) { int retval = -1; QStringList templist; QString tempString; int start = 0; int len = answer.length(); int end = answer.find ("\n",start)+1; bool ok = true; start = end; int ccc = 0; while ( start > 0 ) { templist.clear(); ok = true; int loopCount = 0; while ( ok ) { ++loopCount; if ( loopCount > 25 ) { qDebug("KO: Error in while loop"); ok = false; start = 0; break; } if ( ok ) tempString = getPart( answer, ok, start ); if ( start >= len || start == 0 ) { start = 0; ok = false; } if ( tempString.right(1) =="\n" ) tempString = tempString.left( tempString.length()-1); templist.append( tempString ); } ++ccc; if ( ccc == 2 && loopCount < 25 ) { start = 0; bool ok; int newnum = templist[0].toInt( &ok ); if ( ok && newnum > 0) { retval = newnum; inc->setID( "Sharp_DTM",templist[0] ); inc->setCsum( "Sharp_DTM", QString::number( getCsum( templist ) )); inc->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID ); } } } //qDebug("getNumFromRecord returning : %d ", retval); return retval; } bool SharpFormat::save( Calendar *calendar) { QLabel status ( i18n("Processing/adding events ..."), 0 ); int w = status.sizeHint().width()+20 ; if ( w < 200 ) w = 200; int h = status.sizeHint().height()+20 ; int dw = QApplication::desktop()->width(); int dh = QApplication::desktop()->height(); status.setCaption(i18n("Writing DTM Data") ); status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); status.show(); status.raise(); qApp->processEvents(); bool debug = DEBUGMODE; QString codec = "utf8"; QString answer; QString ePrefix = "CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY\n"; QString tPrefix = "CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1\n"; QString command; QPtrList<Event> er = calendar->rawEvents(); Event* ev = er.first(); - QString fileName = "/tmp/kopitempout"; + QString fileName = "/tmp/kdepimtempfile"; int i = 0; QString changeString = ePrefix; QString deleteString = ePrefix; bool deleteEnt = false; bool changeEnt = false; QString message = i18n("Processing event # "); int procCount = 0; while ( ev ) { //qDebug("i %d ", ++i); if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); QString eString = getEventString( ev ); if ( ev->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete // deleting empty strings does not work. // we write first and x and then delete the record with the x eString = eString.replace( QRegExp(",\"\""),",\"x\"" ); changeString += eString + "\n"; deleteString += eString + "\n"; deleteEnt = true; changeEnt = true; } else if ( ev->getID("Sharp_DTM").isEmpty() ) { // add new command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName; system ( command.utf8() ); QFile file( fileName ); if (!file.open( IO_ReadOnly ) ) { return false; } QTextStream ts( &file ); ts.setCodec( QTextCodec::codecForName("utf8") ); answer = ts.read(); file.close(); //qDebug("answer \n%s ", answer.latin1()); getNumFromRecord( answer, ev ) ; } else { // change existing //qDebug("canging %d %d",ev->zaurusStat() ,ev->zaurusId() ); //command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName; changeString += eString + "\n"; changeEnt = true; } } ev = er.next(); } status.setText ( i18n("Changing events ...") ); qApp->processEvents(); //qDebug("changing... "); if ( changeEnt ) { QFile file( fileName ); if (!file.open( IO_WriteOnly ) ) { return false; } QTextStream ts( &file ); ts.setCodec( QTextCodec::codecForName("utf8") ); ts << changeString ; file.close(); command = "db2file datebook -w -g -c " + codec+ " < "+ fileName; system ( command.latin1() ); //qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1()); } status.setText ( i18n("Deleting events ...") ); qApp->processEvents(); //qDebug("deleting... "); if ( deleteEnt ) { QFile file( fileName ); if (!file.open( IO_WriteOnly ) ) { return false; } QTextStream ts( &file ); ts.setCodec( QTextCodec::codecForName("utf8") ); ts << deleteString; file.close(); command = "db2file datebook -d -c " + codec+ " < "+ fileName; system ( command.latin1() ); // qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1()); } changeString = tPrefix; deleteString = tPrefix; status.setText ( i18n("Processing todos ...") ); qApp->processEvents(); QPtrList<Todo> tl = calendar->rawTodos(); Todo* to = tl.first(); i = 0; message = i18n("Processing todo # "); procCount = 0; while ( to ) { if ( to->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { status.setText ( message + QString::number ( ++procCount ) ); qApp->processEvents(); QString eString = getTodoString( to ); if ( to->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete // deleting empty strings does not work. // we write first and x and then delete the record with the x eString = eString.replace( QRegExp(",\"\""),",\"x\"" ); changeString += eString + "\n"; deleteString += eString + "\n"; deleteEnt = true; changeEnt = true; } else if ( to->getID("Sharp_DTM").isEmpty() ) { // add new command = "(echo \"" + tPrefix + eString + "\" ) | db2file todo -w -g -c " + codec+ " > "+ fileName; system ( command.utf8() ); QFile file( fileName ); if (!file.open( IO_ReadOnly ) ) { return false; } QTextStream ts( &file ); ts.setCodec( QTextCodec::codecForName("utf8") ); answer = ts.read(); file.close(); //qDebug("answer \n%s ", answer.latin1()); getNumFromRecord( answer, to ) ; } else { // change existing //qDebug("canging %d %d",to->zaurusStat() ,to->zaurusId() ); //command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName; changeString += eString + "\n"; changeEnt = true; } } to = tl.next(); } status.setText ( i18n("Changing todos ...") ); qApp->processEvents(); //qDebug("changing... "); if ( changeEnt ) { QFile file( fileName ); if (!file.open( IO_WriteOnly ) ) { return false; } QTextStream ts( &file ); ts.setCodec( QTextCodec::codecForName("utf8") ); ts << changeString ; file.close(); command = "db2file todo -w -g -c " + codec+ " < "+ fileName; system ( command.latin1() ); //qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1()); } status.setText ( i18n("Deleting todos ...") ); qApp->processEvents(); //qDebug("deleting... "); if ( deleteEnt ) { QFile file( fileName ); if (!file.open( IO_WriteOnly ) ) { return false; } QTextStream ts( &file ); ts.setCodec( QTextCodec::codecForName("utf8") ); ts << deleteString; file.close(); command = "db2file todo -d -c " + codec+ " < "+ fileName; system ( command.latin1() ); // qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1()); } return true; } QString SharpFormat::dtToString( const QDateTime& dti, bool useTZ ) { 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; } QString SharpFormat::getEventString( Event* event ) { QStringList list; list.append( event->getID("Sharp_DTM") ); list.append( event->categories().join(",") ); if ( !event->summary().isEmpty() ) list.append( event->summary() ); else list.append("" ); if ( !event->location().isEmpty() ) list.append( event->location() ); else list.append("" ); if ( !event->description().isEmpty() ) list.append( event->description() ); else list.append( "" ); if ( event->doesFloat () ) { list.append( dtToString( QDateTime(event->dtStart().date(), QTime(0,0,0)), false )); list.append( dtToString( QDateTime(event->dtEnd().date(),QTime(23,59,59)), false )); //6 list.append( "1" ); } else { list.append( dtToString( event->dtStart()) ); list.append( dtToString( event->dtEnd()) ); //6 list.append( "0" ); } bool noAlarm = true; if ( event->alarms().count() > 0 ) { Alarm * al = event->alarms().first(); if ( al->enabled() ) { noAlarm = false; list.append( "0" ); // yes, 0 == alarm list.append( QString::number( al->startOffset().asSeconds()/(-60) ) ); if ( al->type() == Alarm::Audio ) list.append( "1" ); // type audio else list.append( "0" ); // type silent } } if ( noAlarm ) { list.append( "1" ); // yes, 1 == no alarm list.append( "0" ); // no alarm offset list.append( "1" ); // type } // next is: 11 // next is: 11-16 are recurrence Recurrence* rec = event->recurrence(); 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( dtToString( rec->endDate()) ); } else { list.append( "0" ); list.append( "20991231T000000" ); } } if ( event->doesFloat () ) { list.append( dtToString( event->dtStart(), false ).left( 8 )); list.append( dtToString( event->dtEnd(), false ).left( 8 )); //6 } else { list.append( QString() ); list.append( QString() ); } if (event->dtStart().date() == event->dtEnd().date() ) list.append( "0" ); else list.append( "1" ); for(QStringList::Iterator it=list.begin(); it!=list.end(); ++it){ QString& s = (*it); s.replace(QRegExp("\""), "\"\""); if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){ s.prepend('\"'); s.append('\"'); } else if(s.isEmpty() && !s.isNull()){ s = "\"\""; } } return list.join(","); } QString SharpFormat::getTodoString( Todo* todo ) { QStringList list; list.append( todo->getID("Sharp_DTM") ); list.append( todo->categories().join(",") ); if ( todo->hasStartDate() ) { list.append( dtToString( todo->dtStart()) ); } else list.append( QString() ); if ( todo->hasDueDate() ) { QTime tim; if ( todo->doesFloat()) { list.append( dtToString( QDateTime(todo->dtDue().date(),QTime( 0,0,0 )), false)) ; } else { list.append( dtToString(todo->dtDue() ) ); } } else list.append( QString() ); if ( todo->isCompleted() ) { list.append( dtToString( todo->completed()) ); list.append( "0" ); // yes 0 == completed } else { list.append( dtToString( todo->completed()) ); list.append( "1" ); } list.append( QString::number( todo->priority() )); if( ! todo->summary().isEmpty() ) list.append( todo->summary() ); else list.append( "" ); if (! todo->description().isEmpty() ) list.append( todo->description() ); else list.append( "" ); for(QStringList::Iterator it=list.begin(); it!=list.end(); ++it){ QString& s = (*it); s.replace(QRegExp("\""), "\"\""); if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){ s.prepend('\"'); s.append('\"'); } else if(s.isEmpty() && !s.isNull()){ s = "\"\""; } } return list.join(","); } QString SharpFormat::getPart( const QString & text, bool &ok, int &start ) { //qDebug("start %d ", start); QString retval =""; if ( text.at(start) == '"' ) { if ( text.mid( start,2) == "\"\"" && !( text.mid( start+2,1) == "\"")) { start = start +2; if ( text.mid( start,1) == "," ) { start += 1; } retval = ""; if ( text.mid( start,1) == "\n" ) { start += 1; ok = false; } return retval; } int hk = start+1; hk = text.find ('"',hk); while ( text.at(hk+1) == '"' ) hk = text.find ('"',hk+2); retval = text.mid( start+1, hk-start-1); start = hk+1; retval.replace( QRegExp("\"\""), "\""); if ( text.mid( start,1) == "," ) { start += 1; } if ( text.mid( start,1) == "\n" ) { start += 1; ok = false; } //qDebug("retval***%s*** ",retval.latin1() ); return retval; } else { int nl = text.find ("\n",start); int kom = text.find (',',start); if ( kom < nl ) { // qDebug("kom < nl %d ", kom); retval = text.mid(start, kom-start); start = kom+1; return retval; } else { if ( nl == kom ) { // qDebug(" nl == kom "); start = 0; ok = false; return "0"; } // qDebug(" nl < kom ", nl); retval = text.mid( start, nl-start); ok = false; start = nl+1; return retval; } } } bool SharpFormat::fromString( Calendar *calendar, const QString & text) { return false; } bool SharpFormat::fromString2Cal( Calendar *calendar,Calendar *existingCalendar, const QString & text, const QString & type) { // qDebug("test %s ", text.latin1()); QStringList templist; QString tempString; int start = 0; int len = text.length(); int end = text.find ("\n",start)+1; bool ok = true; start = end; SharpParser handler( calendar ); handler.setCategoriesList( mCategories ); while ( start > 0 ) { templist.clear(); ok = true; while ( ok ) { tempString = getPart( text, ok, start ); if ( start >= len || start == 0 ) { start = 0; ok = false; } if ( tempString.right(1) =="\n" ) tempString = tempString.left( tempString.length()-1); //if ( ok ) templist.append( tempString ); //qDebug("%d ---%s---", templist.count(),tempString.latin1() ); } handler.startElement( existingCalendar, templist, type ); } return false; } QString SharpFormat::toString( Calendar * ) { return QString::null; } diff --git a/libkcal/vcalformat.cpp b/libkcal/vcalformat.cpp index 076cd3f..9307f12 100644 --- a/libkcal/vcalformat.cpp +++ b/libkcal/vcalformat.cpp @@ -1,1700 +1,1705 @@ /* 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 <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; } VCalFormat::~VCalFormat() { } bool VCalFormat::load(Calendar *calendar, const QString &fileName) { mCalendar = calendar; clearException(); kdDebug(5800) << "VCalFormat::load() " << fileName << endl; 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; QString tmpStr; VObject *vcal, *vo; kdDebug(5800) << "VCalFormat::save(): " << fileName << endl; 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)) { kdDebug(5800) << "No error" << endl; return true; } else { kdDebug(5800) << "Error" << endl; 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 { kdDebug(5800) << "VCalFormat::fromString(): Unknown object type." << endl; deleteVObject( vcal ); return false; } deleteVObject( vcal ); return true; } QString VCalFormat::eventToString( Event * event, Calendar *calendar) { if ( !event ) return QString::null; mCalendar = calendar; VObject *vevent = eventToVEvent( event ); char *buf = writeMemVObject( 0, 0, vevent ); QString result( buf ); cleanVObject( vevent ); return result; } QString VCalFormat::todoToString( Todo * todo, Calendar *calendar ) { if ( !todo ) return QString::null; mCalendar = calendar; VObject *vevent = eventToVTodo( todo ); char *buf = writeMemVObject( 0, 0, vevent ); QString result( buf ); cleanVObject( vevent ); 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 = addProp(vtodo, VCDAlarmProp); + VObject *a; tmpStr = qDateTimeToISO(alarm->time()); - addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); - addPropValue(a, VCRepeatCountProp, "1"); - addPropValue(a, VCDisplayStringProp, "beep!"); 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)) tmpStr += dayFromNum(i); } break; case Recurrence::rMonthlyPos: tmpStr.sprintf("MP%i ", anEvent->recurrence()->frequency()); // write out all rMonthPos's tmpPositions = anEvent->recurrence()->monthPositions(); for (tmpPos = tmpPositions.first(); tmpPos; tmpPos = tmpPositions.next()) { tmpStr2.sprintf("%i", tmpPos->rPos); if (tmpPos->negative) tmpStr2 += "- "; else tmpStr2 += "+ "; tmpStr += tmpStr2; for (i = 0; i < 7; i++) { if (tmpPos->rDays.testBit(i)) tmpStr += dayFromNum(i); } } // loop for all rMonthPos's break; case Recurrence::rMonthlyDay: tmpStr.sprintf("MD%i ", anEvent->recurrence()->frequency()); // write out all rMonthDays; tmpDays = anEvent->recurrence()->monthDays(); for (tmpDay = tmpDays.first(); tmpDay; tmpDay = tmpDays.next()) { tmpStr2.sprintf("%i ", *tmpDay); tmpStr += tmpStr2; } break; case Recurrence::rYearlyMonth: tmpStr.sprintf("YM%i ", anEvent->recurrence()->frequency()); // write out all the rYearNums; tmpDays = anEvent->recurrence()->yearNums(); for (tmpDay = tmpDays.first(); tmpDay; tmpDay = tmpDays.next()) { tmpStr2.sprintf("%i ", *tmpDay); tmpStr += tmpStr2; } break; case Recurrence::rYearlyDay: tmpStr.sprintf("YD%i ", anEvent->recurrence()->frequency()); // write out all the rYearNums; tmpDays = anEvent->recurrence()->yearNums(); for (tmpDay = tmpDays.first(); tmpDay; tmpDay = tmpDays.next()) { tmpStr2.sprintf("%i ", *tmpDay); tmpStr += tmpStr2; } break; default: kdDebug(5800) << "ERROR, it should never get here in eventToVEvent!" << endl; break; } // switch if (anEvent->recurrence()->duration() > 0) { tmpStr2.sprintf("#%i",anEvent->recurrence()->duration()); tmpStr += tmpStr2; } else if (anEvent->recurrence()->duration() == -1) { tmpStr += "#0"; // defined as repeat forever } else { tmpStr += qDateTimeToISO(anEvent->recurrence()->endDate(), FALSE); } addPropValue(vevent,VCRRuleProp, tmpStr.local8Bit()); } // event repeats // exceptions to recurrence DateList dateList = anEvent->exDates(); DateList::ConstIterator it; QString tmpStr2; for (it = dateList.begin(); it != dateList.end(); ++it) { tmpStr = qDateToISO(*it) + ";"; tmpStr2 += tmpStr; } if (!tmpStr2.isEmpty()) { tmpStr2.truncate(tmpStr2.length()-1); addPropValue(vevent, VCExpDateProp, tmpStr2.local8Bit()); } // description if (!anEvent->description().isEmpty()) { VObject *d = addPropValue(vevent, VCDescriptionProp, anEvent->description().local8Bit()); if (anEvent->description().find('\n') != -1) addProp(d, VCQuotedPrintableProp); } // summary if (!anEvent->summary().isEmpty()) addPropValue(vevent, VCSummaryProp, anEvent->summary().local8Bit()); if (!anEvent->location().isEmpty()) addPropValue(vevent, VCLocationProp, anEvent->location().local8Bit()); // status // TODO: define Event status // addPropValue(vevent, VCStatusProp, anEvent->statusStr().local8Bit()); // secrecy const char *text = 0; switch (anEvent->secrecy()) { case Incidence::SecrecyPublic: text = "PUBLIC"; break; case Incidence::SecrecyPrivate: text = "PRIVATE"; break; case Incidence::SecrecyConfidential: text = "CONFIDENTIAL"; break; } if (text) { addPropValue(vevent, VCClassProp, text); } // 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(vevent, VCCategoriesProp, tmpStr.local8Bit()); } // attachments // TODO: handle binary attachments! QPtrList<Attachment> attachments = anEvent->attachments(); for ( Attachment *at = attachments.first(); at; at = attachments.next() ) addPropValue(vevent, VCAttachProp, at->uri().local8Bit()); // resources tmpStrList = anEvent->resources(); tmpStr = tmpStrList.join(";"); if (!tmpStr.isEmpty()) addPropValue(vevent, VCResourcesProp, tmpStr.local8Bit()); // alarm stuff QPtrList<Alarm> alarms = anEvent->alarms(); Alarm* alarm; for (alarm = alarms.first(); alarm; alarm = alarms.next()) { if (alarm->enabled()) { - VObject *a = addProp(vevent, VCDAlarmProp); + VObject *a ; tmpStr = qDateTimeToISO(alarm->time()); - addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); - addPropValue(a, VCRepeatCountProp, "1"); - addPropValue(a, VCDisplayStringProp, "beep!"); if (alarm->type() == Alarm::Audio) { a = addProp(vevent, VCAAlarmProp); addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); addPropValue(a, VCRepeatCountProp, "1"); addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile())); } if (alarm->type() == Alarm::Procedure) { a = addProp(vevent, VCPAlarmProp); addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); addPropValue(a, VCRepeatCountProp, "1"); addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile())); + } else { + a = addProp(vevent, VCDAlarmProp); + addPropValue(a, VCRunTimeProp, tmpStr.local8Bit()); + addPropValue(a, VCRepeatCountProp, "1"); + addPropValue(a, VCDisplayStringProp, "beep!"); + } } } // priority tmpStr.sprintf("%i",anEvent->priority()); addPropValue(vevent, VCPriorityProp, tmpStr.local8Bit()); // transparency tmpStr.sprintf("%i",anEvent->transparency()); addPropValue(vevent, VCTranspProp, tmpStr.local8Bit()); // related event if (anEvent->relatedTo()) { addPropValue(vevent, VCRelatedToProp, anEvent->relatedTo()->uid().local8Bit()); } if (anEvent->pilotId()) { // pilot sync stuff tmpStr.sprintf("%i",anEvent->pilotId()); addPropValue(vevent, XPilotIdProp, tmpStr.local8Bit()); tmpStr.sprintf("%i",anEvent->syncStatus()); addPropValue(vevent, XPilotStatusProp, tmpStr.local8Bit()); } return vevent; } Todo *VCalFormat::VTodoToEvent(VObject *vtodo) { VObject *vo; VObjectIterator voi; char *s; Todo *anEvent = new Todo; // creation date if ((vo = isAPropertyOf(vtodo, VCDCreatedProp)) != 0) { anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo)))); deleteStr(s); } // unique id vo = isAPropertyOf(vtodo, 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); } // last modification date if ((vo = isAPropertyOf(vtodo, 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(vtodo, ICOrganizerProp)) != 0) { anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo))); deleteStr(s); } else { anEvent->setOrganizer(mCalendar->getEmail()); } // attendees. initPropIterator(&voi, vtodo); 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); } } // description for todo if ((vo = isAPropertyOf(vtodo, VCDescriptionProp)) != 0) { s = fakeCString(vObjectUStringZValue(vo)); anEvent->setDescription(QString::fromLocal8Bit(s)); deleteStr(s); } // summary if ((vo = isAPropertyOf(vtodo, VCSummaryProp))) { s = fakeCString(vObjectUStringZValue(vo)); anEvent->setSummary(QString::fromLocal8Bit(s)); deleteStr(s); } if ((vo = isAPropertyOf(vtodo, VCLocationProp))) { s = fakeCString(vObjectUStringZValue(vo)); anEvent->setLocation(QString::fromLocal8Bit(s)); deleteStr(s); } // completed // was: status if ((vo = isAPropertyOf(vtodo, VCStatusProp)) != 0) { s = fakeCString(vObjectUStringZValue(vo)); 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); } } /*********************** 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); } } else { 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) { QDateTime tmpDT(qdt); tmpDT = tmpDT.addSecs(60*(-mCalendar->getTimeZone())); // correct to GMT. 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(60*mCalendar->getTimeZone()); 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); } // 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; } } |