libopie PIM API Documentation

ocontactaccessbackend_xml.cpp

Go to the documentation of this file.
00001 /*
00002  * XML Backend for the OPIE-Contact Database.
00003  *
00004  * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
00005  *
00006  * =====================================================================
00007  *  This program is free software; you can redistribute it and/or
00008  *  modify it under the terms of the GNU Library General Public
00009  *      License as published by the Free Software Foundation; either
00010  *      version 2 of the License, or (at your option) any later version.
00011  * =====================================================================
00012  *
00013  * =====================================================================
00014  * Version: $Id: ocontactaccessbackend_xml.cpp,v 1.9 2003/09/22 14:31:16 eilers Exp $
00015  * =====================================================================
00016  * History:
00017  * $Log: ocontactaccessbackend_xml.cpp,v $
00018  * Revision 1.9  2003/09/22 14:31:16  eilers
00019  * Added first experimental incarnation of sql-backend for addressbook.
00020  * Some modifications to be able to compile the todo sql-backend.
00021  * A lot of changes fill follow...
00022  *
00023  * Revision 1.8  2003/08/30 15:28:26  eilers
00024  * Removed some unimportant debug output which causes slow down..
00025  *
00026  * Revision 1.7  2003/08/01 12:30:16  eilers
00027  * Merging changes from BRANCH_1_0 to HEAD
00028  *
00029  * Revision 1.6  2003/07/07 16:19:47  eilers
00030  * Fixing serious bug in hasQuerySettings()
00031  *
00032  * Revision 1.5  2003/04/13 18:07:10  zecke
00033  * More API doc
00034  * QString -> const QString&
00035  * QString = 0l -> QString::null
00036  *
00037  * Revision 1.4  2003/03/21 14:32:54  mickeyl
00038  * g++ compliance fix: default arguments belong into the declaration, but not the definition
00039  *
00040  * Revision 1.3  2003/03/21 12:26:28  eilers
00041  * Fixing small bug: If we search a birthday from today to today, it returned
00042  * every contact ..
00043  *
00044  * Revision 1.2  2003/03/21 10:33:09  eilers
00045  * Merged speed optimized xml backend for contacts to main.
00046  * Added QDateTime to querybyexample. For instance, it is now possible to get
00047  * all Birthdays/Anniversaries between two dates. This should be used
00048  * to show all birthdays in the datebook..
00049  * This change is sourcecode backward compatible but you have to upgrade
00050  * the binaries for today-addressbook.
00051  *
00052  * Revision 1.1.2.2  2003/02/11 12:17:28  eilers
00053  * Speed optimization. Removed the sequential search loops.
00054  *
00055  * Revision 1.1.2.1  2003/02/10 15:31:38  eilers
00056  * Writing offsets to debug output..
00057  *
00058  * Revision 1.1  2003/02/09 15:05:01  eilers
00059  * Nothing happened.. Just some cleanup before I will start..
00060  *
00061  * Revision 1.12  2003/01/03 16:58:03  eilers
00062  * Reenable debug output
00063  *
00064  * Revision 1.11  2003/01/03 12:31:28  eilers
00065  * Bugfix for calculating data diffs..
00066  *
00067  * Revision 1.10  2003/01/02 14:27:12  eilers
00068  * Improved query by example: Search by date is possible.. First step
00069  * for a today plugin for birthdays..
00070  *
00071  * Revision 1.9  2002/12/08 12:48:57  eilers
00072  * Moved journal-enum from ocontact into i the xml-backend..
00073  *
00074  * Revision 1.8  2002/11/14 17:04:24  eilers
00075  * Sorting will now work if fullname is identical on some entries
00076  *
00077  * Revision 1.7  2002/11/13 15:02:46  eilers
00078  * Small Bug in sorted fixed
00079  *
00080  * Revision 1.6  2002/11/13 14:14:51  eilers
00081  * Added sorted for Contacts..
00082  *
00083  * Revision 1.5  2002/11/01 15:10:42  eilers
00084  * Added regExp-search in database for all fields in a contact.
00085  *
00086  * Revision 1.4  2002/10/16 10:52:40  eilers
00087  * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
00088  *
00089  * Revision 1.3  2002/10/14 16:21:54  eilers
00090  * Some minor interface updates
00091  *
00092  * Revision 1.2  2002/10/07 17:34:24  eilers
00093  * added OBackendFactory for advanced backend access
00094  *
00095  * Revision 1.1  2002/09/27 17:11:44  eilers
00096  * Added API for accessing the Contact-Database ! It is compiling, but
00097  * please do not expect that anything is working !
00098  * I will debug that stuff in the next time ..
00099  * Please read README_COMPILE for compiling !
00100  *
00101  *
00102  */
00103 
00104 #include "ocontactaccessbackend_xml.h"
00105 
00106 #include <qasciidict.h>
00107 #include <qdatetime.h>
00108 #include <qfile.h>
00109 #include <qfileinfo.h>
00110 #include <qregexp.h>
00111 #include <qarray.h>
00112 #include <qmap.h>
00113 #include <qdatetime.h>
00114 
00115 #include <qpe/global.h>
00116 
00117 #include <opie/xmltree.h>
00118 #include "ocontactaccessbackend.h"
00119 #include "ocontactaccess.h"
00120 
00121 #include <stdlib.h>
00122 #include <errno.h>
00123 
00124 using namespace Opie;
00125 
00126 
00127 OContactAccessBackend_XML::OContactAccessBackend_XML ( const QString& appname, const QString& filename ):
00128     m_changed( false )
00129 {
00130     // Just m_contactlist should call delete if an entry
00131     // is removed.
00132     m_contactList.setAutoDelete( true );
00133     m_uidToContact.setAutoDelete( false );
00134 
00135     m_appName = appname;
00136 
00137     /* Set journalfile name ... */
00138     m_journalName = getenv("HOME");
00139     m_journalName +="/.abjournal" + appname;
00140 
00141     /* Expecting to access the default filename if nothing else is set */
00142     if ( filename.isEmpty() ){
00143         m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
00144     } else
00145         m_fileName = filename;
00146 
00147     /* Load Database now */
00148     load ();
00149 }
00150 
00151 bool OContactAccessBackend_XML::save()
00152 {
00153 
00154     if ( !m_changed )
00155         return true;
00156 
00157     QString strNewFile = m_fileName + ".new";
00158     QFile f( strNewFile );
00159     if ( !f.open( IO_WriteOnly|IO_Raw ) )
00160         return false;
00161 
00162     int total_written;
00163     int idx_offset = 0;
00164     QString out;
00165 
00166     // Write Header
00167     out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
00168         " <Groups>\n"
00169         " </Groups>\n"
00170         " <Contacts>\n";
00171     QCString cstr = out.utf8();
00172     f.writeBlock( cstr.data(), cstr.length() );
00173     idx_offset += cstr.length();
00174     out = "";
00175 
00176     // Write all contacts
00177     QListIterator<OContact> it( m_contactList );
00178     for ( ; it.current(); ++it ) {
00179         // qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset );
00180         out += "<Contact ";
00181         (*it)->save( out );
00182         out += "/>\n";
00183         cstr = out.utf8();
00184         total_written = f.writeBlock( cstr.data(), cstr.length() );
00185         idx_offset += cstr.length();
00186         if ( total_written != int(cstr.length()) ) {
00187             f.close();
00188             QFile::remove( strNewFile );
00189             return false;
00190         }
00191         out = "";
00192     }
00193     out += " </Contacts>\n</AddressBook>\n";
00194 
00195     // Write Footer
00196     cstr = out.utf8();
00197     total_written = f.writeBlock( cstr.data(), cstr.length() );
00198     if ( total_written != int( cstr.length() ) ) {
00199         f.close();
00200         QFile::remove( strNewFile );
00201         return false;
00202     }
00203     f.close();
00204 
00205     // move the file over, I'm just going to use the system call
00206     // because, I don't feel like using QDir.
00207     if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
00208         qWarning( "problem renaming file %s to %s, errno: %d",
00209               strNewFile.latin1(), m_journalName.latin1(), errno );
00210         // remove the tmp file...
00211         QFile::remove( strNewFile );
00212     }
00213 
00214     /* The journalfile should be removed now... */
00215     removeJournal();
00216 
00217     m_changed = false;
00218     return true;
00219 }
00220 
00221 bool OContactAccessBackend_XML::load ()
00222 {
00223     m_contactList.clear();
00224     m_uidToContact.clear();
00225 
00226     /* Load XML-File and journal if it exists */
00227     if ( !load ( m_fileName, false ) )
00228         return false;
00229     /* The returncode of the journalfile is ignored due to the
00230      * fact that it does not exist when this class is instantiated !
00231      * But there may such a file exist, if the application crashed.
00232      * Therefore we try to load it to get the changes before the #
00233      * crash happened...
00234      */
00235     load (m_journalName, true);
00236 
00237     return true;
00238 }
00239 
00240 void OContactAccessBackend_XML::clear ()
00241 {
00242     m_contactList.clear();
00243     m_uidToContact.clear();
00244 
00245     m_changed = false;
00246 }
00247 
00248 bool OContactAccessBackend_XML::wasChangedExternally()
00249 {
00250     QFileInfo fi( m_fileName );
00251 
00252     QDateTime lastmod = fi.lastModified ();
00253 
00254     return (lastmod != m_readtime);
00255 }
00256 
00257 QArray<int> OContactAccessBackend_XML::allRecords() const
00258 {
00259     QArray<int> uid_list( m_contactList.count() );
00260 
00261     uint counter = 0;
00262     QListIterator<OContact> it( m_contactList );
00263     for( ; it.current(); ++it ){
00264         uid_list[counter++] = (*it)->uid();
00265     }
00266 
00267     return ( uid_list );
00268 }
00269 
00270 OContact OContactAccessBackend_XML::find ( int uid ) const
00271 {
00272     OContact foundContact; //Create empty contact
00273 
00274     OContact* found = m_uidToContact.find( QString().setNum( uid ) );
00275 
00276     if ( found ){
00277         foundContact = *found;
00278     }
00279 
00280     return ( foundContact );
00281 }
00282 
00283 QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings,
00284                             const QDateTime& d )
00285 {
00286 
00287     QArray<int> m_currentQuery( m_contactList.count() );
00288     QListIterator<OContact> it( m_contactList );
00289     uint arraycounter = 0;
00290 
00291     for( ; it.current(); ++it ){
00292         /* Search all fields and compare them with query object. Store them into list
00293          * if all fields matches.
00294          */
00295         QDate* queryDate = 0l;
00296         QDate* checkDate = 0l;
00297         bool allcorrect = true;
00298         for ( int i = 0; i < Qtopia::Groups; i++ ) {
00299             // Birthday and anniversary are special nonstring fields and should
00300             // be handled specially
00301             switch ( i ){
00302             case Qtopia::Birthday:
00303                 queryDate = new QDate( query.birthday() );
00304                 checkDate = new QDate( (*it)->birthday() );
00305             case Qtopia::Anniversary:
00306                 if ( queryDate == 0l ){
00307                     queryDate = new QDate( query.anniversary() );
00308                     checkDate = new QDate( (*it)->anniversary() );
00309                 }
00310 
00311                 if ( queryDate->isValid() ){
00312                     if(  checkDate->isValid() ){
00313                         if ( settings & OContactAccess::DateYear ){
00314                             if ( queryDate->year() != checkDate->year() )
00315                                 allcorrect = false;
00316                         }
00317                         if ( settings & OContactAccess::DateMonth ){
00318                             if ( queryDate->month() != checkDate->month() )
00319                                 allcorrect = false;
00320                         }
00321                         if ( settings & OContactAccess::DateDay ){
00322                             if ( queryDate->day() != checkDate->day() )
00323                                 allcorrect = false;
00324                         }
00325                         if ( settings & OContactAccess::DateDiff ) {
00326                             QDate current;
00327                             // If we get an additional date, we
00328                             // will take this date instead of
00329                             // the current one..
00330                             if ( !d.date().isValid() )
00331                                 current = QDate::currentDate();
00332                             else
00333                                 current = d.date();
00334 
00335                             // We have to equalize the year, otherwise
00336                             // the search will fail..
00337                             checkDate->setYMD( current.year(),
00338                                        checkDate->month(),
00339                                        checkDate->day() );
00340                             if ( *checkDate < current )
00341                                 checkDate->setYMD( current.year()+1,
00342                                            checkDate->month(),
00343                                            checkDate->day() );
00344 
00345                             // Check whether the birthday/anniversary date is between
00346                             // the current/given date and the maximum date
00347                             // ( maximum time range ) !
00348                             qWarning("Checking if %s is between %s and %s ! ",
00349                                  checkDate->toString().latin1(),
00350                                  current.toString().latin1(),
00351                                  queryDate->toString().latin1() );
00352                             if ( current.daysTo( *queryDate ) >= 0 ){
00353                                 if ( !( ( *checkDate >= current ) &&
00354                                     ( *checkDate <= *queryDate ) ) ){
00355                                     allcorrect = false;
00356                                     qWarning (" Nope!..");
00357                                 }
00358                             }
00359                         }
00360                     } else{
00361                         // checkDate is invalid. Therefore this entry is always rejected
00362                         allcorrect = false;
00363                     }
00364                 }
00365 
00366                 delete queryDate;
00367                 queryDate = 0l;
00368                 delete checkDate;
00369                 checkDate = 0l;
00370                 break;
00371             default:
00372                 /* Just compare fields which are not empty in the query object */
00373                 if ( !query.field(i).isEmpty() ){
00374                     switch ( settings & ~( OContactAccess::IgnoreCase
00375                                    | OContactAccess::DateDiff
00376                                    | OContactAccess::DateYear
00377                                    | OContactAccess::DateMonth
00378                                    | OContactAccess::DateDay
00379                                    | OContactAccess::MatchOne
00380                                    ) ){
00381 
00382                     case OContactAccess::RegExp:{
00383                         QRegExp expr ( query.field(i),
00384                                    !(settings & OContactAccess::IgnoreCase),
00385                                    false );
00386                         if ( expr.find ( (*it)->field(i), 0 ) == -1 )
00387                             allcorrect = false;
00388                     }
00389                         break;
00390                     case OContactAccess::WildCards:{
00391                         QRegExp expr ( query.field(i),
00392                                    !(settings & OContactAccess::IgnoreCase),
00393                                    true );
00394                         if ( expr.find ( (*it)->field(i), 0 ) == -1 )
00395                             allcorrect = false;
00396                     }
00397                         break;
00398                     case OContactAccess::ExactMatch:{
00399                         if (settings & OContactAccess::IgnoreCase){
00400                             if ( query.field(i).upper() !=
00401                                  (*it)->field(i).upper() )
00402                                 allcorrect = false;
00403                         }else{
00404                             if ( query.field(i) != (*it)->field(i) )
00405                                 allcorrect = false;
00406                         }
00407                     }
00408                         break;
00409                     }
00410                 }
00411             }
00412         }
00413         if ( allcorrect ){
00414             m_currentQuery[arraycounter++] = (*it)->uid();
00415         }
00416     }
00417 
00418     // Shrink to fit..
00419     m_currentQuery.resize(arraycounter);
00420 
00421     return m_currentQuery;
00422 }
00423 
00424 QArray<int> OContactAccessBackend_XML::matchRegexp(  const QRegExp &r ) const
00425 {
00426     QArray<int> m_currentQuery( m_contactList.count() );
00427     QListIterator<OContact> it( m_contactList );
00428     uint arraycounter = 0;
00429 
00430     for( ; it.current(); ++it ){
00431         if ( (*it)->match( r ) ){
00432             m_currentQuery[arraycounter++] = (*it)->uid();
00433         }
00434 
00435     }
00436     // Shrink to fit..
00437     m_currentQuery.resize(arraycounter);
00438 
00439     return m_currentQuery;
00440 }
00441 
00442 const uint OContactAccessBackend_XML::querySettings()
00443 {
00444     return ( OContactAccess::WildCards
00445          | OContactAccess::IgnoreCase
00446          | OContactAccess::RegExp
00447          | OContactAccess::ExactMatch
00448          | OContactAccess::DateDiff
00449          | OContactAccess::DateYear
00450          | OContactAccess::DateMonth
00451          | OContactAccess::DateDay
00452          );
00453 }
00454 
00455 bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const
00456 {
00457     /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
00458      * may be added with any of the other settings. IgnoreCase should never used alone.
00459      * Wildcards, RegExp, ExactMatch should never used at the same time...
00460      */
00461 
00462     // Step 1: Check whether the given settings are supported by this backend
00463     if ( ( querySettings & ( 
00464                 OContactAccess::IgnoreCase
00465                 | OContactAccess::WildCards
00466                 | OContactAccess::DateDiff
00467                 | OContactAccess::DateYear
00468                 | OContactAccess::DateMonth
00469                 | OContactAccess::DateDay
00470                 | OContactAccess::RegExp
00471                 | OContactAccess::ExactMatch
00472                    ) ) != querySettings )
00473         return false;
00474 
00475     // Step 2: Check whether the given combinations are ok..
00476 
00477     // IngoreCase alone is invalid
00478     if ( querySettings == OContactAccess::IgnoreCase )
00479         return false;
00480 
00481     // WildCards, RegExp and ExactMatch should never used at the same time 
00482     switch ( querySettings & ~( OContactAccess::IgnoreCase
00483                     | OContactAccess::DateDiff
00484                     | OContactAccess::DateYear
00485                     | OContactAccess::DateMonth
00486                     | OContactAccess::DateDay
00487                     )
00488          ){
00489     case OContactAccess::RegExp:
00490         return ( true );
00491     case OContactAccess::WildCards:
00492         return ( true );
00493     case OContactAccess::ExactMatch:
00494         return ( true );
00495     case 0: // one of the upper removed bits were set..
00496         return ( true );
00497     default:
00498         return ( false );
00499     }
00500 }
00501 
00502 // Currently only asc implemented..
00503 QArray<int> OContactAccessBackend_XML::sorted( bool asc,  int , int ,  int )
00504 {
00505     QMap<QString, int> nameToUid;
00506     QStringList names;
00507     QArray<int> m_currentQuery( m_contactList.count() );
00508 
00509     // First fill map and StringList with all Names
00510     // Afterwards sort namelist and use map to fill array to return..
00511     QListIterator<OContact> it( m_contactList );
00512     for( ; it.current(); ++it ){
00513         names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) );
00514         nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() );
00515     }
00516     names.sort();
00517 
00518     int i = 0;
00519     if ( asc ){
00520         for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
00521             m_currentQuery[i++] = nameToUid[ (*it) ];
00522     }else{
00523         for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
00524             m_currentQuery[i++] = nameToUid[ (*it) ];
00525     }
00526 
00527     return m_currentQuery;
00528 
00529 }
00530 
00531 bool OContactAccessBackend_XML::add ( const OContact &newcontact )
00532 {
00533     //qWarning("odefaultbackend: ACTION::ADD");
00534     updateJournal (newcontact, ACTION_ADD);
00535     addContact_p( newcontact );
00536 
00537     m_changed = true;
00538 
00539     return true;
00540 }
00541 
00542 bool OContactAccessBackend_XML::replace ( const OContact &contact )
00543 {
00544     m_changed = true;
00545 
00546     OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) );
00547 
00548     if ( found ) {
00549         OContact* newCont = new OContact( contact );
00550 
00551         updateJournal ( *newCont, ACTION_REPLACE);
00552         m_contactList.removeRef ( found );
00553         m_contactList.append ( newCont );
00554         m_uidToContact.remove( QString().setNum( contact.uid() ) );
00555         m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont );
00556 
00557         qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid());
00558 
00559         return true;
00560     } else
00561         return false;
00562 }
00563 
00564 bool OContactAccessBackend_XML::remove ( int uid )
00565 {
00566     m_changed = true;
00567 
00568     OContact* found = m_uidToContact.find ( QString().setNum( uid ) );
00569 
00570     if ( found ) {
00571         updateJournal ( *found, ACTION_REMOVE);
00572         m_contactList.removeRef ( found );
00573         m_uidToContact.remove( QString().setNum( uid ) );
00574 
00575         return true;
00576     } else
00577         return false;
00578 }
00579 
00580 bool OContactAccessBackend_XML::reload(){
00581     /* Reload is the same as load in this implementation */
00582     return ( load() );
00583 }
00584 
00585 void OContactAccessBackend_XML::addContact_p( const OContact &newcontact )
00586 {
00587     OContact* contRef = new OContact( newcontact );
00588 
00589     m_contactList.append ( contRef );
00590     m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef );
00591 }
00592 
00593 /* This function loads the xml-database and the journalfile */
00594 bool OContactAccessBackend_XML::load( const QString filename, bool isJournal )
00595 {
00596 
00597     /* We use the time of the last read to check if the file was
00598      * changed externally.
00599      */
00600     if ( !isJournal ){
00601         QFileInfo fi( filename );
00602         m_readtime = fi.lastModified ();
00603     }
00604 
00605     const int JOURNALACTION = Qtopia::Notes + 1;
00606     const int JOURNALROW = JOURNALACTION + 1;
00607 
00608     bool foundAction = false;
00609     journal_action action = ACTION_ADD;
00610     int journalKey = 0;
00611     QMap<int, QString> contactMap;
00612     QMap<QString, QString> customMap;
00613     QMap<QString, QString>::Iterator customIt;
00614     QAsciiDict<int> dict( 47 );
00615 
00616     dict.setAutoDelete( TRUE );
00617     dict.insert( "Uid", new int(Qtopia::AddressUid) );
00618     dict.insert( "Title", new int(Qtopia::Title) );
00619     dict.insert( "FirstName", new int(Qtopia::FirstName) );
00620     dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
00621     dict.insert( "LastName", new int(Qtopia::LastName) );
00622     dict.insert( "Suffix", new int(Qtopia::Suffix) );
00623     dict.insert( "FileAs", new int(Qtopia::FileAs) );
00624     dict.insert( "Categories", new int(Qtopia::AddressCategory) );
00625     dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
00626     dict.insert( "Emails", new int(Qtopia::Emails) );
00627     dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
00628     dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
00629     dict.insert( "HomeState", new int(Qtopia::HomeState) );
00630     dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
00631     dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
00632     dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
00633     dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
00634     dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
00635     dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
00636     dict.insert( "Company", new int(Qtopia::Company) );
00637     dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
00638     dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
00639     dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
00640     dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
00641     dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
00642     dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
00643     dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
00644     dict.insert( "Department", new int(Qtopia::Department) );
00645     dict.insert( "Office", new int(Qtopia::Office) );
00646     dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
00647     dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
00648     dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
00649     dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
00650     dict.insert( "Profession", new int(Qtopia::Profession) );
00651     dict.insert( "Assistant", new int(Qtopia::Assistant) );
00652     dict.insert( "Manager", new int(Qtopia::Manager) );
00653     dict.insert( "Spouse", new int(Qtopia::Spouse) );
00654     dict.insert( "Children", new int(Qtopia::Children) );
00655     dict.insert( "Gender", new int(Qtopia::Gender) );
00656     dict.insert( "Birthday", new int(Qtopia::Birthday) );
00657     dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
00658     dict.insert( "Nickname", new int(Qtopia::Nickname) );
00659     dict.insert( "Notes", new int(Qtopia::Notes) );
00660     dict.insert( "action", new int(JOURNALACTION) );
00661     dict.insert( "actionrow", new int(JOURNALROW) );
00662 
00663     //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
00664 
00665     XMLElement *root = XMLElement::load( filename );
00666     if(root != 0l ){ // start parsing
00667         /* Parse all XML-Elements and put the data into the
00668          * Contact-Class
00669          */
00670         XMLElement *element = root->firstChild();
00671         //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
00672         element = element->firstChild();
00673 
00674         /* Search Tag "Contacts" which is the parent of all Contacts */
00675         while( element && !isJournal ){
00676             if( element->tagName() != QString::fromLatin1("Contacts") ){
00677                 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
00678                 //    element->tagName().latin1());
00679                 element = element->nextChild();
00680             } else {
00681                 element = element->firstChild();
00682                 break;
00683             }
00684         }
00685         /* Parse all Contacts and ignore unknown tags */
00686         while( element ){
00687             if( element->tagName() != QString::fromLatin1("Contact") ){
00688                 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
00689                 //    element->tagName().latin1());
00690                 element = element->nextChild();
00691                 continue;
00692             }
00693             /* Found alement with tagname "contact", now parse and store all
00694              * attributes contained
00695              */
00696             //qWarning("OContactDefBack::load element tagName() : %s",
00697             //   element->tagName().latin1() );
00698             QString dummy;
00699             foundAction = false;
00700 
00701             XMLElement::AttributeMap aMap = element->attributes();
00702             XMLElement::AttributeMap::Iterator it;
00703             contactMap.clear();
00704             customMap.clear();
00705             for( it = aMap.begin(); it != aMap.end(); ++it ){
00706                 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
00707 
00708                 int *find = dict[ it.key() ];
00709                 /* Unknown attributes will be stored as "Custom" elements */
00710                 if ( !find ) {
00711                     // qWarning("Attribute %s not known.", it.key().latin1());
00712                     //contact.setCustomField(it.key(), it.data());
00713                     customMap.insert( it.key(),  it.data() );
00714                     continue;
00715                 }
00716 
00717                 /* Check if special conversion is needed and add attribute
00718                  * into Contact class
00719                  */
00720                 switch( *find ) {
00721                     /*
00722                       case Qtopia::AddressUid:
00723                       contact.setUid( it.data().toInt() );
00724                       break;
00725                       case Qtopia::AddressCategory:
00726                       contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
00727                       break;
00728                     */
00729                 case JOURNALACTION:
00730                     action = journal_action(it.data().toInt());
00731                     foundAction = true;
00732                     qWarning ("ODefBack(journal)::ACTION found: %d", action);
00733                     break;
00734                 case JOURNALROW:
00735                     journalKey = it.data().toInt();
00736                     break;
00737                 default: // no conversion needed add them to the map
00738                     contactMap.insert( *find, it.data() );
00739                     break;
00740                 }
00741             }
00742             /* now generate the Contact contact */
00743             OContact contact( contactMap );
00744 
00745             for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
00746                 contact.setCustomField( customIt.key(),  customIt.data() );
00747             }
00748 
00749             if (foundAction){
00750                 foundAction = false;
00751                 switch ( action ) {
00752                 case ACTION_ADD:
00753                     addContact_p (contact);
00754                     break;
00755                 case ACTION_REMOVE:
00756                     if ( !remove (contact.uid()) )
00757                         qWarning ("ODefBack(journal)::Unable to remove uid: %d",
00758                               contact.uid() );
00759                     break;
00760                 case ACTION_REPLACE:
00761                     if ( !replace ( contact ) )
00762                         qWarning ("ODefBack(journal)::Unable to replace uid: %d",
00763                               contact.uid() );
00764                     break;
00765                 default:
00766                     qWarning ("Unknown action: ignored !");
00767                     break;
00768                 }
00769             }else{
00770                 /* Add contact to list */
00771                 addContact_p (contact);
00772             }
00773 
00774             /* Move to next element */
00775             element = element->nextChild();
00776         }
00777     }else {
00778         qWarning("ODefBack::could not load");
00779     }
00780     delete root;
00781     qWarning("returning from loading" );
00782     return true;
00783 }
00784 
00785 
00786 void OContactAccessBackend_XML::updateJournal( const OContact& cnt,
00787                            journal_action action )
00788 {
00789     QFile f( m_journalName );
00790     bool created = !f.exists();
00791     if ( !f.open(IO_WriteOnly|IO_Append) )
00792         return;
00793 
00794     QString buf;
00795     QCString str;
00796 
00797     // if the file was created, we have to set the Tag "<CONTACTS>" to
00798     // get a XML-File which is readable by our parser.
00799     // This is just a cheat, but better than rewrite the parser.
00800     if ( created ){
00801         buf = "<Contacts>";
00802         QCString cstr = buf.utf8();
00803         f.writeBlock( cstr.data(), cstr.length() );
00804     }
00805 
00806     buf = "<Contact ";
00807     cnt.save( buf );
00808     buf += " action=\"" + QString::number( (int)action ) + "\" ";
00809     buf += "/>\n";
00810     QCString cstr = buf.utf8();
00811     f.writeBlock( cstr.data(), cstr.length() );
00812 }
00813 
00814 void OContactAccessBackend_XML::removeJournal()
00815 {
00816     QFile f ( m_journalName );
00817     if ( f.exists() )
00818         f.remove();
00819 }
00820 
KDE Logo
This file is part of the documentation for OPIE Version 1.1.
Documentation copyright © 1997-2003 the KDE developers. 2003 OPIE developers
Generated on Tue Feb 10 20:25:19 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001