summaryrefslogtreecommitdiff
path: root/libopie
Side-by-side diff
Diffstat (limited to 'libopie') (more/less context) (show whitespace changes)
-rw-r--r--libopie/pim/ocontactaccessbackend_xml.cpp739
1 files changed, 739 insertions, 0 deletions
diff --git a/libopie/pim/ocontactaccessbackend_xml.cpp b/libopie/pim/ocontactaccessbackend_xml.cpp
new file mode 100644
index 0000000..2df6757
--- a/dev/null
+++ b/libopie/pim/ocontactaccessbackend_xml.cpp
@@ -0,0 +1,739 @@
+/*
+ * XML Backend for the OPIE-Contact Database.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program 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.
+ * =====================================================================
+ * ToDo: XML-Backend: Automatic reload if something was changed...
+ *
+ *
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2003/02/09 15:05:01 eilers
+ * Nothing happened.. Just some cleanup before I will start..
+ *
+ * Revision 1.12 2003/01/03 16:58:03 eilers
+ * Reenable debug output
+ *
+ * Revision 1.11 2003/01/03 12:31:28 eilers
+ * Bugfix for calculating data diffs..
+ *
+ * Revision 1.10 2003/01/02 14:27:12 eilers
+ * Improved query by example: Search by date is possible.. First step
+ * for a today plugin for birthdays..
+ *
+ * Revision 1.9 2002/12/08 12:48:57 eilers
+ * Moved journal-enum from ocontact into i the xml-backend..
+ *
+ * Revision 1.8 2002/11/14 17:04:24 eilers
+ * Sorting will now work if fullname is identical on some entries
+ *
+ * Revision 1.7 2002/11/13 15:02:46 eilers
+ * Small Bug in sorted fixed
+ *
+ * Revision 1.6 2002/11/13 14:14:51 eilers
+ * Added sorted for Contacts..
+ *
+ * Revision 1.5 2002/11/01 15:10:42 eilers
+ * Added regExp-search in database for all fields in a contact.
+ *
+ * Revision 1.4 2002/10/16 10:52:40 eilers
+ * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
+ *
+ * Revision 1.3 2002/10/14 16:21:54 eilers
+ * Some minor interface updates
+ *
+ * Revision 1.2 2002/10/07 17:34:24 eilers
+ * added OBackendFactory for advanced backend access
+ *
+ * Revision 1.1 2002/09/27 17:11:44 eilers
+ * Added API for accessing the Contact-Database ! It is compiling, but
+ * please do not expect that anything is working !
+ * I will debug that stuff in the next time ..
+ * Please read README_COMPILE for compiling !
+ *
+ *
+ */
+
+#include "ocontactaccessbackend_xml.h"
+
+#include <qasciidict.h>
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qarray.h>
+#include <qmap.h>
+#include <qdatetime.h>
+
+#include <qpe/global.h>
+
+#include <opie/xmltree.h>
+#include "ocontactaccessbackend.h"
+#include "ocontactaccess.h"
+
+#include <stdlib.h>
+#include <errno.h>
+
+using namespace Opie;
+
+
+OContactAccessBackend_XML::OContactAccessBackend_XML ( QString appname, QString filename = 0l ):
+ m_changed( false )
+{
+ m_appName = appname;
+
+ /* Set journalfile name ... */
+ m_journalName = getenv("HOME");
+ m_journalName +="/.abjournal" + appname;
+
+ /* Expecting to access the default filename if nothing else is set */
+ if ( filename.isEmpty() ){
+ m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
+ } else
+ m_fileName = filename;
+
+ /* Load Database now */
+ load ();
+}
+
+bool OContactAccessBackend_XML::save()
+{
+
+ if ( !m_changed )
+ return true;
+
+ QString strNewFile = m_fileName + ".new";
+ QFile f( strNewFile );
+ if ( !f.open( IO_WriteOnly|IO_Raw ) )
+ return false;
+
+ int total_written;
+ QString out;
+ out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
+ " <Groups>\n"
+ " </Groups>\n"
+ " <Contacts>\n";
+ //QValueList<Contact>::iterator it;
+ QValueListConstIterator<OContact> it;
+ for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) {
+ out += "<Contact ";
+ (*it).save( out );
+ out += "/>\n";
+ QCString cstr = out.utf8();
+ total_written = f.writeBlock( cstr.data(), cstr.length() );
+ if ( total_written != int(cstr.length()) ) {
+ f.close();
+ QFile::remove( strNewFile );
+ return false;
+ }
+ out = "";
+ }
+ out += " </Contacts>\n</AddressBook>\n";
+
+ QCString cstr = out.utf8();
+ total_written = f.writeBlock( cstr.data(), cstr.length() );
+ if ( total_written != int( cstr.length() ) ) {
+ f.close();
+ QFile::remove( strNewFile );
+ return false;
+ }
+ f.close();
+
+ // move the file over, I'm just going to use the system call
+ // because, I don't feel like using QDir.
+ if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
+ qWarning( "problem renaming file %s to %s, errno: %d",
+ strNewFile.latin1(), m_journalName.latin1(), errno );
+ // remove the tmp file...
+ QFile::remove( strNewFile );
+ }
+
+ /* The journalfile should be removed now... */
+ removeJournal();
+
+ m_changed = false;
+ return true;
+}
+
+bool OContactAccessBackend_XML::load ()
+{
+ m_contactList.clear();
+
+ /* Load XML-File and journal if it exists */
+ if ( !load ( m_fileName, false ) )
+ return false;
+ /* The returncode of the journalfile is ignored due to the
+ * fact that it does not exist when this class is instantiated !
+ * But there may such a file exist, if the application crashed.
+ * Therefore we try to load it to get the changes before the #
+ * crash happened...
+ */
+ load (m_journalName, true);
+
+ return true;
+}
+
+void OContactAccessBackend_XML::clear ()
+{
+ m_contactList.clear();
+ m_changed = false;
+
+}
+
+bool OContactAccessBackend_XML::wasChangedExternally()
+{
+ QFileInfo fi( m_fileName );
+
+ QDateTime lastmod = fi.lastModified ();
+
+ return (lastmod != m_readtime);
+}
+
+QArray<int> OContactAccessBackend_XML::allRecords() const
+{
+ QArray<int> uid_list( m_contactList.count() );
+
+ uint counter = 0;
+ QValueListConstIterator<OContact> it;
+ for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
+ uid_list[counter++] = (*it).uid();
+ }
+
+ return ( uid_list );
+}
+
+OContact OContactAccessBackend_XML::find ( int uid ) const
+{
+ bool found = false;
+ OContact foundContact; //Create empty contact
+
+ QValueListConstIterator<OContact> it;
+ for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
+ if ((*it).uid() == uid){
+ found = true;
+ break;
+ }
+ }
+ if ( found ){
+ foundContact = *it;
+ }
+
+ return ( foundContact );
+}
+
+QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings )
+{
+
+ QArray<int> m_currentQuery( m_contactList.count() );
+ QValueListConstIterator<OContact> it;
+ uint arraycounter = 0;
+
+ for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
+ /* Search all fields and compare them with query object. Store them into list
+ * if all fields matches.
+ */
+ QDate* queryDate = 0l;
+ QDate* checkDate = 0l;
+ bool allcorrect = true;
+ for ( int i = 0; i < Qtopia::Groups; i++ ) {
+ // Birthday and anniversary are special nonstring fields and should
+ // be handled specially
+ switch ( i ){
+ case Qtopia::Birthday:
+ queryDate = new QDate( query.birthday() );
+ checkDate = new QDate( (*it).birthday() );
+ case Qtopia::Anniversary:
+ if ( queryDate == 0l ){
+ queryDate = new QDate( query.anniversary() );
+ checkDate = new QDate( (*it).anniversary() );
+ }
+
+ if ( queryDate->isValid() ){
+ if( checkDate->isValid() ){
+ if ( settings & OContactAccess::DateYear ){
+ if ( queryDate->year() != checkDate->year() )
+ allcorrect = false;
+ }
+ if ( settings & OContactAccess::DateMonth ){
+ if ( queryDate->month() != checkDate->month() )
+ allcorrect = false;
+ }
+ if ( settings & OContactAccess::DateDay ){
+ if ( queryDate->day() != checkDate->day() )
+ allcorrect = false;
+ }
+ if ( settings & OContactAccess::DateDiff ) {
+ QDate current = QDate::currentDate();
+ // We have to equalize the year, otherwise
+ // the search will fail..
+ checkDate->setYMD( current.year(),
+ checkDate->month(),
+ checkDate->day() );
+ if ( *checkDate < current )
+ checkDate->setYMD( current.year()+1,
+ checkDate->month(),
+ checkDate->day() );
+ qWarning("Checking if %s is between %s and %s ! ",
+ checkDate->toString().latin1(),
+ current.toString().latin1(),
+ queryDate->toString().latin1() );
+ if ( current.daysTo( *queryDate ) > 0 ){
+ if ( !( ( *checkDate >= current ) &&
+ ( *checkDate <= *queryDate ) ) ){
+ allcorrect = false;
+ qWarning (" Nope!..");
+ }
+ }
+ }
+ } else{
+ // checkDate is invalid. Therfore this entry is always rejected
+ allcorrect = false;
+ }
+ }
+
+ delete queryDate;
+ queryDate = 0l;
+ delete checkDate;
+ checkDate = 0l;
+ break;
+ default:
+ /* Just compare fields which are not empty in the query object */
+ if ( !query.field(i).isEmpty() ){
+ switch ( settings & ~( OContactAccess::IgnoreCase
+ | OContactAccess::DateDiff
+ | OContactAccess::DateYear
+ | OContactAccess::DateMonth
+ | OContactAccess::DateDay
+ | OContactAccess::MatchOne
+ ) ){
+
+ case OContactAccess::RegExp:{
+ QRegExp expr ( query.field(i),
+ !(settings & OContactAccess::IgnoreCase),
+ false );
+ if ( expr.find ( (*it).field(i), 0 ) == -1 )
+ allcorrect = false;
+ }
+ break;
+ case OContactAccess::WildCards:{
+ QRegExp expr ( query.field(i),
+ !(settings & OContactAccess::IgnoreCase),
+ true );
+ if ( expr.find ( (*it).field(i), 0 ) == -1 )
+ allcorrect = false;
+ }
+ break;
+ case OContactAccess::ExactMatch:{
+ if (settings & OContactAccess::IgnoreCase){
+ if ( query.field(i).upper() !=
+ (*it).field(i).upper() )
+ allcorrect = false;
+ }else{
+ if ( query.field(i) != (*it).field(i) )
+ allcorrect = false;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ if ( allcorrect ){
+ m_currentQuery[arraycounter++] = (*it).uid();
+ }
+ }
+
+ // Shrink to fit..
+ m_currentQuery.resize(arraycounter);
+
+ return m_currentQuery;
+}
+
+QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const
+{
+ QArray<int> m_currentQuery( m_contactList.count() );
+ QValueListConstIterator<OContact> it;
+ uint arraycounter = 0;
+
+ for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
+ if ( (*it).match( r ) ){
+ m_currentQuery[arraycounter++] = (*it).uid();
+ }
+
+ }
+ // Shrink to fit..
+ m_currentQuery.resize(arraycounter);
+
+ return m_currentQuery;
+}
+
+const uint OContactAccessBackend_XML::querySettings()
+{
+ return ( OContactAccess::WildCards
+ | OContactAccess::IgnoreCase
+ | OContactAccess::RegExp
+ | OContactAccess::ExactMatch
+ | OContactAccess::DateDiff
+ | OContactAccess::DateYear
+ | OContactAccess::DateMonth
+ | OContactAccess::DateDay
+ );
+}
+
+bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const
+{
+ /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
+ * may be added with any of the other settings. IgnoreCase should never used alone.
+ * Wildcards, RegExp, ExactMatch should never used at the same time...
+ */
+
+ if ( querySettings == OContactAccess::IgnoreCase )
+ return false;
+
+ switch ( querySettings & ~( OContactAccess::IgnoreCase
+ | OContactAccess::DateDiff
+ | OContactAccess::DateYear
+ | OContactAccess::DateMonth
+ | OContactAccess::DateDay
+ )
+ ){
+ case OContactAccess::RegExp:
+ return ( true );
+ case OContactAccess::WildCards:
+ return ( true );
+ case OContactAccess::ExactMatch:
+ return ( true );
+ default:
+ return ( false );
+ }
+}
+
+// Currently only asc implemented..
+QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int )
+{
+ QMap<QString, int> nameToUid;
+ QStringList names;
+ QArray<int> m_currentQuery( m_contactList.count() );
+
+ // First fill map and StringList with all Names
+ // Afterwards sort namelist and use map to fill array to return..
+ QValueListConstIterator<OContact> it;
+ for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
+ names.append( (*it).fileAs() + QString::number( (*it).uid() ) );
+ nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() );
+ }
+ names.sort();
+
+ int i = 0;
+ if ( asc ){
+ for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
+ m_currentQuery[i++] = nameToUid[ (*it) ];
+ }else{
+ for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
+ m_currentQuery[i++] = nameToUid[ (*it) ];
+ }
+
+ return m_currentQuery;
+
+}
+
+bool OContactAccessBackend_XML::add ( const OContact &newcontact )
+{
+ //qWarning("odefaultbackend: ACTION::ADD");
+ updateJournal (newcontact, ACTION_ADD);
+ addContact_p( newcontact );
+
+ m_changed = true;
+
+ return true;
+}
+
+bool OContactAccessBackend_XML::replace ( const OContact &contact )
+{
+ m_changed = true;
+
+ bool found = false;
+
+ QValueListIterator<OContact> it;
+ for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
+ if ( (*it).uid() == contact.uid() ){
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ updateJournal (contact, ACTION_REPLACE);
+ m_contactList.remove (it);
+ m_contactList.append (contact);
+ return true;
+ } else
+ return false;
+}
+
+bool OContactAccessBackend_XML::remove ( int uid )
+{
+ m_changed = true;
+
+ bool found = false;
+ QValueListIterator<OContact> it;
+ for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
+ if ((*it).uid() == uid){
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ updateJournal ( *it, ACTION_REMOVE);
+ m_contactList.remove (it);
+ return true;
+ } else
+ return false;
+}
+
+bool OContactAccessBackend_XML::reload(){
+ /* Reload is the same as load in this implementation */
+ return ( load() );
+}
+
+void OContactAccessBackend_XML::addContact_p( const OContact &newcontact )
+{
+ m_contactList.append (newcontact);
+}
+
+/* This function loads the xml-database and the journalfile */
+bool OContactAccessBackend_XML::load( const QString filename, bool isJournal )
+{
+
+ /* We use the time of the last read to check if the file was
+ * changed externally.
+ */
+ if ( !isJournal ){
+ QFileInfo fi( filename );
+ m_readtime = fi.lastModified ();
+ }
+
+ const int JOURNALACTION = Qtopia::Notes + 1;
+ const int JOURNALROW = JOURNALACTION + 1;
+
+ bool foundAction = false;
+ journal_action action = ACTION_ADD;
+ int journalKey = 0;
+ QMap<int, QString> contactMap;
+ QMap<QString, QString> customMap;
+ QMap<QString, QString>::Iterator customIt;
+ QAsciiDict<int> dict( 47 );
+
+ dict.setAutoDelete( TRUE );
+ dict.insert( "Uid", new int(Qtopia::AddressUid) );
+ dict.insert( "Title", new int(Qtopia::Title) );
+ dict.insert( "FirstName", new int(Qtopia::FirstName) );
+ dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
+ dict.insert( "LastName", new int(Qtopia::LastName) );
+ dict.insert( "Suffix", new int(Qtopia::Suffix) );
+ dict.insert( "FileAs", new int(Qtopia::FileAs) );
+ dict.insert( "Categories", new int(Qtopia::AddressCategory) );
+ dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
+ dict.insert( "Emails", new int(Qtopia::Emails) );
+ dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
+ dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
+ dict.insert( "HomeState", new int(Qtopia::HomeState) );
+ dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
+ dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
+ dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
+ dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
+ dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
+ dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
+ dict.insert( "Company", new int(Qtopia::Company) );
+ dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
+ dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
+ dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
+ dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
+ dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
+ dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
+ dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
+ dict.insert( "Department", new int(Qtopia::Department) );
+ dict.insert( "Office", new int(Qtopia::Office) );
+ dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
+ dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
+ dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
+ dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
+ dict.insert( "Profession", new int(Qtopia::Profession) );
+ dict.insert( "Assistant", new int(Qtopia::Assistant) );
+ dict.insert( "Manager", new int(Qtopia::Manager) );
+ dict.insert( "Spouse", new int(Qtopia::Spouse) );
+ dict.insert( "Children", new int(Qtopia::Children) );
+ dict.insert( "Gender", new int(Qtopia::Gender) );
+ dict.insert( "Birthday", new int(Qtopia::Birthday) );
+ dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
+ dict.insert( "Nickname", new int(Qtopia::Nickname) );
+ dict.insert( "Notes", new int(Qtopia::Notes) );
+ dict.insert( "action", new int(JOURNALACTION) );
+ dict.insert( "actionrow", new int(JOURNALROW) );
+
+ //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
+
+ XMLElement *root = XMLElement::load( filename );
+ if(root != 0l ){ // start parsing
+ /* Parse all XML-Elements and put the data into the
+ * Contact-Class
+ */
+ XMLElement *element = root->firstChild();
+ //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
+ element = element->firstChild();
+
+ /* Search Tag "Contacts" which is the parent of all Contacts */
+ while( element && !isJournal ){
+ if( element->tagName() != QString::fromLatin1("Contacts") ){
+ //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
+ // element->tagName().latin1());
+ element = element->nextChild();
+ } else {
+ element = element->firstChild();
+ break;
+ }
+ }
+ /* Parse all Contacts and ignore unknown tags */
+ while( element ){
+ if( element->tagName() != QString::fromLatin1("Contact") ){
+ //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
+ // element->tagName().latin1());
+ element = element->nextChild();
+ continue;
+ }
+ /* Found alement with tagname "contact", now parse and store all
+ * attributes contained
+ */
+ //qWarning("OContactDefBack::load element tagName() : %s",
+ // element->tagName().latin1() );
+ QString dummy;
+ foundAction = false;
+
+ XMLElement::AttributeMap aMap = element->attributes();
+ XMLElement::AttributeMap::Iterator it;
+ contactMap.clear();
+ customMap.clear();
+ for( it = aMap.begin(); it != aMap.end(); ++it ){
+ // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
+
+ int *find = dict[ it.key() ];
+ /* Unknown attributes will be stored as "Custom" elements */
+ if ( !find ) {
+ qWarning("Attribute %s not known.", it.key().latin1());
+ //contact.setCustomField(it.key(), it.data());
+ customMap.insert( it.key(), it.data() );
+ continue;
+ }
+
+ /* Check if special conversion is needed and add attribute
+ * into Contact class
+ */
+ switch( *find ) {
+ /*
+ case Qtopia::AddressUid:
+ contact.setUid( it.data().toInt() );
+ break;
+ case Qtopia::AddressCategory:
+ contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
+ break;
+ */
+ case JOURNALACTION:
+ action = journal_action(it.data().toInt());
+ foundAction = true;
+ qWarning ("ODefBack(journal)::ACTION found: %d", action);
+ break;
+ case JOURNALROW:
+ journalKey = it.data().toInt();
+ break;
+ default: // no conversion needed add them to the map
+ contactMap.insert( *find, it.data() );
+ break;
+ }
+ }
+ /* now generate the Contact contact */
+ OContact contact( contactMap );
+
+ for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
+ contact.setCustomField( customIt.key(), customIt.data() );
+ }
+
+ if (foundAction){
+ foundAction = false;
+ switch ( action ) {
+ case ACTION_ADD:
+ addContact_p (contact);
+ break;
+ case ACTION_REMOVE:
+ if ( !remove (contact.uid()) )
+ qWarning ("ODefBack(journal)::Unable to remove uid: %d",
+ contact.uid() );
+ break;
+ case ACTION_REPLACE:
+ if ( !replace ( contact ) )
+ qWarning ("ODefBack(journal)::Unable to replace uid: %d",
+ contact.uid() );
+ break;
+ default:
+ qWarning ("Unknown action: ignored !");
+ break;
+ }
+ }else{
+ /* Add contact to list */
+ addContact_p (contact);
+ }
+
+ /* Move to next element */
+ element = element->nextChild();
+ }
+ }else {
+ qWarning("ODefBack::could not load");
+ }
+ delete root;
+ qWarning("returning from loading" );
+ return true;
+}
+
+
+void OContactAccessBackend_XML::updateJournal( const OContact& cnt,
+ journal_action action )
+{
+ QFile f( m_journalName );
+ bool created = !f.exists();
+ if ( !f.open(IO_WriteOnly|IO_Append) )
+ return;
+
+ QString buf;
+ QCString str;
+
+ // if the file was created, we have to set the Tag "<CONTACTS>" to
+ // get a XML-File which is readable by our parser.
+ // This is just a cheat, but better than rewrite the parser.
+ if ( created ){
+ buf = "<Contacts>";
+ QCString cstr = buf.utf8();
+ f.writeBlock( cstr.data(), cstr.length() );
+ }
+
+ buf = "<Contact ";
+ cnt.save( buf );
+ buf += " action=\"" + QString::number( (int)action ) + "\" ";
+ buf += "/>\n";
+ QCString cstr = buf.utf8();
+ f.writeBlock( cstr.data(), cstr.length() );
+}
+
+void OContactAccessBackend_XML::removeJournal()
+{
+ QFile f ( m_journalName );
+ if ( f.exists() )
+ f.remove();
+}
+