Diffstat (limited to 'libopie/pim/odatebookaccessbackend_xml.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libopie/pim/odatebookaccessbackend_xml.cpp | 184 |
1 files changed, 173 insertions, 11 deletions
diff --git a/libopie/pim/odatebookaccessbackend_xml.cpp b/libopie/pim/odatebookaccessbackend_xml.cpp index a4c514b..5239d84 100644 --- a/libopie/pim/odatebookaccessbackend_xml.cpp +++ b/libopie/pim/odatebookaccessbackend_xml.cpp @@ -1,103 +1,233 @@ #include <errno.h> #include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <qasciidict.h> #include <qfile.h> #include <qtopia/global.h> #include <qtopia/stringutil.h> +#include <qtopia/timeconversion.h> #include "opimnotifymanager.h" #include "orecur.h" #include "otimezone.h" #include "odatebookaccessbackend_xml.h" namespace { time_t start, end, created, rp_end; ORecur* rec; ORecur* recur() { if (!rec) rec = new ORecur; return rec; } int alarmTime; int snd; enum Attribute{ - FDescription = 0, - FLocation, - FCategories, - FUid, - FType, + FDescription = 0, + FLocation, + FCategories, + FUid, + FType, FAlarm, FSound, FRType, FRWeekdays, FRPosition, FRFreq, FRHasEndDate, FREndDate, FRStart, FREnd, FNote, - FCreated + FCreated, + FTimeZone, + FRecParent, + FRecChildren, + FExceptions }; + inline void save( const OEvent& ev, QString& buf ) { + buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; + if (!ev.location().isEmpty() ) + buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; + + buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; + buf += " uid=\"" + QString::number( ev.uid() ) + "\""; + + if (ev.isAllDay() ) + buf += " type=\"AllDay\""; + + if (ev.hasNotifiers() ) { + OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first + int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; + buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; + if ( alarm.sound() == OPimAlarm::Loud ) + buf += "loud"; + else + buf += "silent"; + buf += "\""; + } + if ( ev.hasRecurrence() ) { + buf += ev.recurrence().toString(); + } + + /* + * fscking timezones :) well, we'll first convert + * the QDateTime to a QDateTime in UTC time + * and then we'll create a nice time_t + */ + OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); + buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\""; + buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\""; + if (!ev.note().isEmpty() ) { + buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; + } + + buf += " timezone=\""; + if ( ev.timeZone().isEmpty() ) + buf += "None"; + else + buf += ev.timeZone(); + + if (ev.parent() != 0 ) { + buf += " recparent=\""+QString::number(ev.parent() )+"\""; + } + + if (ev.children().count() != 0 ) { + QArray<int> children = ev.children(); + buf += " recchildren=\""; + for ( uint i = 0; i < children.count(); i++ ) { + if ( i != 0 ) buf += " "; + buf += QString::number( children[i] ); + } + buf+= "\""; + } + + // skip custom writing + } + + inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) { + QMap<int, OEvent>::ConstIterator it; + QString buf; + QCString str; + int total_written; + for ( it = list.begin(); it != list.end(); ++it ) { + buf = "<event"; + save( it.data(), buf ); + buf += " />\n"; + str = buf.utf8(); + + total_written = file.writeBlock(str.data(), str.length() ); + if ( total_written != int(str.length() ) ) + return false; + } + return true; + } } ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , const QString& fileName ) : ODateBookAccessBackend() { m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; m_changed = false; } ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { } bool ODateBookAccessBackend_XML::load() { return loadFile(); } bool ODateBookAccessBackend_XML::reload() { clear(); return load(); } bool ODateBookAccessBackend_XML::save() { - if (!m_changed) return true; - m_changed = false; + qWarning("going to save now"); +// if (!m_changed) return true; + + int total_written; + QString strFileNew = m_name + ".new"; + + QFile f( strFileNew ); + if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; + + QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); + buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; + buf += "<events>\n"; + QCString str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length() ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + if (!forAll( m_raw, f ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + if (!forAll( m_rep, f ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + + buf = "</events>\n</DATEBOOK>\n"; + str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length() ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + f.close(); + + exit(0); + if ( ::rename( strFileNew, m_name ) < 0 ) { + QFile::remove( strFileNew ); + return false; + } + + m_changed = false; return true; } QArray<int> ODateBookAccessBackend_XML::allRecords()const { QArray<int> ints( m_raw.count()+ m_rep.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { ints[i] = it.key(); i++; } for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int ) { return QArray<int>(); } void ODateBookAccessBackend_XML::clear() { m_raw.clear(); m_rep.clear(); } OEvent ODateBookAccessBackend_XML::find( int uid ) const{ if ( m_raw.contains( uid ) ) return m_raw[uid]; else return m_rep[uid]; } bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { @@ -154,83 +284,87 @@ OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { list.append( it.data() ); return list; } OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { OEvent::ValueList list; QMap<int, OEvent>::ConstIterator it; for (it = m_rep.begin(); it != m_rep.end(); ++it ) list.append( it.data() ); return list; } bool ODateBookAccessBackend_XML::loadFile() { m_changed = false; int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); if ( fd < 0 ) return false; struct stat attribute; if ( ::fstat(fd, &attribute ) == -1 ) { ::close( fd ); return false; } void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); if ( map_addr == ( (caddr_t)-1) ) { ::close( fd ); return false; } ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); ::close( fd ); - QAsciiDict<int> dict(FCreated+1); + QAsciiDict<int> dict(FExceptions+1); dict.setAutoDelete( true ); dict.insert( "description", new int(FDescription) ); dict.insert( "location", new int(FLocation) ); dict.insert( "categories", new int(FCategories) ); dict.insert( "uid", new int(FUid) ); dict.insert( "type", new int(FType) ); dict.insert( "alarm", new int(FAlarm) ); dict.insert( "sound", new int(FSound) ); dict.insert( "rtype", new int(FRType) ); dict.insert( "rweekdays", new int(FRWeekdays) ); dict.insert( "rposition", new int(FRPosition) ); dict.insert( "rfreq", new int(FRFreq) ); dict.insert( "rhasenddate", new int(FRHasEndDate) ); dict.insert( "enddt", new int(FREndDate) ); dict.insert( "start", new int(FRStart) ); dict.insert( "end", new int(FREnd) ); dict.insert( "note", new int(FNote) ); dict.insert( "created", new int(FCreated) ); + dict.insert( "recparent", new int(FRecParent) ); + dict.insert( "recchildren", new int(FRecChildren) ); + dict.insert( "exceptions", new int(FExceptions) ); + dict.insert( "timezone", new int(FTimeZone) ); char* dt = (char*)map_addr; int len = attribute.st_size; int i = 0; char* point; const char* collectionString = "<event "; int strLen = ::strlen(collectionString); int *find; while ( dt + 1 != 0 && (( point = ::strstr( dt+i, collectionString ) ) != 0 ) ) { i = point -dt; i+= strLen; alarmTime = -1; snd = 0; // silent OEvent ev; rec = 0; while ( TRUE ) { while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) ++i; if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) break; // we have another attribute, read it. int j = i; while ( j < len && dt[j] != '=' ) ++j; QCString attr( dt+i, j-i+1); i = ++j; // skip = @@ -260,68 +394,73 @@ bool ODateBookAccessBackend_XML::loadFile() { QString str = (haveUtf ? QString::fromUtf8( value ) : QString::fromLatin1( value ) ); if ( haveEnt ) str = Qtopia::plainString( str ); /* * add key + value */ find = dict[attr.data()]; if (!find) ev.setCustomField( attr, value ); else { setField( ev, *find, value ); } } /* time to finalize */ finalizeRecord( ev ); add( ev ); delete rec; } ::munmap(map_addr, attribute.st_size ); m_changed = false; // changed during add return true; } void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { /* AllDay is alway in UTC */ if ( ev.isAllDay() ) { OTimeZone utc = OTimeZone::utc(); ev.setStartDateTime( utc.fromUTCDateTime( start ) ); ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); + ev.setTimeZone( "UTC"); // make sure it is really utc }else { + /* to current date time */ OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); - ev.setStartDateTime( zone.toDateTime( start ) ); - ev.setEndDateTime ( zone.toDateTime( end ) ); + QDateTime date = zone.toDateTime( start ); + ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); + + date = zone.toDateTime( end ); + ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); } if ( rec && rec->doesRecur() ) { OTimeZone utc = OTimeZone::utc(); ORecur recu( *rec ); // call copy c'tor; recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); recu.setStart( ev.startDateTime().date() ); ev.setRecurrence( recu ); } if (alarmTime != -1 ) { QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); OPimAlarm al( snd , dt ); ev.notifiers().add( al ); } if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) { ev.setUid( 1 ); } if ( ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); else m_raw.insert( ev.uid(), ev ); } void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) { // qWarning(" setting %s", value.latin1() ); switch( id ) { case FDescription: e.setDescription( value ); break; case FLocation: e.setLocation( value ); @@ -360,36 +499,59 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val recur()->setType( ORecur::NoRepeat ); break; case FRWeekdays: recur()->setDays( value.toInt() ); break; case FRPosition: recur()->setPosition( value.toInt() ); break; case FRFreq: recur()->setFrequency( value.toInt() ); break; case FRHasEndDate: recur()->setHasEndDate( value.toInt() ); break; case FREndDate: { rp_end = (time_t) value.toLong(); break; } case FRStart: { start = (time_t) value.toLong(); break; } case FREnd: { end = ( (time_t) value.toLong() ); break; } case FNote: e.setNote( value ); break; case FCreated: created = value.toInt(); break; + case FRecParent: + e.setParent( value.toInt() ); + break; + case FRecChildren:{ + QStringList list = QStringList::split(' ', value ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + e.addChild( (*it).toInt() ); + } + } + break; + case FExceptions:{ + QStringList list = QStringList::split(' ', value ); + for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); + qWarning("adding exception %s", date.toString().latin1() ); + recur()->exceptions().append( date ); + } + } + break; + case FTimeZone: + if ( value != "None" ) + e.setTimeZone( value ); + break; default: break; } } |