summaryrefslogtreecommitdiff
path: root/libopie/pim
authorzecke <zecke>2003-02-21 23:31:52 (UTC)
committer zecke <zecke>2003-02-21 23:31:52 (UTC)
commit46f47c0a1e542a8b4222f3ced8f3304534c7509d (patch) (side-by-side diff)
tree82dc97a07bae77387987711c0c21697691955937 /libopie/pim
parenta7448ec87d97a0128618e83ad7526bd884ef8853 (diff)
downloadopie-46f47c0a1e542a8b4222f3ced8f3304534c7509d.zip
opie-46f47c0a1e542a8b4222f3ced8f3304534c7509d.tar.gz
opie-46f47c0a1e542a8b4222f3ced8f3304534c7509d.tar.bz2
Add XML datebookresource
-clean up todoaccessxml header -implement some more stuff in the oeven tester -extend DefaultFactory to not crash and to use datebook -reading of OEvents is working nicely.. saving will be added tomorrow -fix spelling in ODateBookAcces
Diffstat (limited to 'libopie/pim') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/pim/obackendfactory.h41
-rw-r--r--libopie/pim/odatebookaccess.cpp5
-rw-r--r--libopie/pim/odatebookaccess.h4
-rw-r--r--libopie/pim/odatebookaccessbackend_xml.cpp395
-rw-r--r--libopie/pim/odatebookaccessbackend_xml.h48
-rw-r--r--libopie/pim/oevent.cpp5
-rw-r--r--libopie/pim/opimnotify.h2
-rw-r--r--libopie/pim/otodoaccessxml.cpp2
-rw-r--r--libopie/pim/test/oevent_test.cpp27
9 files changed, 510 insertions, 19 deletions
diff --git a/libopie/pim/obackendfactory.h b/libopie/pim/obackendfactory.h
index b796fb8..3a73210 100644
--- a/libopie/pim/obackendfactory.h
+++ b/libopie/pim/obackendfactory.h
@@ -10,12 +10,22 @@
* either version 2 of the License, or (at your option) any later
* version.
* =====================================================================
- * ToDo: Use plugins
+ * ToDo: Use plugins
* =====================================================================
* Version: $Id$
* =====================================================================
* History:
* $Log$
+ * Revision 1.5 2003/02/21 23:31:52 zecke
+ * Add XML datebookresource
+ * -clean up todoaccessxml header
+ * -implement some more stuff in the oeven tester
+ * -extend DefaultFactory to not crash and to use datebook
+ *
+ * -reading of OEvents is working nicely.. saving will be added
+ * tomorrow
+ * -fix spelling in ODateBookAcces
+ *
* Revision 1.4 2002/10/14 15:55:18 eilers
* Redeactivate SQL.. ;)
*
@@ -47,6 +57,7 @@
#include "otodoaccessxml.h"
#include "ocontactaccessbackend_xml.h"
+#include "odatebookaccessbackend_xml.h"
#ifdef __USE_SQL
#include "otodoaccesssql.h"
@@ -64,9 +75,9 @@ class OBackendFactory
CONTACT,
DATE
};
-
+
static T* Default( const QString backendName, const QString& appName ){
-
+
// __asm__("int3");
Config config( "pimaccess" );
@@ -78,34 +89,40 @@ class OBackendFactory
dict.insert( "todo", new int (TODO) );
dict.insert( "contact", new int (CONTACT) );
+ dict.insert( "datebook", new int(DATE) );
qWarning ("TODO is: %d", TODO);
qWarning ("CONTACT is: %d", CONTACT);
-
- switch ( *dict.take( backendName ) ){
+
+ int *find = dict[ backendName ];
+ if (!find ) return 0;
+
+ switch ( *find ){
case TODO:
#ifdef __USE_SQL
- if ( backend == "sql" )
+ if ( backend == "sql" )
return (T*) new OTodoAccessBackendSQL("");
#else
- if ( backend == "sql" )
+ if ( backend == "sql" )
qWarning ("OBackendFactory:: sql Backend not implemented! Using XML instead!");
#endif
return (T*) new OTodoAccessXML( appName );
case CONTACT:
- if ( backend == "sql" )
+ if ( backend == "sql" )
qWarning ("OBackendFactory:: sql Backend not implemented! Using XML instead!");
return (T*) new OContactAccessBackend_XML( appName );
case DATE:
- qWarning ("OBackendFactory:: DATE-Backend not implemented!");
- return NULL;
+ if ( backend == "sql" )
+ qWarning("OBackendFactory:: sql Backend not implemented! Using XML instead!");
+
+ return (T*) new ODateBookAccessBackend_XML( appName );
default:
return NULL;
}
-
-
+
+
}
};
diff --git a/libopie/pim/odatebookaccess.cpp b/libopie/pim/odatebookaccess.cpp
index 5f97e7c..08e61ff 100644
--- a/libopie/pim/odatebookaccess.cpp
+++ b/libopie/pim/odatebookaccess.cpp
@@ -8,6 +8,7 @@ ODateBookAccess::ODateBookAccess( ODateBookAccessBackend* back, enum Access ac )
back = OBackendFactory<ODateBookAccessBackend>::Default("datebook", QString::null );
m_backEnd = back;
+ setBackEnd( m_backEnd );
}
ODateBookAccess::~ODateBookAccess() {
}
@@ -29,9 +30,9 @@ ODateBookAccess::List ODateBookAccess::nonRepeats()const {
List lis( ints, this );
return lis;
}
-OEffectiveEvent::ValueList ODateBookAccess::effecticeEvents( const QDate& from, const QDate& to ) {
+OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDate& from, const QDate& to ) {
return m_backEnd->effecticeEvents( from, to );
}
-OEffectiveEvent::ValueList ODateBookAccess::effecticeEvents( const QDateTime& start ) {
+OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDateTime& start ) {
return m_backEnd->effecticeEvents( start );
}
diff --git a/libopie/pim/odatebookaccess.h b/libopie/pim/odatebookaccess.h
index 3f2c728..7047039 100644
--- a/libopie/pim/odatebookaccess.h
+++ b/libopie/pim/odatebookaccess.h
@@ -20,8 +20,8 @@ public:
/** return non repeating events */
List nonRepeats()const;
- OEffectiveEvent::ValueList effecticeEvents( const QDate& from, const QDate& to );
- OEffectiveEvent::ValueList effecticeEvents( const QDateTime& start );
+ OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to );
+ OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start );
private:
ODateBookAccessBackend* m_backEnd;
diff --git a/libopie/pim/odatebookaccessbackend_xml.cpp b/libopie/pim/odatebookaccessbackend_xml.cpp
new file mode 100644
index 0000000..a4c514b
--- a/dev/null
+++ b/libopie/pim/odatebookaccessbackend_xml.cpp
@@ -0,0 +1,395 @@
+#include <errno.h>
+#include <fcntl.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 "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,
+ FAlarm,
+ FSound,
+ FRType,
+ FRWeekdays,
+ FRPosition,
+ FRFreq,
+ FRHasEndDate,
+ FREndDate,
+ FRStart,
+ FREnd,
+ FNote,
+ FCreated
+ };
+}
+
+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;
+
+ 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 ) {
+ 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() );
+ 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;
+}
+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);
+ 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) );
+
+ 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 =
+
+ // 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, 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 ) );
+ }else {
+ OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
+ ev.setStartDateTime( zone.toDateTime( start ) );
+ ev.setEndDateTime ( zone.toDateTime( end ) );
+ }
+ 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 );
+ 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;
+ default:
+ break;
+ }
+}
diff --git a/libopie/pim/odatebookaccessbackend_xml.h b/libopie/pim/odatebookaccessbackend_xml.h
new file mode 100644
index 0000000..40f69d8
--- a/dev/null
+++ b/libopie/pim/odatebookaccessbackend_xml.h
@@ -0,0 +1,48 @@
+#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H
+#define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H
+
+#include <qmap.h>
+
+#include "odatebookaccessbackend.h"
+
+class ODateBookAccessBackend_XML : public ODateBookAccessBackend {
+public:
+ ODateBookAccessBackend_XML( const QString& appName,
+ const QString& fileName = QString::null);
+ ~ODateBookAccessBackend_XML();
+
+ bool load();
+ bool reload();
+ bool save();
+
+ QArray<int> allRecords()const;
+ QArray<int> queryByExample( const OEvent&, int );
+ OEvent find( int uid )const;
+ void clear();
+ bool add( const OEvent& ev );
+ bool remove( int uid );
+ bool replace( const OEvent& ev );
+
+ QArray<UID> rawEvents()const;
+ QArray<UID> rawRepeats()const;
+ QArray<UID> nonRepeats()const;
+
+ OEvent::ValueList directNonRepeats();
+ OEvent::ValueList directRawRepeats();
+
+private:
+ bool m_changed :1 ;
+ bool loadFile();
+ inline void finalizeRecord( OEvent& ev );
+ inline void setField( OEvent&, int field, const QString& val );
+ QString m_name;
+ QMap<int, OEvent> m_raw;
+ QMap<int, OEvent> m_rep;
+
+ struct Data;
+ Data* data;
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/libopie/pim/oevent.cpp b/libopie/pim/oevent.cpp
index aaae3b2..ada596c 100644
--- a/libopie/pim/oevent.cpp
+++ b/libopie/pim/oevent.cpp
@@ -187,6 +187,11 @@ bool OEvent::isMultipleDay()const {
bool OEvent::isAllDay()const {
return data->isAllDay;
}
+void OEvent::setAllDay( bool allDay ) {
+ changeOrModify();
+ data->isAllDay = allDay;
+ if (allDay ) data->timezone = "UTC";
+}
void OEvent::setTimeZone( const QString& tz ) {
changeOrModify();
data->timezone = tz;
diff --git a/libopie/pim/opimnotify.h b/libopie/pim/opimnotify.h
index 3501948..b0de000 100644
--- a/libopie/pim/opimnotify.h
+++ b/libopie/pim/opimnotify.h
@@ -72,7 +72,7 @@ private:
*/
class OPimAlarm : public OPimNotify {
public:
- enum Sound{Loud=0, Silent, Custom };
+ enum Sound{Loud=1, Silent=0, Custom=2 };
OPimAlarm( int sound = Silent, const QDateTime& start = QDateTime(), int duration = 0, int parent = 0 );
OPimAlarm( const OPimAlarm& );
~OPimAlarm();
diff --git a/libopie/pim/otodoaccessxml.cpp b/libopie/pim/otodoaccessxml.cpp
index c3416cb..22b2469 100644
--- a/libopie/pim/otodoaccessxml.cpp
+++ b/libopie/pim/otodoaccessxml.cpp
@@ -15,8 +15,6 @@
#include <qpe/stringutil.h>
#include <qpe/timeconversion.h>
-#include <opie/xmltree.h>
-
#include "otodoaccessxml.h"
OTodoAccessXML::OTodoAccessXML( const QString& appName,
diff --git a/libopie/pim/test/oevent_test.cpp b/libopie/pim/test/oevent_test.cpp
index 50cc032..6f04995 100644
--- a/libopie/pim/test/oevent_test.cpp
+++ b/libopie/pim/test/oevent_test.cpp
@@ -1,6 +1,7 @@
#include <qdatetime.h>
#include "../oevent.h"
+#include "../odatebookaccess.h"
int main(int argc, char* argv ) {
OEvent ev;
@@ -19,5 +20,31 @@ int main(int argc, char* argv ) {
qWarning("%s", ev2.startDateTime().toString().latin1() );
qWarning("%s", ev2.startDateTimeInZone().toString().latin1() );
+
+ ODateBookAccess acc;
+ if(!acc.load() ) qWarning("could not load");
+
+ ODateBookAccess::List::Iterator it;
+ ODateBookAccess::List list = acc.allRecords();
+
+ for( it = list.begin(); it != list.end(); ++it ){
+ OEvent ev = (*it);
+ qWarning("Summary: %s",ev.description().latin1() );
+ qWarning("Start: %s End: %s",ev.startDateTime().toString().latin1(), ev.endDateTime().toString().latin1() );
+ qWarning("All Day: %d",ev.isAllDay() );
+
+ }
+ QDate date1(2003,02,01 );
+ QDate date2(2003,03,01 );
+
+ OEffectiveEvent::ValueList effList = acc.effectiveEvents( date1,date2 );
+ OEffectiveEvent::ValueList::Iterator effIt;
+
+ for( effIt = effList.begin(); effIt != effList.end(); ++effIt ){
+ OEffectiveEvent ef = (*effIt);
+ qWarning("Summary: %s", ef.description().latin1() );
+ qWarning("Date: %s", ef.date().toString().latin1() );
+ }
+
return 0;
}