summaryrefslogtreecommitdiff
path: root/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp
Side-by-side diff
Diffstat (limited to 'noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp') (more/less context) (show whitespace changes)
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp612
1 files changed, 612 insertions, 0 deletions
diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp
new file mode 100644
index 0000000..929d004
--- a/dev/null
+++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp
@@ -0,0 +1,612 @@
+#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 {
+ // FROM TT again
+char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
+{
+ char needleChar;
+ char haystackChar;
+ if (!needle || !haystack || !hLen || !nLen)
+ return 0;
+
+ const char* hsearch = haystack;
+
+ if ((needleChar = *needle++) != 0) {
+ nLen--; //(to make up for needle++)
+ do {
+ do {
+ if ((haystackChar = *hsearch++) == 0)
+ return (0);
+ if (hsearch >= haystack + hLen)
+ return (0);
+ } while (haystackChar != needleChar);
+ } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
+ hsearch--;
+ }
+ return ((char *)hsearch);
+}
+}
+
+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,
+ FAlarm,
+ FSound,
+ FRType,
+ FRWeekdays,
+ FRPosition,
+ FRFreq,
+ FRHasEndDate,
+ FREndDate,
+ FRStart,
+ FREnd,
+ FNote,
+ FCreated, // Should't this be called FRCreated ?
+ FTimeZone,
+ FRecParent,
+ FRecChildren,
+ FExceptions
+ };
+
+ // FIXME: Use OEvent::toMap() here !! (eilers)
+ inline void save( const OEvent& ev, QString& buf ) {
+ qWarning("Saving %d %s", ev.uid(), ev.description().latin1() );
+ 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\""; // is that all ?? (eilers)
+
+ 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();
+ buf += "\"";
+
+ 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;
+
+ 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();
+
+ 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, const QDateTime& ) {
+ return QArray<int>();
+}
+void ODateBookAccessBackend_XML::clear() {
+ m_changed = true;
+ 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 ) {
+ m_changed = true;
+ if (ev.hasRecurrence() )
+ m_rep.insert( ev.uid(), ev );
+ else
+ m_raw.insert( ev.uid(), ev );
+
+ return true;
+}
+bool ODateBookAccessBackend_XML::remove( int uid ) {
+ m_changed = true;
+ m_rep.remove( uid );
+ m_rep.remove( uid );
+
+ return true;
+}
+bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) {
+ replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers)
+ return add( ev );
+}
+QArray<int> ODateBookAccessBackend_XML::rawEvents()const {
+ return allRecords();
+}
+QArray<int> ODateBookAccessBackend_XML::rawRepeats()const {
+ QArray<int> ints( m_rep.count() );
+ uint i = 0;
+ QMap<int, OEvent>::ConstIterator it;
+
+ for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
+ ints[i] = it.key();
+ i++;
+ }
+
+ return ints;
+}
+QArray<int> ODateBookAccessBackend_XML::nonRepeats()const {
+ QArray<int> ints( m_raw.count() );
+ uint i = 0;
+ QMap<int, OEvent>::ConstIterator it;
+
+ for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
+ ints[i] = it.key();
+ i++;
+ }
+
+ return ints;
+}
+OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() {
+ OEvent::ValueList list;
+ QMap<int, OEvent>::ConstIterator it;
+ for (it = m_raw.begin(); it != m_raw.end(); ++it )
+ 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;
+}
+
+// FIXME: Use OEvent::fromMap() (eilers)
+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(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) ); // Shouldn't this be FRCreated ??
+ 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 ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 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 =
+
+ // find the start of quotes
+ while ( i < len && dt[i] != '"' )
+ ++i;
+ j = ++i;
+
+ bool haveUtf = FALSE;
+ bool haveEnt = FALSE;
+ while ( j < len && dt[j] != '"' ) {
+ if ( ((unsigned char)dt[j]) > 0x7f )
+ haveUtf = TRUE;
+ if ( dt[j] == '&' )
+ haveEnt = TRUE;
+ ++j;
+ }
+ if ( i == j ) {
+ // empty value
+ i = j + 1;
+ continue;
+ }
+
+ QCString value( dt+i, j-i+1 );
+ i = j + 1;
+
+ 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, str );
+ else {
+ setField( ev, *find, str );
+ }
+ }
+ /* time to finalize */
+ finalizeRecord( ev );
+ delete rec;
+ }
+ ::munmap(map_addr, attribute.st_size );
+ m_changed = false; // changed during add
+
+ return true;
+}
+
+// FIXME: Use OEvent::fromMap() which makes this obsolete.. (eilers)
+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 */
+ // qWarning(" Start is %d", start );
+ OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
+ QDateTime date = zone.toDateTime( start );
+ qWarning(" Start is %s", date.toString().latin1() );
+ 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() ) ) {
+ qWarning("already contains assign uid");
+ ev.setUid( 1 );
+ }
+ qWarning("addind %d %s", ev.uid(), ev.description().latin1() );
+ 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 );
+ break;
+ case FCategories:
+ e.setCategories( e.idsFromString( value ) );
+ break;
+ case FUid:
+ e.setUid( value.toInt() );
+ break;
+ case FType:
+ if ( value == "AllDay" ) {
+ e.setAllDay( true );
+ e.setTimeZone( "UTC" );
+ }
+ break;
+ case FAlarm:
+ alarmTime = value.toInt();
+ break;
+ case FSound:
+ snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent;
+ break;
+ // recurrence stuff
+ case FRType:
+ if ( value == "Daily" )
+ recur()->setType( ORecur::Daily );
+ else if ( value == "Weekly" )
+ recur()->setType( ORecur::Weekly);
+ else if ( value == "MonthlyDay" )
+ recur()->setType( ORecur::MonthlyDay );
+ else if ( value == "MonthlyDate" )
+ recur()->setType( ORecur::MonthlyDate );
+ else if ( value == "Yearly" )
+ recur()->setType( ORecur::Yearly );
+ else
+ 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;
+ }
+}
+QArray<int> ODateBookAccessBackend_XML::matchRegexp( const QRegExp &r ) const
+{
+ QArray<int> m_currentQuery( m_raw.count()+ m_rep.count() );
+ uint arraycounter = 0;
+ QMap<int, OEvent>::ConstIterator it;
+
+ for ( it = m_raw.begin(); it != m_raw.end(); ++it )
+ if ( it.data().match( r ) )
+ m_currentQuery[arraycounter++] = it.data().uid();
+ for ( it = m_rep.begin(); it != m_rep.end(); ++it )
+ if ( it.data().match( r ) )
+ m_currentQuery[arraycounter++] = it.data().uid();
+
+ // Shrink to fit..
+ m_currentQuery.resize(arraycounter);
+
+ return m_currentQuery;
+}