summaryrefslogtreecommitdiff
path: root/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp
Unidiff
Diffstat (limited to 'noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp') (more/less context) (show whitespace changes)
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp824
1 files changed, 824 insertions, 0 deletions
diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp
new file mode 100644
index 0000000..7ceaf5b
--- a/dev/null
+++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp
@@ -0,0 +1,824 @@
1/*
2 * XML Backend for the OPIE-Contact Database.
3 *
4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
5 *
6 * =====================================================================
7 *This program is free software; you can redistribute it and/or
8 *modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 * =====================================================================
12 *
13 * =====================================================================
14 * Version: $Id$
15 * =====================================================================
16 * History:
17 * $Log$
18 * Revision 1.1 2004/11/16 21:46:07 mickeyl
19 * libopie1 goes into unsupported
20 *
21 * Revision 1.10 2004/03/01 15:44:36 chicken
22 * fix includes
23 *
24 * Revision 1.9 2003/09/22 14:31:16 eilers
25 * Added first experimental incarnation of sql-backend for addressbook.
26 * Some modifications to be able to compile the todo sql-backend.
27 * A lot of changes fill follow...
28 *
29 * Revision 1.8 2003/08/30 15:28:26 eilers
30 * Removed some unimportant debug output which causes slow down..
31 *
32 * Revision 1.7 2003/08/01 12:30:16 eilers
33 * Merging changes from BRANCH_1_0 to HEAD
34 *
35 * Revision 1.6 2003/07/07 16:19:47 eilers
36 * Fixing serious bug in hasQuerySettings()
37 *
38 * Revision 1.5 2003/04/13 18:07:10 zecke
39 * More API doc
40 * QString -> const QString&
41 * QString = 0l -> QString::null
42 *
43 * Revision 1.4 2003/03/21 14:32:54 mickeyl
44 * g++ compliance fix: default arguments belong into the declaration, but not the definition
45 *
46 * Revision 1.3 2003/03/21 12:26:28 eilers
47 * Fixing small bug: If we search a birthday from today to today, it returned
48 * every contact ..
49 *
50 * Revision 1.2 2003/03/21 10:33:09 eilers
51 * Merged speed optimized xml backend for contacts to main.
52 * Added QDateTime to querybyexample. For instance, it is now possible to get
53 * all Birthdays/Anniversaries between two dates. This should be used
54 * to show all birthdays in the datebook..
55 * This change is sourcecode backward compatible but you have to upgrade
56 * the binaries for today-addressbook.
57 *
58 * Revision 1.1.2.2 2003/02/11 12:17:28 eilers
59 * Speed optimization. Removed the sequential search loops.
60 *
61 * Revision 1.1.2.1 2003/02/10 15:31:38 eilers
62 * Writing offsets to debug output..
63 *
64 * Revision 1.1 2003/02/09 15:05:01 eilers
65 * Nothing happened.. Just some cleanup before I will start..
66 *
67 * Revision 1.12 2003/01/03 16:58:03 eilers
68 * Reenable debug output
69 *
70 * Revision 1.11 2003/01/03 12:31:28 eilers
71 * Bugfix for calculating data diffs..
72 *
73 * Revision 1.10 2003/01/02 14:27:12 eilers
74 * Improved query by example: Search by date is possible.. First step
75 * for a today plugin for birthdays..
76 *
77 * Revision 1.9 2002/12/08 12:48:57 eilers
78 * Moved journal-enum from ocontact into i the xml-backend..
79 *
80 * Revision 1.8 2002/11/14 17:04:24 eilers
81 * Sorting will now work if fullname is identical on some entries
82 *
83 * Revision 1.7 2002/11/13 15:02:46 eilers
84 * Small Bug in sorted fixed
85 *
86 * Revision 1.6 2002/11/13 14:14:51 eilers
87 * Added sorted for Contacts..
88 *
89 * Revision 1.5 2002/11/01 15:10:42 eilers
90 * Added regExp-search in database for all fields in a contact.
91 *
92 * Revision 1.4 2002/10/16 10:52:40 eilers
93 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
94 *
95 * Revision 1.3 2002/10/14 16:21:54 eilers
96 * Some minor interface updates
97 *
98 * Revision 1.2 2002/10/07 17:34:24 eilers
99 * added OBackendFactory for advanced backend access
100 *
101 * Revision 1.1 2002/09/27 17:11:44 eilers
102 * Added API for accessing the Contact-Database ! It is compiling, but
103 * please do not expect that anything is working !
104 * I will debug that stuff in the next time ..
105 * Please read README_COMPILE for compiling !
106 *
107 *
108 */
109
110#include "ocontactaccessbackend_xml.h"
111
112#include <qasciidict.h>
113#include <qfile.h>
114#include <qfileinfo.h>
115#include <qregexp.h>
116#include <qarray.h>
117#include <qmap.h>
118
119#include <qpe/global.h>
120
121#include <opie/xmltree.h>
122#include "ocontactaccessbackend.h"
123#include "ocontactaccess.h"
124
125#include <stdlib.h>
126#include <errno.h>
127
128using namespace Opie;
129
130
131OContactAccessBackend_XML::OContactAccessBackend_XML ( const QString& appname, const QString& filename ):
132 m_changed( false )
133{
134 // Just m_contactlist should call delete if an entry
135 // is removed.
136 m_contactList.setAutoDelete( true );
137 m_uidToContact.setAutoDelete( false );
138
139 m_appName = appname;
140
141 /* Set journalfile name ... */
142 m_journalName = getenv("HOME");
143 m_journalName +="/.abjournal" + appname;
144
145 /* Expecting to access the default filename if nothing else is set */
146 if ( filename.isEmpty() ){
147 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
148 } else
149 m_fileName = filename;
150
151 /* Load Database now */
152 load ();
153}
154
155bool OContactAccessBackend_XML::save()
156{
157
158 if ( !m_changed )
159 return true;
160
161 QString strNewFile = m_fileName + ".new";
162 QFile f( strNewFile );
163 if ( !f.open( IO_WriteOnly|IO_Raw ) )
164 return false;
165
166 int total_written;
167 int idx_offset = 0;
168 QString out;
169
170 // Write Header
171 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
172 " <Groups>\n"
173 " </Groups>\n"
174 " <Contacts>\n";
175 QCString cstr = out.utf8();
176 f.writeBlock( cstr.data(), cstr.length() );
177 idx_offset += cstr.length();
178 out = "";
179
180 // Write all contacts
181 QListIterator<OContact> it( m_contactList );
182 for ( ; it.current(); ++it ) {
183 // qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset );
184 out += "<Contact ";
185 (*it)->save( out );
186 out += "/>\n";
187 cstr = out.utf8();
188 total_written = f.writeBlock( cstr.data(), cstr.length() );
189 idx_offset += cstr.length();
190 if ( total_written != int(cstr.length()) ) {
191 f.close();
192 QFile::remove( strNewFile );
193 return false;
194 }
195 out = "";
196 }
197 out += " </Contacts>\n</AddressBook>\n";
198
199 // Write Footer
200 cstr = out.utf8();
201 total_written = f.writeBlock( cstr.data(), cstr.length() );
202 if ( total_written != int( cstr.length() ) ) {
203 f.close();
204 QFile::remove( strNewFile );
205 return false;
206 }
207 f.close();
208
209 // move the file over, I'm just going to use the system call
210 // because, I don't feel like using QDir.
211 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
212 qWarning( "problem renaming file %s to %s, errno: %d",
213 strNewFile.latin1(), m_journalName.latin1(), errno );
214 // remove the tmp file...
215 QFile::remove( strNewFile );
216 }
217
218 /* The journalfile should be removed now... */
219 removeJournal();
220
221 m_changed = false;
222 return true;
223}
224
225bool OContactAccessBackend_XML::load ()
226{
227 m_contactList.clear();
228 m_uidToContact.clear();
229
230 /* Load XML-File and journal if it exists */
231 if ( !load ( m_fileName, false ) )
232 return false;
233 /* The returncode of the journalfile is ignored due to the
234 * fact that it does not exist when this class is instantiated !
235 * But there may such a file exist, if the application crashed.
236 * Therefore we try to load it to get the changes before the #
237 * crash happened...
238 */
239 load (m_journalName, true);
240
241 return true;
242}
243
244void OContactAccessBackend_XML::clear ()
245{
246 m_contactList.clear();
247 m_uidToContact.clear();
248
249 m_changed = false;
250}
251
252bool OContactAccessBackend_XML::wasChangedExternally()
253{
254 QFileInfo fi( m_fileName );
255
256 QDateTime lastmod = fi.lastModified ();
257
258 return (lastmod != m_readtime);
259}
260
261QArray<int> OContactAccessBackend_XML::allRecords() const
262{
263 QArray<int> uid_list( m_contactList.count() );
264
265 uint counter = 0;
266 QListIterator<OContact> it( m_contactList );
267 for( ; it.current(); ++it ){
268 uid_list[counter++] = (*it)->uid();
269 }
270
271 return ( uid_list );
272}
273
274OContact OContactAccessBackend_XML::find ( int uid ) const
275{
276 OContact foundContact; //Create empty contact
277
278 OContact* found = m_uidToContact.find( QString().setNum( uid ) );
279
280 if ( found ){
281 foundContact = *found;
282 }
283
284 return ( foundContact );
285}
286
287QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings,
288 const QDateTime& d )
289{
290
291 QArray<int> m_currentQuery( m_contactList.count() );
292 QListIterator<OContact> it( m_contactList );
293 uint arraycounter = 0;
294
295 for( ; it.current(); ++it ){
296 /* Search all fields and compare them with query object. Store them into list
297 * if all fields matches.
298 */
299 QDate* queryDate = 0l;
300 QDate* checkDate = 0l;
301 bool allcorrect = true;
302 for ( int i = 0; i < Qtopia::Groups; i++ ) {
303 // Birthday and anniversary are special nonstring fields and should
304 // be handled specially
305 switch ( i ){
306 case Qtopia::Birthday:
307 queryDate = new QDate( query.birthday() );
308 checkDate = new QDate( (*it)->birthday() );
309 case Qtopia::Anniversary:
310 if ( queryDate == 0l ){
311 queryDate = new QDate( query.anniversary() );
312 checkDate = new QDate( (*it)->anniversary() );
313 }
314
315 if ( queryDate->isValid() ){
316 if( checkDate->isValid() ){
317 if ( settings & OContactAccess::DateYear ){
318 if ( queryDate->year() != checkDate->year() )
319 allcorrect = false;
320 }
321 if ( settings & OContactAccess::DateMonth ){
322 if ( queryDate->month() != checkDate->month() )
323 allcorrect = false;
324 }
325 if ( settings & OContactAccess::DateDay ){
326 if ( queryDate->day() != checkDate->day() )
327 allcorrect = false;
328 }
329 if ( settings & OContactAccess::DateDiff ) {
330 QDate current;
331 // If we get an additional date, we
332 // will take this date instead of
333 // the current one..
334 if ( !d.date().isValid() )
335 current = QDate::currentDate();
336 else
337 current = d.date();
338
339 // We have to equalize the year, otherwise
340 // the search will fail..
341 checkDate->setYMD( current.year(),
342 checkDate->month(),
343 checkDate->day() );
344 if ( *checkDate < current )
345 checkDate->setYMD( current.year()+1,
346 checkDate->month(),
347 checkDate->day() );
348
349 // Check whether the birthday/anniversary date is between
350 // the current/given date and the maximum date
351 // ( maximum time range ) !
352 qWarning("Checking if %s is between %s and %s ! ",
353 checkDate->toString().latin1(),
354 current.toString().latin1(),
355 queryDate->toString().latin1() );
356 if ( current.daysTo( *queryDate ) >= 0 ){
357 if ( !( ( *checkDate >= current ) &&
358 ( *checkDate <= *queryDate ) ) ){
359 allcorrect = false;
360 qWarning (" Nope!..");
361 }
362 }
363 }
364 } else{
365 // checkDate is invalid. Therefore this entry is always rejected
366 allcorrect = false;
367 }
368 }
369
370 delete queryDate;
371 queryDate = 0l;
372 delete checkDate;
373 checkDate = 0l;
374 break;
375 default:
376 /* Just compare fields which are not empty in the query object */
377 if ( !query.field(i).isEmpty() ){
378 switch ( settings & ~( OContactAccess::IgnoreCase
379 | OContactAccess::DateDiff
380 | OContactAccess::DateYear
381 | OContactAccess::DateMonth
382 | OContactAccess::DateDay
383 | OContactAccess::MatchOne
384 ) ){
385
386 case OContactAccess::RegExp:{
387 QRegExp expr ( query.field(i),
388 !(settings & OContactAccess::IgnoreCase),
389 false );
390 if ( expr.find ( (*it)->field(i), 0 ) == -1 )
391 allcorrect = false;
392 }
393 break;
394 case OContactAccess::WildCards:{
395 QRegExp expr ( query.field(i),
396 !(settings & OContactAccess::IgnoreCase),
397 true );
398 if ( expr.find ( (*it)->field(i), 0 ) == -1 )
399 allcorrect = false;
400 }
401 break;
402 case OContactAccess::ExactMatch:{
403 if (settings & OContactAccess::IgnoreCase){
404 if ( query.field(i).upper() !=
405 (*it)->field(i).upper() )
406 allcorrect = false;
407 }else{
408 if ( query.field(i) != (*it)->field(i) )
409 allcorrect = false;
410 }
411 }
412 break;
413 }
414 }
415 }
416 }
417 if ( allcorrect ){
418 m_currentQuery[arraycounter++] = (*it)->uid();
419 }
420 }
421
422 // Shrink to fit..
423 m_currentQuery.resize(arraycounter);
424
425 return m_currentQuery;
426}
427
428QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const
429{
430 QArray<int> m_currentQuery( m_contactList.count() );
431 QListIterator<OContact> it( m_contactList );
432 uint arraycounter = 0;
433
434 for( ; it.current(); ++it ){
435 if ( (*it)->match( r ) ){
436 m_currentQuery[arraycounter++] = (*it)->uid();
437 }
438
439 }
440 // Shrink to fit..
441 m_currentQuery.resize(arraycounter);
442
443 return m_currentQuery;
444}
445
446const uint OContactAccessBackend_XML::querySettings()
447{
448 return ( OContactAccess::WildCards
449 | OContactAccess::IgnoreCase
450 | OContactAccess::RegExp
451 | OContactAccess::ExactMatch
452 | OContactAccess::DateDiff
453 | OContactAccess::DateYear
454 | OContactAccess::DateMonth
455 | OContactAccess::DateDay
456 );
457}
458
459bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const
460{
461 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
462 * may be added with any of the other settings. IgnoreCase should never used alone.
463 * Wildcards, RegExp, ExactMatch should never used at the same time...
464 */
465
466 // Step 1: Check whether the given settings are supported by this backend
467 if ( ( querySettings & (
468 OContactAccess::IgnoreCase
469 | OContactAccess::WildCards
470 | OContactAccess::DateDiff
471 | OContactAccess::DateYear
472 | OContactAccess::DateMonth
473 | OContactAccess::DateDay
474 | OContactAccess::RegExp
475 | OContactAccess::ExactMatch
476 ) ) != querySettings )
477 return false;
478
479 // Step 2: Check whether the given combinations are ok..
480
481 // IngoreCase alone is invalid
482 if ( querySettings == OContactAccess::IgnoreCase )
483 return false;
484
485 // WildCards, RegExp and ExactMatch should never used at the same time
486 switch ( querySettings & ~( OContactAccess::IgnoreCase
487 | OContactAccess::DateDiff
488 | OContactAccess::DateYear
489 | OContactAccess::DateMonth
490 | OContactAccess::DateDay
491 )
492 ){
493 case OContactAccess::RegExp:
494 return ( true );
495 case OContactAccess::WildCards:
496 return ( true );
497 case OContactAccess::ExactMatch:
498 return ( true );
499 case 0: // one of the upper removed bits were set..
500 return ( true );
501 default:
502 return ( false );
503 }
504}
505
506// Currently only asc implemented..
507QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int )
508{
509 QMap<QString, int> nameToUid;
510 QStringList names;
511 QArray<int> m_currentQuery( m_contactList.count() );
512
513 // First fill map and StringList with all Names
514 // Afterwards sort namelist and use map to fill array to return..
515 QListIterator<OContact> it( m_contactList );
516 for( ; it.current(); ++it ){
517 names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) );
518 nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() );
519 }
520 names.sort();
521
522 int i = 0;
523 if ( asc ){
524 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
525 m_currentQuery[i++] = nameToUid[ (*it) ];
526 }else{
527 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
528 m_currentQuery[i++] = nameToUid[ (*it) ];
529 }
530
531 return m_currentQuery;
532
533}
534
535bool OContactAccessBackend_XML::add ( const OContact &newcontact )
536{
537 //qWarning("odefaultbackend: ACTION::ADD");
538 updateJournal (newcontact, ACTION_ADD);
539 addContact_p( newcontact );
540
541 m_changed = true;
542
543 return true;
544}
545
546bool OContactAccessBackend_XML::replace ( const OContact &contact )
547{
548 m_changed = true;
549
550 OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) );
551
552 if ( found ) {
553 OContact* newCont = new OContact( contact );
554
555 updateJournal ( *newCont, ACTION_REPLACE);
556 m_contactList.removeRef ( found );
557 m_contactList.append ( newCont );
558 m_uidToContact.remove( QString().setNum( contact.uid() ) );
559 m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont );
560
561 qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid());
562
563 return true;
564 } else
565 return false;
566}
567
568bool OContactAccessBackend_XML::remove ( int uid )
569{
570 m_changed = true;
571
572 OContact* found = m_uidToContact.find ( QString().setNum( uid ) );
573
574 if ( found ) {
575 updateJournal ( *found, ACTION_REMOVE);
576 m_contactList.removeRef ( found );
577 m_uidToContact.remove( QString().setNum( uid ) );
578
579 return true;
580 } else
581 return false;
582}
583
584bool OContactAccessBackend_XML::reload(){
585 /* Reload is the same as load in this implementation */
586 return ( load() );
587}
588
589void OContactAccessBackend_XML::addContact_p( const OContact &newcontact )
590{
591 OContact* contRef = new OContact( newcontact );
592
593 m_contactList.append ( contRef );
594 m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef );
595}
596
597/* This function loads the xml-database and the journalfile */
598bool OContactAccessBackend_XML::load( const QString filename, bool isJournal )
599{
600
601 /* We use the time of the last read to check if the file was
602 * changed externally.
603 */
604 if ( !isJournal ){
605 QFileInfo fi( filename );
606 m_readtime = fi.lastModified ();
607 }
608
609 const int JOURNALACTION = Qtopia::Notes + 1;
610 const int JOURNALROW = JOURNALACTION + 1;
611
612 bool foundAction = false;
613 journal_action action = ACTION_ADD;
614 int journalKey = 0;
615 QMap<int, QString> contactMap;
616 QMap<QString, QString> customMap;
617 QMap<QString, QString>::Iterator customIt;
618 QAsciiDict<int> dict( 47 );
619
620 dict.setAutoDelete( TRUE );
621 dict.insert( "Uid", new int(Qtopia::AddressUid) );
622 dict.insert( "Title", new int(Qtopia::Title) );
623 dict.insert( "FirstName", new int(Qtopia::FirstName) );
624 dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
625 dict.insert( "LastName", new int(Qtopia::LastName) );
626 dict.insert( "Suffix", new int(Qtopia::Suffix) );
627 dict.insert( "FileAs", new int(Qtopia::FileAs) );
628 dict.insert( "Categories", new int(Qtopia::AddressCategory) );
629 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
630 dict.insert( "Emails", new int(Qtopia::Emails) );
631 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
632 dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
633 dict.insert( "HomeState", new int(Qtopia::HomeState) );
634 dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
635 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
636 dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
637 dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
638 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
639 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
640 dict.insert( "Company", new int(Qtopia::Company) );
641 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
642 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
643 dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
644 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
645 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
646 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
647 dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
648 dict.insert( "Department", new int(Qtopia::Department) );
649 dict.insert( "Office", new int(Qtopia::Office) );
650 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
651 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
652 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
653 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
654 dict.insert( "Profession", new int(Qtopia::Profession) );
655 dict.insert( "Assistant", new int(Qtopia::Assistant) );
656 dict.insert( "Manager", new int(Qtopia::Manager) );
657 dict.insert( "Spouse", new int(Qtopia::Spouse) );
658 dict.insert( "Children", new int(Qtopia::Children) );
659 dict.insert( "Gender", new int(Qtopia::Gender) );
660 dict.insert( "Birthday", new int(Qtopia::Birthday) );
661 dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
662 dict.insert( "Nickname", new int(Qtopia::Nickname) );
663 dict.insert( "Notes", new int(Qtopia::Notes) );
664 dict.insert( "action", new int(JOURNALACTION) );
665 dict.insert( "actionrow", new int(JOURNALROW) );
666
667 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
668
669 XMLElement *root = XMLElement::load( filename );
670 if(root != 0l ){ // start parsing
671 /* Parse all XML-Elements and put the data into the
672 * Contact-Class
673 */
674 XMLElement *element = root->firstChild();
675 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
676 element = element->firstChild();
677
678 /* Search Tag "Contacts" which is the parent of all Contacts */
679 while( element && !isJournal ){
680 if( element->tagName() != QString::fromLatin1("Contacts") ){
681 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
682 // element->tagName().latin1());
683 element = element->nextChild();
684 } else {
685 element = element->firstChild();
686 break;
687 }
688 }
689 /* Parse all Contacts and ignore unknown tags */
690 while( element ){
691 if( element->tagName() != QString::fromLatin1("Contact") ){
692 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
693 // element->tagName().latin1());
694 element = element->nextChild();
695 continue;
696 }
697 /* Found alement with tagname "contact", now parse and store all
698 * attributes contained
699 */
700 //qWarning("OContactDefBack::load element tagName() : %s",
701 // element->tagName().latin1() );
702 QString dummy;
703 foundAction = false;
704
705 XMLElement::AttributeMap aMap = element->attributes();
706 XMLElement::AttributeMap::Iterator it;
707 contactMap.clear();
708 customMap.clear();
709 for( it = aMap.begin(); it != aMap.end(); ++it ){
710 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
711
712 int *find = dict[ it.key() ];
713 /* Unknown attributes will be stored as "Custom" elements */
714 if ( !find ) {
715 // qWarning("Attribute %s not known.", it.key().latin1());
716 //contact.setCustomField(it.key(), it.data());
717 customMap.insert( it.key(), it.data() );
718 continue;
719 }
720
721 /* Check if special conversion is needed and add attribute
722 * into Contact class
723 */
724 switch( *find ) {
725 /*
726 case Qtopia::AddressUid:
727 contact.setUid( it.data().toInt() );
728 break;
729 case Qtopia::AddressCategory:
730 contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
731 break;
732 */
733 case JOURNALACTION:
734 action = journal_action(it.data().toInt());
735 foundAction = true;
736 qWarning ("ODefBack(journal)::ACTION found: %d", action);
737 break;
738 case JOURNALROW:
739 journalKey = it.data().toInt();
740 break;
741 default: // no conversion needed add them to the map
742 contactMap.insert( *find, it.data() );
743 break;
744 }
745 }
746 /* now generate the Contact contact */
747 OContact contact( contactMap );
748
749 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
750 contact.setCustomField( customIt.key(), customIt.data() );
751 }
752
753 if (foundAction){
754 foundAction = false;
755 switch ( action ) {
756 case ACTION_ADD:
757 addContact_p (contact);
758 break;
759 case ACTION_REMOVE:
760 if ( !remove (contact.uid()) )
761 qWarning ("ODefBack(journal)::Unable to remove uid: %d",
762 contact.uid() );
763 break;
764 case ACTION_REPLACE:
765 if ( !replace ( contact ) )
766 qWarning ("ODefBack(journal)::Unable to replace uid: %d",
767 contact.uid() );
768 break;
769 default:
770 qWarning ("Unknown action: ignored !");
771 break;
772 }
773 }else{
774 /* Add contact to list */
775 addContact_p (contact);
776 }
777
778 /* Move to next element */
779 element = element->nextChild();
780 }
781 }else {
782 qWarning("ODefBack::could not load");
783 }
784 delete root;
785 qWarning("returning from loading" );
786 return true;
787}
788
789
790void OContactAccessBackend_XML::updateJournal( const OContact& cnt,
791 journal_action action )
792{
793 QFile f( m_journalName );
794 bool created = !f.exists();
795 if ( !f.open(IO_WriteOnly|IO_Append) )
796 return;
797
798 QString buf;
799 QCString str;
800
801 // if the file was created, we have to set the Tag "<CONTACTS>" to
802 // get a XML-File which is readable by our parser.
803 // This is just a cheat, but better than rewrite the parser.
804 if ( created ){
805 buf = "<Contacts>";
806 QCString cstr = buf.utf8();
807 f.writeBlock( cstr.data(), cstr.length() );
808 }
809
810 buf = "<Contact ";
811 cnt.save( buf );
812 buf += " action=\"" + QString::number( (int)action ) + "\" ";
813 buf += "/>\n";
814 QCString cstr = buf.utf8();
815 f.writeBlock( cstr.data(), cstr.length() );
816}
817
818void OContactAccessBackend_XML::removeJournal()
819{
820 QFile f ( m_journalName );
821 if ( f.exists() )
822 f.remove();
823}
824