Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

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

Generated on Sat Nov 5 16:16:15 2005 for OPIE by  doxygen 1.4.2