summaryrefslogtreecommitdiff
path: root/libopie2/opiepim
authoreilers <eilers>2002-09-27 17:11:44 (UTC)
committer eilers <eilers>2002-09-27 17:11:44 (UTC)
commit44c98b497ff1cb8cddba10b56435f136a583cce2 (patch) (unidiff)
treed76ab641b0a9151031f1ec7ac19ff00c11f82b53 /libopie2/opiepim
parentd44b205c9009af71db036b3951363a91110e1c20 (diff)
downloadopie-44c98b497ff1cb8cddba10b56435f136a583cce2.zip
opie-44c98b497ff1cb8cddba10b56435f136a583cce2.tar.gz
opie-44c98b497ff1cb8cddba10b56435f136a583cce2.tar.bz2
Added API for accessing the Contact-Database ! It is compiling, but
please do not expect that anything is working ! I will debug that stuff in the next time .. Please read README_COMPILE for compiling !
Diffstat (limited to 'libopie2/opiepim') (more/less context) (show whitespace changes)
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend.h70
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend_xml.h550
-rw-r--r--libopie2/opiepim/core/ocontactaccess.cpp174
-rw-r--r--libopie2/opiepim/core/ocontactaccess.h197
-rw-r--r--libopie2/opiepim/ocontact.cpp1433
-rw-r--r--libopie2/opiepim/ocontact.h311
6 files changed, 2735 insertions, 0 deletions
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend.h b/libopie2/opiepim/backend/ocontactaccessbackend.h
new file mode 100644
index 0000000..9469bbc
--- a/dev/null
+++ b/libopie2/opiepim/backend/ocontactaccessbackend.h
@@ -0,0 +1,70 @@
1/**
2 * The class responsible for managing a backend.
3 * The implementation of this abstract class contains
4 * the complete database handling.
5 *
6 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
7 * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org)
8 *
9 * =====================================================================
10 *This program is free software; you can redistribute it and/or
11 *modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation;
13 * either version 2 of the License, or (at your option) any later
14 * version.
15 * =====================================================================
16 * ToDo: Define enum for query settings
17 * =====================================================================
18 * Version: $Id$
19 * =====================================================================
20 * History:
21 * $Log$
22 * Revision 1.1 2002/09/27 17:11:44 eilers
23 * Added API for accessing the Contact-Database ! It is compiling, but
24 * please do not expect that anything is working !
25 * I will debug that stuff in the next time ..
26 * Please read README_COMPILE for compiling !
27 *
28 * =====================================================================
29 *
30 */
31
32#ifndef _OCONTACTACCESSBACKEND_H_
33#define _OCONTACTACCESSBACKEND_H_
34
35#include "opimaccessbackend.h"
36
37class OContactAccessBackend: public OPimAccessBackend<OContact> {
38 public:
39 OContactAccessBackend() {}
40 virtual ~OContactAccessBackend() {}
41
42
43 /** Return if database was changed externally.
44 * This may just make sense on file based databases like a XML-File.
45 * It is used to prevent to overwrite the current database content
46 * if the file was already changed by something else !
47 * If this happens, we have to reload before save our data.
48 * If we use real databases, this should be handled by the database
49 * management system themselve, therefore this function should always return false in
50 * this case. It is not our problem to handle this conflict ...
51 * @return <i>true</i> if the database was changed and if save without reload will
52 * be dangerous. <i>false</i> if the database was not changed or it is save to write
53 * in this situation.
54 */
55 virtual bool wasChangedExternally() = 0;
56
57 /** Return all possible settings.
58 * @return All settings provided by the current backend
59 * (i.e.: query_WildCards & query_IgnoreCase)
60 */
61 virtual const uint querySettings() = 0;
62
63 /** Check whether settings are correct.
64 * @return <i>true</i> if the given settings are correct and possible.
65 */
66 virtual bool hasQuerySettings (uint querySettings) const = 0;
67
68
69};
70#endif
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h
new file mode 100644
index 0000000..2cdb45b
--- a/dev/null
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h
@@ -0,0 +1,550 @@
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 * ToDo: XML-Backend: Automatic reload if something was changed...
13 *
14 *
15 * =====================================================================
16 * Version: $Id$
17 * =====================================================================
18 * History:
19 * $Log$
20 * Revision 1.1 2002/09/27 17:11:44 eilers
21 * Added API for accessing the Contact-Database ! It is compiling, but
22 * please do not expect that anything is working !
23 * I will debug that stuff in the next time ..
24 * Please read README_COMPILE for compiling !
25 *
26 *
27 */
28
29#ifndef _OContactAccessBackend_XML_
30#define _OContactAccessBackend_XML_
31
32#include <qasciidict.h>
33#include <qdatetime.h>
34#include <qfile.h>
35#include <qregexp.h>
36#include <qarray.h>
37
38#include <opie/xmltree.h>
39#include "ocontactaccessbackend.h"
40
41using namespace Opie;
42
43/* the default xml implementation */
44class OContactAccessBackend_XML : public OContactAccessBackend {
45 public:
46 OContactAccessBackend_XML ( QString appname, QString filename = 0l )
47 {
48 m_appName = appname;
49
50 /* Set journalfile name ... */
51 m_journalName = getenv("HOME");
52 m_journalName +="/.abjournal" + appname;
53
54 /* Expecting to access the default filename if nothing else is set */
55 if ( filename.isEmpty() ){
56 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
57 } else
58 m_fileName = filename;
59
60 /* Load Database now */
61 load ();
62 }
63
64 bool save() {
65 QString strNewFile = m_fileName + ".new";
66 QFile f( strNewFile );
67 if ( !f.open( IO_WriteOnly|IO_Raw ) )
68 return false;
69
70 int total_written;
71 QString out;
72 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
73 " <Groups>\n"
74 " </Groups>\n"
75 " <Contacts>\n";
76 //QValueList<Contact>::iterator it;
77 QValueListConstIterator<OContact> it;
78 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) {
79 out += "<Contact ";
80 (*it).save( out );
81 out += "/>\n";
82 QCString cstr = out.utf8();
83 total_written = f.writeBlock( cstr.data(), cstr.length() );
84 if ( total_written != int(cstr.length()) ) {
85 f.close();
86 QFile::remove( strNewFile );
87 return false;
88 }
89 out = "";
90 }
91 out += " </Contacts>\n</AddressBook>\n";
92
93 QCString cstr = out.utf8();
94 total_written = f.writeBlock( cstr.data(), cstr.length() );
95 if ( total_written != int( cstr.length() ) ) {
96 f.close();
97 QFile::remove( strNewFile );
98 return false;
99 }
100 f.close();
101
102 // move the file over, I'm just going to use the system call
103 // because, I don't feel like using QDir.
104 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
105 qWarning( "problem renaming file %s to %s, errno: %d",
106 strNewFile.latin1(), m_journalName.latin1(), errno );
107 // remove the tmp file...
108 QFile::remove( strNewFile );
109 }
110
111 /* The journalfile should be removed now... */
112 removeJournal();
113 return true;
114 }
115
116 bool load () {
117 m_contactList.clear();
118
119 /* Load XML-File and journal if it exists */
120 if ( !load ( m_fileName, false ) )
121 return false;
122 /* The returncode of the journalfile is ignored due to the
123 * fact that it does not exist when this class is instantiated !
124 * But there may such a file exist, if the application crashed.
125 * Therefore we try to load it to get the changes before the #
126 * crash happened...
127 */
128 load (m_journalName, true);
129
130 return true;
131 }
132
133 void clear () {
134 m_contactList.clear();
135
136 }
137
138 bool wasChangedExternally()
139 {
140 QFileInfo fi( m_fileName );
141
142 QDateTime lastmod = fi.lastModified ();
143
144 return (lastmod != m_readtime);
145 }
146
147 QArray<int> allRecords() const {
148 QArray<int> uid_list( m_contactList.count() );
149
150 uint counter = 0;
151 QValueListConstIterator<OContact> it;
152 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
153 uid_list[counter++] = (*it).uid();
154 }
155
156 return ( uid_list );
157 }
158
159 OContact find ( int uid ) const
160 {
161 bool found = false;
162 OContact foundContact; //Create empty contact
163
164 QValueListConstIterator<OContact> it;
165 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
166 if ((*it).uid() == uid){
167 found = true;
168 break;
169 }
170 }
171 if ( found ){
172 foundContact = *it;
173 }
174
175 return ( foundContact );
176 }
177
178 QArray<int> queryByExample ( const OContact &query, int settings ){
179
180 QArray<int> m_currentQuery( m_contactList.count() );
181 QValueListConstIterator<OContact> it;
182 uint arraycounter = 0;
183
184 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
185 /* Search all fields and compare them with query object. Store them into list
186 * if all fields matches.
187 */
188 bool allcorrect = true;
189 for ( int i = 0; i < Qtopia::rid; i++ ) {
190 /* Just compare fields which are not empty in the query object */
191 if ( !query.field(i).isEmpty() ){
192 switch ( settings & ~OContactAccess::query_IgnoreCase ){
193 case OContactAccess::query_RegExp:{
194 QRegExp expr ( query.field(i),
195 !(settings & OContactAccess::query_IgnoreCase),
196 false );
197 if ( expr.find ( (*it).field(i), 0 ) == -1 )
198 allcorrect = false;
199 }
200 break;
201 case OContactAccess::query_WildCards:{
202 QRegExp expr ( query.field(i),
203 !(settings & OContactAccess::query_IgnoreCase),
204 true );
205 if ( expr.find ( (*it).field(i), 0 ) == -1 )
206 allcorrect = false;
207 }
208 break;
209 case OContactAccess::query_ExactMatch:{
210 if (settings & OContactAccess::query_IgnoreCase){
211 if ( query.field(i).upper() !=
212 (*it).field(i).upper() )
213 allcorrect = false;
214 }else{
215 if ( query.field(i) != (*it).field(i) )
216 allcorrect = false;
217 }
218 }
219 break;
220 }
221 }
222 }
223 if ( allcorrect ){
224 m_currentQuery[arraycounter++] = (*it).uid();
225 }
226 }
227
228 // Shrink to fit..
229 m_currentQuery.resize(arraycounter);
230
231 return m_currentQuery;
232 }
233
234 const uint querySettings()
235 {
236 return ( OContactAccess::query_WildCards
237 & OContactAccess::query_IgnoreCase
238 & OContactAccess::query_RegExp
239 & OContactAccess::query_ExactMatch );
240 }
241
242 bool hasQuerySettings (uint querySettings) const
243 {
244 /* OContactAccess::query_IgnoreCase may be added with one
245 * of the other settings, but never used alone.
246 * The other settings are just valid alone...
247 */
248 switch ( querySettings & ~OContactAccess::query_IgnoreCase ){
249 case OContactAccess::query_RegExp:
250 return ( true );
251 case OContactAccess::query_WildCards:
252 return ( true );
253 case OContactAccess::query_ExactMatch:
254 return ( true );
255 default:
256 return ( false );
257 }
258 }
259
260 bool add ( const OContact &newcontact )
261 {
262 //qWarning("odefaultbackend: ACTION::ADD");
263 updateJournal (newcontact, OContact::ACTION_ADD);
264 addContact_p( newcontact );
265 return true;
266 }
267
268 bool replace ( const OContact &contact )
269 {
270 bool found = false;
271
272 QValueListIterator<OContact> it;
273 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
274 if ( (*it).uid() == contact.uid() ){
275 found = true;
276 break;
277 }
278 }
279 if (found) {
280 updateJournal (contact, OContact::ACTION_REPLACE);
281 m_contactList.remove (it);
282 m_contactList.append (contact);
283 return true;
284 } else
285 return false;
286 }
287
288 bool remove ( int uid )
289 {
290 bool found = false;
291 QValueListIterator<OContact> it;
292 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
293 if ((*it).uid() == uid){
294 found = true;
295 break;
296 }
297 }
298 if (found) {
299 updateJournal ( *it, OContact::ACTION_REMOVE);
300 m_contactList.remove (it);
301 return true;
302 } else
303 return false;
304 }
305
306 bool reload(){
307 /* Reload is the same as load in this implementation */
308 return ( load() );
309 }
310
311 private:
312 void addContact_p( const OContact &newcontact ){
313 m_contactList.append (newcontact);
314 }
315
316 /* This function loads the xml-database and the journalfile */
317 bool load( const QString filename, bool isJournal ) {
318
319 /* We use the time of the last read to check if the file was
320 * changed externally.
321 */
322 if ( !isJournal ){
323 QFileInfo fi( filename );
324 m_readtime = fi.lastModified ();
325 }
326
327 const int JOURNALACTION = Qtopia::Notes + 1;
328 const int JOURNALROW = JOURNALACTION + 1;
329
330 bool foundAction = false;
331 OContact::journal_action action = OContact::ACTION_ADD;
332 int journalKey = 0;
333 QMap<int, QString> contactMap;
334 QMap<QString, QString> customMap;
335 QMap<QString, QString>::Iterator customIt;
336 QAsciiDict<int> dict( 47 );
337
338 dict.setAutoDelete( TRUE );
339 dict.insert( "Uid", new int(Qtopia::AddressUid) );
340 dict.insert( "Title", new int(Qtopia::Title) );
341 dict.insert( "FirstName", new int(Qtopia::FirstName) );
342 dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
343 dict.insert( "LastName", new int(Qtopia::LastName) );
344 dict.insert( "Suffix", new int(Qtopia::Suffix) );
345 dict.insert( "FileAs", new int(Qtopia::FileAs) );
346 dict.insert( "Categories", new int(Qtopia::AddressCategory) );
347 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
348 dict.insert( "Emails", new int(Qtopia::Emails) );
349 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
350 dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
351 dict.insert( "HomeState", new int(Qtopia::HomeState) );
352 dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
353 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
354 dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
355 dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
356 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
357 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
358 dict.insert( "Company", new int(Qtopia::Company) );
359 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
360 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
361 dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
362 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
363 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
364 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
365 dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
366 dict.insert( "Department", new int(Qtopia::Department) );
367 dict.insert( "Office", new int(Qtopia::Office) );
368 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
369 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
370 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
371 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
372 dict.insert( "Profession", new int(Qtopia::Profession) );
373 dict.insert( "Assistant", new int(Qtopia::Assistant) );
374 dict.insert( "Manager", new int(Qtopia::Manager) );
375 dict.insert( "Spouse", new int(Qtopia::Spouse) );
376 dict.insert( "Children", new int(Qtopia::Children) );
377 dict.insert( "Gender", new int(Qtopia::Gender) );
378 dict.insert( "Birthday", new int(Qtopia::Birthday) );
379 dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
380 dict.insert( "Nickname", new int(Qtopia::Nickname) );
381 dict.insert( "Notes", new int(Qtopia::Notes) );
382 dict.insert( "action", new int(JOURNALACTION) );
383 dict.insert( "actionrow", new int(JOURNALROW) );
384
385 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
386
387 XMLElement *root = XMLElement::load( filename );
388 if(root != 0l ){ // start parsing
389 /* Parse all XML-Elements and put the data into the
390 * Contact-Class
391 */
392 XMLElement *element = root->firstChild();
393 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
394 element = element->firstChild();
395
396 /* Search Tag "Contacts" which is the parent of all Contacts */
397 while( element && !isJournal ){
398 if( element->tagName() != QString::fromLatin1("Contacts") ){
399 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
400 // element->tagName().latin1());
401 element = element->nextChild();
402 } else {
403 element = element->firstChild();
404 break;
405 }
406 }
407 /* Parse all Contacts and ignore unknown tags */
408 while( element ){
409 if( element->tagName() != QString::fromLatin1("Contact") ){
410 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
411 // element->tagName().latin1());
412 element = element->nextChild();
413 continue;
414 }
415 /* Found alement with tagname "contact", now parse and store all
416 * attributes contained
417 */
418 //qWarning("OContactDefBack::load element tagName() : %s",
419 // element->tagName().latin1() );
420 QString dummy;
421 foundAction = false;
422
423 XMLElement::AttributeMap aMap = element->attributes();
424 XMLElement::AttributeMap::Iterator it;
425 contactMap.clear();
426 customMap.clear();
427 for( it = aMap.begin(); it != aMap.end(); ++it ){
428 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
429
430 int *find = dict[ it.key() ];
431 /* Unknown attributes will be stored as "Custom" elements */
432 if ( !find ) {
433 qWarning("Attribute %s not known.", it.key().latin1());
434 //contact.setCustomField(it.key(), it.data());
435 customMap.insert( it.key(), it.data() );
436 continue;
437 }
438
439 /* Check if special conversion is needed and add attribute
440 * into Contact class
441 */
442 switch( *find ) {
443 /*
444 case Qtopia::AddressUid:
445 contact.setUid( it.data().toInt() );
446 break;
447 case Qtopia::AddressCategory:
448 contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
449 break;
450 */
451 case JOURNALACTION:
452 action = OContact::journal_action(it.data().toInt());
453 foundAction = true;
454 qWarning ("ODefBack(journal)::ACTION found: %d", action);
455 break;
456 case JOURNALROW:
457 journalKey = it.data().toInt();
458 break;
459 default: // no conversion needed add them to the map
460 contactMap.insert( *find, it.data() );
461 break;
462 }
463 }
464 /* now generate the Contact contact */
465 OContact contact( contactMap );
466
467 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
468 contact.setCustomField( customIt.key(), customIt.data() );
469 }
470
471 if (foundAction){
472 foundAction = false;
473 switch ( action ) {
474 case OContact::ACTION_ADD:
475 addContact_p (contact);
476 break;
477 case OContact::ACTION_REMOVE:
478 if ( !remove (contact.uid()) )
479 qWarning ("ODefBack(journal)::Unable to remove uid: %d",
480 contact.uid() );
481 break;
482 case OContact::ACTION_REPLACE:
483 if ( !replace ( contact ) )
484 qWarning ("ODefBack(journal)::Unable to replace uid: %d",
485 contact.uid() );
486 break;
487 default:
488 qWarning ("Unknown action: ignored !");
489 break;
490 }
491 }else{
492 /* Add contact to list */
493 addContact_p (contact);
494 }
495
496 /* Move to next element */
497 element = element->nextChild();
498 }
499 }else {
500 qWarning("ODefBack::could not load");
501 }
502 delete root;
503 qWarning("returning from loading" );
504 return true;
505 }
506
507
508 void updateJournal( const OContact& cnt,
509 OContact::journal_action action ) {
510 QFile f( m_journalName );
511 bool created = !f.exists();
512 if ( !f.open(IO_WriteOnly|IO_Append) )
513 return;
514
515 QString buf;
516 QCString str;
517
518 // if the file was created, we have to set the Tag "<CONTACTS>" to
519 // get a XML-File which is readable by our parser.
520 // This is just a cheat, but better than rewrite the parser.
521 if ( created ){
522 buf = "<Contacts>";
523 QCString cstr = buf.utf8();
524 f.writeBlock( cstr.data(), cstr.length() );
525 }
526
527 buf = "<Contact ";
528 cnt.save( buf );
529 buf += " action=\"" + QString::number( (int)action ) + "\" ";
530 buf += "/>\n";
531 QCString cstr = buf.utf8();
532 f.writeBlock( cstr.data(), cstr.length() );
533 }
534
535 void removeJournal()
536 {
537 QFile f ( m_journalName );
538 if ( f.exists() )
539 f.remove();
540 }
541
542 protected:
543 QString m_journalName;
544 QString m_fileName;
545 QString m_appName;
546 QValueList<OContact> m_contactList;
547 QDateTime m_readtime;
548};
549
550#endif
diff --git a/libopie2/opiepim/core/ocontactaccess.cpp b/libopie2/opiepim/core/ocontactaccess.cpp
new file mode 100644
index 0000000..2d808f7
--- a/dev/null
+++ b/libopie2/opiepim/core/ocontactaccess.cpp
@@ -0,0 +1,174 @@
1/*
2 * Class to manage the Contacts.
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 * Info: This class could just work with a change in the header-file
13 * of the Contact class ! Therefore our libopie only compiles
14 * with our version of libqpe
15 * =====================================================================
16 * ToDo: XML-Backend: Automatic reload if something was changed...
17 *
18 *
19 * =====================================================================
20 * Version: $Id$
21 * =====================================================================
22 * History:
23 * $Log$
24 * Revision 1.1 2002/09/27 17:11:44 eilers
25 * Added API for accessing the Contact-Database ! It is compiling, but
26 * please do not expect that anything is working !
27 * I will debug that stuff in the next time ..
28 * Please read README_COMPILE for compiling !
29 *
30 *
31 */
32
33#include "ocontactaccess.h"
34
35#include <qasciidict.h>
36#include <qdatetime.h>
37#include <qfile.h>
38#include <qregexp.h>
39#include <qlist.h>
40#include <qcopchannel_qws.h>
41
42//#include <qpe/qcopenvelope_qws.h>
43#include <qpe/global.h>
44
45#include <errno.h>
46#include <fcntl.h>
47#include <unistd.h>
48#include <stdlib.h>
49
50#include "ocontactaccessbackend_xml.h"
51
52
53OContactAccess::OContactAccess ( const QString appname, const QString filename,
54 OContactAccessBackend* end, bool autosync ):
55 OPimAccessTemplate<OContact>( end ),
56 m_changed ( false )
57{
58 /* take care of the backend. If there is no one defined, we
59 * will use the XML-Backend as default (until we have a cute SQL-Backend..).
60 */
61 if( end == 0 ) {
62 end = new OContactAccessBackend_XML( appname, filename );
63 }
64 m_backEnd = end;
65
66 /* Connect signal of external db change to function */
67 QCopChannel *dbchannel = new QCopChannel( "QPE/PIM", this );
68 connect( dbchannel, SIGNAL(received(const QCString &, const QByteArray &)),
69 this, SLOT(copMessage( const QCString &, const QByteArray &)) );
70 if ( autosync ){
71 QCopChannel *syncchannel = new QCopChannel( "QPE/Sync", this );
72 connect( syncchannel, SIGNAL(received(const QCString &, const QByteArray &)),
73 this, SLOT(copMessage( const QCString &, const QByteArray &)) );
74 }
75
76
77}
78OContactAccess::~OContactAccess ()
79{
80 /* The user may forget to save the changed database, therefore try to
81 * do it for him..
82 */
83 if ( m_changed )
84 save();
85 delete m_backEnd;
86}
87
88bool OContactAccess::load()
89{
90 return ( m_backEnd->load() );
91}
92
93bool OContactAccess::save ()
94{
95 /* If the database was changed externally, we could not save the
96 * Data. This will remove added items which is unacceptable !
97 * Therefore: Reload database and merge the data...
98 */
99 if ( m_backEnd->wasChangedExternally() )
100 reload();
101
102 if ( m_changed ){
103 bool status = m_backEnd->save();
104 if ( !status ) return false;
105
106 m_changed = false;
107 /* Now tell everyone that new data is available.
108 */
109 QCopEnvelope e( "QPE/PIM", "addressbookUpdated()" );
110
111 }
112
113 return true;
114}
115
116const uint OContactAccess::querySettings()
117{
118 return ( m_backEnd->querySettings() );
119}
120
121bool OContactAccess::hasQuerySettings ( int querySettings ) const
122{
123 return ( m_backEnd->hasQuerySettings ( querySettings ) );
124}
125
126bool OContactAccess::add ( const OContact& newcontact )
127{
128 m_changed = true;
129 return ( m_backEnd->add ( newcontact ) );
130}
131
132bool OContactAccess::replace ( const OContact& contact )
133{
134 m_changed = true;
135 return ( m_backEnd->replace ( contact ) );
136}
137
138bool OContactAccess::remove ( const OContact& t )
139{
140 m_changed = true;
141 return ( m_backEnd->remove ( t.uid() ) );
142}
143
144bool OContactAccess::remove ( int uid )
145{
146 m_changed = true;
147 return ( m_backEnd->remove ( uid ) );
148}
149
150bool OContactAccess::wasChangedExternally()const
151{
152 return ( m_backEnd->wasChangedExternally() );
153}
154
155
156bool OContactAccess::reload()
157{
158 return ( m_backEnd->reload() );
159}
160
161void OContactAccess::copMessage( const QCString &msg, const QByteArray & )
162{
163 if ( msg == "addressbookUpdated()" ){
164 qWarning ("OContactAccess: Received addressbokUpdated()");
165 emit signalChanged ( this );
166 } else if ( msg == "flush()" ) {
167 qWarning ("OContactAccess: Received flush()");
168 save ();
169 } else if ( msg == "reload()" ) {
170 qWarning ("OContactAccess: Received reload()");
171 reload ();
172 emit signalChanged ( this );
173 }
174}
diff --git a/libopie2/opiepim/core/ocontactaccess.h b/libopie2/opiepim/core/ocontactaccess.h
new file mode 100644
index 0000000..54f7f07
--- a/dev/null
+++ b/libopie2/opiepim/core/ocontactaccess.h
@@ -0,0 +1,197 @@
1/*
2 * Class to manage the Contacts.
3 *
4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
5 * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org)
6 *
7 * =====================================================================
8 *This program is free software; you can redistribute it and/or
9 *modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation;
11 * either version 2 of the License, or (at your option) any later
12 * version.
13 * =====================================================================
14 * ToDo: Define enum for query settings
15 * =====================================================================
16 * Version: $Id$
17 * =====================================================================
18 * History:
19 * $Log$
20 * Revision 1.1 2002/09/27 17:11:44 eilers
21 * Added API for accessing the Contact-Database ! It is compiling, but
22 * please do not expect that anything is working !
23 * I will debug that stuff in the next time ..
24 * Please read README_COMPILE for compiling !
25 *
26 * =====================================================================
27 */
28#ifndef _OCONTACTACCESS_H
29#define _OCONTACTACCESS_H
30
31#include <qobject.h>
32
33#include <qpe/qcopenvelope_qws.h>
34
35#include <qvaluelist.h>
36#include <qfileinfo.h>
37
38#include "ocontact.h"
39#include "ocontactaccessbackend.h"
40#include "opimaccesstemplate.h"
41
42/** Class to access the contacts database.
43 * This is just a frontend for the real database handling which is
44 * done by the backend.
45 */
46class OContactAccess: public QObject, public OPimAccessTemplate<OContact>
47{
48 Q_OBJECT
49
50
51 /* class Iterator{
52 friend OContactAccess;
53 public:
54 Iterator();
55 Iterator ( const Iterator& copy );
56
57 bool operator== ( const Iterator& it );
58 bool operator!= ( const Iterator& it );
59 Iterator& operator= ( const Iterator& it );
60 Iterator& operator++ (); // prefix
61 Iterator operator++ ( int ); // postfix
62 Iterator& operator-- (); // prefix
63 Iterator operator-- ( int ); // postfix
64 Contact operator*() const;
65 Contact operator->() const;
66
67 Iterator begin();
68 Iterator end();
69
70 uint count() const;
71
72 private:
73 QValueList<int> m_uids;
74 int m_cur_position;
75 bool m_end_reached;
76 OContactAccess *m_db;
77
78 };
79
80 */
81
82 public:
83 /** Create Database with contacts (addressbook).
84 * @param appname Name of application which wants access to the database
85 * (i.e. "todolist")
86 * @param filename The name of the database file. If not set, the default one
87 * is used.
88 * @param backend Pointer to an alternative Backend. If not set, we will use
89 * the default backend.
90 * @param handlesync If <b>true</b> the database stores the current state
91 * automatically if it receives the signals <i>flush()</i> and <i>reload()</i>
92 * which are used before and after synchronisation. If the application wants
93 * to react itself, it should be disabled by setting it to <b>false</b>
94 * @see OContactBackend
95 */
96 OContactAccess (const QString appname, const QString filename = 0l,
97 OContactAccessBackend* backend = 0l, bool handlesync = true);
98 ~OContactAccess ();
99
100 /** Constants for query.
101 * Use this constants to set the query parameters.
102 * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes !
103 * @see queryByExample()
104 * - why not enum - zecke?
105 * -> Had some implementation problems .. Will use enum soon ! .. (se)
106 */
107 static const int query_WildCards = 0x0001;
108 static const int query_IgnoreCase = 0x0002;
109 static const int query_RegExp = 0x0004;
110 static const int query_ExactMatch = 0x0008;
111
112 /** Return all possible settings.
113 * @return All settings provided by the current backend
114 * (i.e.: query_WildCards & query_IgnoreCase)
115 */
116 const uint querySettings();
117
118 /** Check whether settings are correct.
119 * @return <i>true</i> if the given settings are correct and possible.
120 */
121 bool hasQuerySettings ( int querySettings ) const;
122
123 /** Add Contact to database.
124 * @param newcontact The contact to add.
125 * @return <i>true</i> if added successfully.
126 */
127 bool add (const OContact& newcontact);
128
129 /** Replace contact.
130 * Replaces given contact with contact with the user id <i>uid</i>.
131 * @param uid The user ID
132 * @param contact The new contact
133 * @return <i>true</i> if successful.
134 */
135 bool replace ( const OContact& contact );
136
137 /** Remove contact.
138 * Removes contact with the user id <i>uid</i>.
139 * @param The contact to remove
140 * @return <i>true</i> if successful.
141 */
142 bool remove ( const OContact& t );
143
144 /** Remove contact.
145 * Removes contact with the user id <i>uid</i>.
146 * @param The user id of the contact to remove
147 * @return <i>true</i> if successful.
148 */
149 bool remove ( int uid );
150
151 /** Load Database *
152 */
153 bool load();
154
155 /**
156 * if the resource was changed externally.
157 * You should use the signal instead of polling possible changes !
158 */
159 bool wasChangedExternally()const;
160
161 /** Reload database.
162 * You should execute this function if the external database
163 * was changed.
164 * This function will load the external database and afterwards
165 * rejoin the local changes. Therefore the local database will be set consistent.
166 */
167 bool reload();
168
169 /** Save contacts database.
170 * Save is more a "commit". After calling this function, all changes are public available.
171 * @return true if successful
172 */
173 bool save();
174
175 signals:
176 /* Signal is emitted if the database was changed. Therefore
177 * we may need to reload to stay consistent.
178 * @param which Pointer to the database who created this event. This pointer
179 * is useful if an application has to handle multiple databases at the same time.
180 * @see reload()
181 */
182 void signalChanged ( const OContactAccess *which );
183
184
185 private:
186 // class OContactAccessPrivate;
187 // OContactAccessPrivate* d;
188 OContactAccessBackend *m_backEnd;
189 bool m_loading:1;
190 bool m_changed;
191
192 private slots:
193 void copMessage( const QCString &msg, const QByteArray &data );
194
195
196};
197#endif
diff --git a/libopie2/opiepim/ocontact.cpp b/libopie2/opiepim/ocontact.cpp
new file mode 100644
index 0000000..66632f5
--- a/dev/null
+++ b/libopie2/opiepim/ocontact.cpp
@@ -0,0 +1,1433 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#define QTOPIA_INTERNAL_CONTACT_MRE
22
23#include "ocontact.h"
24#include "vobject_p.h"
25#include "qfiledirect_p.h"
26
27#include <qpe/stringutil.h>
28#include <qpe/timeconversion.h>
29
30#include <qobject.h>
31#include <qregexp.h>
32#include <qstylesheet.h>
33#include <qfileinfo.h>
34#include <qmap.h>
35
36#include <stdio.h>
37
38/*!
39 \class Contact contact.h
40 \brief The Contact class holds the data of an address book entry.
41
42 This data includes information the name of the person, contact
43 information, and business information such as deparment and job title.
44
45 \ingroup qtopiaemb
46 \ingroup qtopiadesktop
47*/
48
49Qtopia::UidGen OContact::sUidGen( Qtopia::UidGen::Qtopia );
50
51/*!
52 Creates a new, empty contact.
53*/
54OContact::OContact()
55 : OPimRecord(), mMap(), d( 0 )
56{
57}
58
59/*!
60 \internal
61 Creates a new contact. The properties of the contact are
62 set from \a fromMap.
63*/
64OContact::OContact( const QMap<int, QString> &fromMap ) :
65 OPimRecord(), mMap( fromMap ), d( 0 )
66{
67 QString cats = mMap[ Qtopia::AddressCategory ];
68 if ( !cats.isEmpty() )
69 setCategories( idsFromString( cats ) );
70 QString uidStr = find( Qtopia::AddressUid );
71
72 if ( uidStr.isEmpty() )
73 setUid( uidGen().generate() );
74 else
75 setUid( uidStr.toInt() );
76
77 if ( !uidStr.isEmpty() )
78 setUid( uidStr.toInt() );
79}
80
81/*!
82 Destroys a contact.
83*/
84OContact::~OContact()
85{
86}
87
88/*! \fn void OContact::setTitle( const QString &str )
89 Sets the title of the contact to \a str.
90*/
91
92/*! \fn void OContact::setFirstName( const QString &str )
93 Sets the first name of the contact to \a str.
94*/
95
96/*! \fn void OContact::setMiddleName( const QString &str )
97 Sets the middle name of the contact to \a str.
98*/
99
100/*! \fn void OContact::setLastName( const QString &str )
101 Sets the last name of the contact to \a str.
102*/
103
104/*! \fn void OContact::setSuffix( const QString &str )
105 Sets the suffix of the contact to \a str.
106*/
107
108/*! \fn void OContact::setFileAs( const QString &str )
109 Sets the contact to filed as \a str.
110*/
111
112/*! \fn void OContact::setDefaultEmail( const QString &str )
113 Sets the default email of the contact to \a str.
114*/
115
116/*! \fn void OContact::setHomeStreet( const QString &str )
117 Sets the home street address of the contact to \a str.
118*/
119
120/*! \fn void OContact::setHomeCity( const QString &str )
121 Sets the home city of the contact to \a str.
122*/
123
124/*! \fn void OContact::setHomeState( const QString &str )
125 Sets the home state of the contact to \a str.
126*/
127
128/*! \fn void OContact::setHomeZip( const QString &str )
129 Sets the home zip code of the contact to \a str.
130*/
131
132/*! \fn void OContact::setHomeCountry( const QString &str )
133 Sets the home country of the contact to \a str.
134*/
135
136/*! \fn void OContact::setHomePhone( const QString &str )
137 Sets the home phone number of the contact to \a str.
138*/
139
140/*! \fn void OContact::setHomeFax( const QString &str )
141 Sets the home fax number of the contact to \a str.
142*/
143
144/*! \fn void OContact::setHomeMobile( const QString &str )
145 Sets the home mobile phone number of the contact to \a str.
146*/
147
148/*! \fn void OContact::setHomeWebpage( const QString &str )
149 Sets the home webpage of the contact to \a str.
150*/
151
152/*! \fn void OContact::setCompany( const QString &str )
153 Sets the company for contact to \a str.
154*/
155
156/*! \fn void OContact::setJobTitle( const QString &str )
157 Sets the job title of the contact to \a str.
158*/
159
160/*! \fn void OContact::setDepartment( const QString &str )
161 Sets the department for contact to \a str.
162*/
163
164/*! \fn void OContact::setOffice( const QString &str )
165 Sets the office for contact to \a str.
166*/
167
168/*! \fn void OContact::setBusinessStreet( const QString &str )
169 Sets the business street address of the contact to \a str.
170*/
171
172/*! \fn void OContact::setBusinessCity( const QString &str )
173 Sets the business city of the contact to \a str.
174*/
175
176/*! \fn void OContact::setBusinessState( const QString &str )
177 Sets the business state of the contact to \a str.
178*/
179
180/*! \fn void OContact::setBusinessZip( const QString &str )
181 Sets the business zip code of the contact to \a str.
182*/
183
184/*! \fn void OContact::setBusinessCountry( const QString &str )
185 Sets the business country of the contact to \a str.
186*/
187
188/*! \fn void OContact::setBusinessPhone( const QString &str )
189 Sets the business phone number of the contact to \a str.
190*/
191
192/*! \fn void OContact::setBusinessFax( const QString &str )
193 Sets the business fax number of the contact to \a str.
194*/
195
196/*! \fn void OContact::setBusinessMobile( const QString &str )
197 Sets the business mobile phone number of the contact to \a str.
198*/
199
200/*! \fn void OContact::setBusinessPager( const QString &str )
201 Sets the business pager number of the contact to \a str.
202*/
203
204/*! \fn void OContact::setBusinessWebpage( const QString &str )
205 Sets the business webpage of the contact to \a str.
206*/
207
208/*! \fn void OContact::setProfession( const QString &str )
209 Sets the profession of the contact to \a str.
210*/
211
212/*! \fn void OContact::setAssistant( const QString &str )
213 Sets the assistant of the contact to \a str.
214*/
215
216/*! \fn void OContact::setManager( const QString &str )
217 Sets the manager of the contact to \a str.
218*/
219
220/*! \fn void OContact::setSpouse( const QString &str )
221 Sets the spouse of the contact to \a str.
222*/
223
224/*! \fn void OContact::setGender( const QString &str )
225 Sets the gender of the contact to \a str.
226*/
227
228/*! \fn void OContact::setBirthday( const QString &str )
229 Sets the birthday for the contact to \a str.
230*/
231
232/*! \fn void OContact::setAnniversary( const QString &str )
233 Sets the anniversary of the contact to \a str.
234*/
235
236/*! \fn void OContact::setNickname( const QString &str )
237 Sets the nickname of the contact to \a str.
238*/
239
240/*! \fn void OContact::setNotes( const QString &str )
241 Sets the notes about the contact to \a str.
242*/
243
244/*! \fn QString OContact::title() const
245 Returns the title of the contact.
246*/
247
248/*! \fn QString OContact::firstName() const
249 Returns the first name of the contact.
250*/
251
252/*! \fn QString OContact::middleName() const
253 Returns the middle name of the contact.
254*/
255
256/*! \fn QString OContact::lastName() const
257 Returns the last name of the contact.
258*/
259
260/*! \fn QString OContact::suffix() const
261 Returns the suffix of the contact.
262*/
263
264/*! \fn QString OContact::fileAs() const
265 Returns the string the contact is filed as.
266*/
267
268/*! \fn QString OContact::defaultEmail() const
269 Returns the default email address of the contact.
270*/
271
272/*! \fn QString OContact::emails() const
273 Returns the list of email address for a contact separated by ';'s in a single
274 string.
275*/
276
277/*! \fn QString OContact::homeStreet() const
278 Returns the home street address of the contact.
279*/
280
281/*! \fn QString OContact::homeCity() const
282 Returns the home city of the contact.
283*/
284
285/*! \fn QString OContact::homeState() const
286 Returns the home state of the contact.
287*/
288
289/*! \fn QString OContact::homeZip() const
290 Returns the home zip of the contact.
291*/
292
293/*! \fn QString OContact::homeCountry() const
294 Returns the home country of the contact.
295*/
296
297/*! \fn QString OContact::homePhone() const
298 Returns the home phone number of the contact.
299*/
300
301/*! \fn QString OContact::homeFax() const
302 Returns the home fax number of the contact.
303*/
304
305/*! \fn QString OContact::homeMobile() const
306 Returns the home mobile number of the contact.
307*/
308
309/*! \fn QString OContact::homeWebpage() const
310 Returns the home webpage of the contact.
311*/
312
313/*! \fn QString OContact::company() const
314 Returns the company for the contact.
315*/
316
317/*! \fn QString OContact::department() const
318 Returns the department for the contact.
319*/
320
321/*! \fn QString OContact::office() const
322 Returns the office for the contact.
323*/
324
325/*! \fn QString OContact::jobTitle() const
326 Returns the job title of the contact.
327*/
328
329/*! \fn QString OContact::profession() const
330 Returns the profession of the contact.
331*/
332
333/*! \fn QString OContact::assistant() const
334 Returns the assistant of the contact.
335*/
336
337/*! \fn QString OContact::manager() const
338 Returns the manager of the contact.
339*/
340
341/*! \fn QString OContact::businessStreet() const
342 Returns the business street address of the contact.
343*/
344
345/*! \fn QString OContact::businessCity() const
346 Returns the business city of the contact.
347*/
348
349/*! \fn QString OContact::businessState() const
350 Returns the business state of the contact.
351*/
352
353/*! \fn QString OContact::businessZip() const
354 Returns the business zip of the contact.
355*/
356
357/*! \fn QString OContact::businessCountry() const
358 Returns the business country of the contact.
359*/
360
361/*! \fn QString OContact::businessPhone() const
362 Returns the business phone number of the contact.
363*/
364
365/*! \fn QString OContact::businessFax() const
366 Returns the business fax number of the contact.
367*/
368
369/*! \fn QString OContact::businessMobile() const
370 Returns the business mobile number of the contact.
371*/
372
373/*! \fn QString OContact::businessPager() const
374 Returns the business pager number of the contact.
375*/
376
377/*! \fn QString OContact::businessWebpage() const
378 Returns the business webpage of the contact.
379*/
380
381/*! \fn QString OContact::spouse() const
382 Returns the spouse of the contact.
383*/
384
385/*! \fn QString OContact::gender() const
386 Returns the gender of the contact.
387*/
388
389/*! \fn QString OContact::birthday() const
390 Returns the birthday of the contact.
391*/
392
393/*! \fn QString OContact::anniversary() const
394 Returns the anniversary of the contact.
395*/
396
397/*! \fn QString OContact::nickname() const
398 Returns the nickname of the contact.
399*/
400
401/*! \fn QString OContact::children() const
402 Returns the children of the contact.
403*/
404
405/*! \fn QString OContact::notes() const
406 Returns the notes relating to the the contact.
407*/
408
409/*! \fn QString OContact::groups() const
410 \internal
411 Returns the groups for the contact.
412*/
413
414/*! \fn QStringList OContact::groupList() const
415 \internal
416*/
417
418/*! \fn QString OContact::field(int) const
419 \internal
420*/
421
422/*! \fn void OContact::saveJournal( journal_action, const QString & = QString::null )
423 \internal
424*/
425
426/*! \fn void OContact::setUid( int id )
427 \internal
428 Sets the uid for this record to \a id.
429*/
430
431/*! \enum OContact::journal_action
432 \internal
433*/
434
435/*!
436 \internal
437*/
438QMap<int, QString> OContact::toMap() const
439{
440 QMap<int, QString> map = mMap;
441 QString cats = idsToString( categories() );
442 if ( !cats.isEmpty() )
443 map.insert( Qtopia::AddressCategory, cats );
444 return map;
445}
446
447/*!
448 Returns a rich text formatted QString representing the contents the contact.
449*/
450QString OContact::toRichText() const
451{
452 QString text;
453 QString value, comp, state;
454
455 // name, jobtitle and company
456 if ( !(value = fullName()).isEmpty() )
457 text += "<b>" + Qtopia::escapeString(value) + "</b><br>";
458 if ( !(value = jobTitle()).isEmpty() )
459 text += Qtopia::escapeString(value) + "<br>";
460
461 comp = company();
462 if ( !(value = department()).isEmpty() ) {
463 text += Qtopia::escapeString(value);
464 if ( comp )
465 text += ", ";
466 else
467 text += "<br>";
468 }
469 if ( !comp.isEmpty() )
470 text += Qtopia::escapeString(comp) + "<br>";
471
472 // business address
473 if ( !businessStreet().isEmpty() || !businessCity().isEmpty() ||
474 !businessZip().isEmpty() || !businessCountry().isEmpty() ) {
475 text += "<br>";
476 text += QObject::tr( "<b>Work Address:</b>" );
477 text += "<br>";
478 }
479
480 if ( !(value = businessStreet()).isEmpty() )
481 text += Qtopia::escapeString(value) + "<br>";
482 state = businessState();
483 if ( !(value = businessCity()).isEmpty() ) {
484 text += Qtopia::escapeString(value);
485 if ( state )
486 text += ", " + Qtopia::escapeString(state);
487 text += "<br>";
488 } else if ( !state.isEmpty() )
489 text += Qtopia::escapeString(state) + "<br>";
490 if ( !(value = businessZip()).isEmpty() )
491 text += Qtopia::escapeString(value) + "<br>";
492 if ( !(value = businessCountry()).isEmpty() )
493 text += Qtopia::escapeString(value) + "<br>";
494
495 // home address
496 if ( !homeStreet().isEmpty() || !homeCity().isEmpty() ||
497 !homeZip().isEmpty() || !homeCountry().isEmpty() ) {
498 text += "<br>";
499 text += QObject::tr( "<b>Home Address:</b>" );
500 text += "<br>";
501 }
502
503 if ( !(value = homeStreet()).isEmpty() )
504 text += Qtopia::escapeString(value) + "<br>";
505 state = homeState();
506 if ( !(value = homeCity()).isEmpty() ) {
507 text += Qtopia::escapeString(value);
508 if ( !state.isEmpty() )
509 text += ", " + Qtopia::escapeString(state);
510 text += "<br>";
511 } else if (!state.isEmpty())
512 text += Qtopia::escapeString(state) + "<br>";
513 if ( !(value = homeZip()).isEmpty() )
514 text += Qtopia::escapeString(value) + "<br>";
515 if ( !(value = homeCountry()).isEmpty() )
516 text += Qtopia::escapeString(value) + "<br>";
517
518 // the others...
519 QString str;
520 str = emails();
521 if ( !str.isEmpty() )
522 text += "<b>" + QObject::tr("Email Addresses: ") + "</b>"
523 + Qtopia::escapeString(str) + "<br>";
524 str = homePhone();
525 if ( !str.isEmpty() )
526 text += "<b>" + QObject::tr("Home Phone: ") + "</b>"
527 + Qtopia::escapeString(str) + "<br>";
528 str = homeFax();
529 if ( !str.isEmpty() )
530 text += "<b>" + QObject::tr("Home Fax: ") + "</b>"
531 + Qtopia::escapeString(str) + "<br>";
532 str = homeMobile();
533 if ( !str.isEmpty() )
534 text += "<b>" + QObject::tr("Home Mobile: ") + "</b>"
535 + Qtopia::escapeString(str) + "<br>";
536 str = homeWebpage();
537 if ( !str.isEmpty() )
538 text += "<b>" + QObject::tr("Home Web Page: ") + "</b>"
539 + Qtopia::escapeString(str) + "<br>";
540 str = businessWebpage();
541 if ( !str.isEmpty() )
542 text += "<b>" + QObject::tr("Business Web Page: ") + "</b>"
543 + Qtopia::escapeString(str) + "<br>";
544 str = office();
545 if ( !str.isEmpty() )
546 text += "<b>" + QObject::tr("Office: ") + "</b>"
547 + Qtopia::escapeString(str) + "<br>";
548 str = businessPhone();
549 if ( !str.isEmpty() )
550 text += "<b>" + QObject::tr("Business Phone: ") + "</b>"
551 + Qtopia::escapeString(str) + "<br>";
552 str = businessFax();
553 if ( !str.isEmpty() )
554 text += "<b>" + QObject::tr("Business Fax: ") + "</b>"
555 + Qtopia::escapeString(str) + "<br>";
556 str = businessMobile();
557 if ( !str.isEmpty() )
558 text += "<b>" + QObject::tr("Business Mobile: ") + "</b>"
559 + Qtopia::escapeString(str) + "<br>";
560 str = businessPager();
561 if ( !str.isEmpty() )
562 text += "<b>" + QObject::tr("Business Pager: ") + "</b>"
563 + Qtopia::escapeString(str) + "<br>";
564 str = profession();
565 if ( !str.isEmpty() )
566 text += "<b>" + QObject::tr("Profession: ") + "</b>"
567 + Qtopia::escapeString(str) + "<br>";
568 str = assistant();
569 if ( !str.isEmpty() )
570 text += "<b>" + QObject::tr("Assistant: ") + "</b>"
571 + Qtopia::escapeString(str) + "<br>";
572 str = manager();
573 if ( !str.isEmpty() )
574 text += "<b>" + QObject::tr("Manager: ") + "</b>"
575 + Qtopia::escapeString(str) + "<br>";
576 str = gender();
577 if ( !str.isEmpty() && str.toInt() != 0 ) {
578 if ( str.toInt() == 1 )
579 str = QObject::tr( "Male" );
580 else if ( str.toInt() == 2 )
581 str = QObject::tr( "Female" );
582 text += "<b>" + QObject::tr("Gender: ") + "</b>" + str + "<br>";
583 }
584 str = spouse();
585 if ( !str.isEmpty() )
586 text += "<b>" + QObject::tr("Spouse: ") + "</b>"
587 + Qtopia::escapeString(str) + "<br>";
588 str = birthday();
589 if ( !str.isEmpty() )
590 text += "<b>" + QObject::tr("Birthday: ") + "</b>"
591 + Qtopia::escapeString(str) + "<br>";
592 str = anniversary();
593 if ( !str.isEmpty() )
594 text += "<b>" + QObject::tr("Anniversary: ") + "</b>"
595 + Qtopia::escapeString(str) + "<br>";
596 str = nickname();
597 if ( !str.isEmpty() )
598 text += "<b>" + QObject::tr("Nickname: ") + "</b>"
599 + Qtopia::escapeString(str) + "<br>";
600
601 // notes last
602 if ( (value = notes()) ) {
603 QRegExp reg("\n");
604
605 //QString tmp = Qtopia::escapeString(value);
606 QString tmp = QStyleSheet::convertFromPlainText(value);
607 //tmp.replace( reg, "<br>" );
608 text += "<br>" + tmp + "<br>";
609 }
610 return text;
611}
612
613/*!
614 \internal
615*/
616void OContact::insert( int key, const QString &v )
617{
618 QString value = v.stripWhiteSpace();
619 if ( value.isEmpty() )
620 mMap.remove( key );
621 else
622 mMap.insert( key, value );
623}
624
625/*!
626 \internal
627*/
628void OContact::replace( int key, const QString & v )
629{
630 QString value = v.stripWhiteSpace();
631 if ( value.isEmpty() )
632 mMap.remove( key );
633 else
634 mMap.replace( key, value );
635}
636
637/*!
638 \internal
639*/
640QString OContact::find( int key ) const
641{
642 return mMap[key];
643}
644
645/*!
646 \internal
647*/
648QString OContact::displayAddress( const QString &street,
649 const QString &city,
650 const QString &state,
651 const QString &zip,
652 const QString &country ) const
653{
654 QString s = street;
655 if ( !street.isEmpty() )
656 s+= "\n";
657 s += city;
658 if ( !city.isEmpty() && !state.isEmpty() )
659 s += ", ";
660 s += state;
661 if ( !state.isEmpty() && !zip.isEmpty() )
662 s += " ";
663 s += zip;
664 if ( !country.isEmpty() && !s.isEmpty() )
665 s += "\n";
666 s += country;
667 return s;
668}
669
670/*!
671 \internal
672*/
673QString OContact::displayBusinessAddress() const
674{
675 return displayAddress( businessStreet(), businessCity(),
676 businessState(), businessZip(),
677 businessCountry() );
678}
679
680/*!
681 \internal
682*/
683QString OContact::displayHomeAddress() const
684{
685 return displayAddress( homeStreet(), homeCity(),
686 homeState(), homeZip(),
687 homeCountry() );
688}
689
690/*!
691 Returns the full name of the contact
692*/
693QString OContact::fullName() const
694{
695 QString title = find( Qtopia::Title );
696 QString firstName = find( Qtopia::FirstName );
697 QString middleName = find( Qtopia::MiddleName );
698 QString lastName = find( Qtopia::LastName );
699 QString suffix = find( Qtopia::Suffix );
700
701 QString name = title;
702 if ( !firstName.isEmpty() ) {
703 if ( !name.isEmpty() )
704 name += " ";
705 name += firstName;
706 }
707 if ( !middleName.isEmpty() ) {
708 if ( !name.isEmpty() )
709 name += " ";
710 name += middleName;
711 }
712 if ( !lastName.isEmpty() ) {
713 if ( !name.isEmpty() )
714 name += " ";
715 name += lastName;
716 }
717 if ( !suffix.isEmpty() ) {
718 if ( !name.isEmpty() )
719 name += " ";
720 name += suffix;
721 }
722 return name.simplifyWhiteSpace();
723}
724
725/*!
726 Returns a list of the names of the children of the contact.
727*/
728QStringList OContact::childrenList() const
729{
730 return QStringList::split( " ", find( Qtopia::Children ) );
731}
732
733/*! \fn void OContact::insertEmail( const QString &email )
734
735 Insert \a email into the email list. Ensures \a email can only be added
736 once. If there is no default email address set, it sets it to the \a email.
737*/
738
739/*! \fn void OContact::removeEmail( const QString &email )
740
741 Removes the \a email from the email list. If the default email was \a email,
742 then the default email address is assigned to the first email in the
743 email list
744*/
745
746/*! \fn void OContact::clearEmails()
747
748 Clears the email list.
749 */
750
751/*! \fn void OContact::insertEmails( const QStringList &emailList )
752
753 Appends the \a emailList to the exiting email list
754 */
755
756/*!
757 Returns a list of email addresses belonging to the contact, including
758 the default email address.
759*/
760QStringList OContact::emailList() const
761{
762 QString emailStr = emails();
763
764 QStringList r;
765 if ( !emailStr.isEmpty() ) {
766 qDebug(" emailstr ");
767 QStringList l = QStringList::split( emailSeparator(), emailStr );
768 for ( QStringList::ConstIterator it = l.begin();it != l.end();++it )
769 r += (*it).simplifyWhiteSpace();
770 }
771
772 return r;
773}
774
775/*!
776 \overload
777
778 Generates the string for the contact to be filed as from the first,
779 middle and last name of the contact.
780*/
781void OContact::setFileAs()
782{
783 QString lastName, firstName, middleName, fileas;
784
785 lastName = find( Qtopia::LastName );
786 firstName = find( Qtopia::FirstName );
787 middleName = find( Qtopia::MiddleName );
788 if ( !lastName.isEmpty() && !firstName.isEmpty()
789 && !middleName.isEmpty() )
790 fileas = lastName + ", " + firstName + " " + middleName;
791 else if ( !lastName.isEmpty() && !firstName.isEmpty() )
792 fileas = lastName + ", " + firstName;
793 else if ( !lastName.isEmpty() || !firstName.isEmpty() ||
794 !middleName.isEmpty() )
795 fileas = firstName + ( firstName.isEmpty() ? "" : " " )
796 + middleName + ( middleName.isEmpty() ? "" : " " )
797 + lastName;
798
799 replace( Qtopia::FileAs, fileas );
800}
801
802/*!
803 \internal
804 Appends the contact information to \a buf.
805*/
806void OContact::save( QString &buf ) const
807{
808 static const QStringList SLFIELDS = fields();
809 // I'm expecting "<Contact " in front of this...
810 for ( QMap<int, QString>::ConstIterator it = mMap.begin();
811 it != mMap.end(); ++it ) {
812 const QString &value = it.data();
813 int key = it.key();
814 if ( !value.isEmpty() ) {
815 if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid)
816 continue;
817
818 key -= Qtopia::AddressCategory+1;
819 buf += SLFIELDS[key];
820 buf += "=\"" + Qtopia::escapeString(value) + "\" ";
821 }
822 }
823 buf += customToXml();
824 if ( categories().count() > 0 )
825 buf += "Categories=\"" + idsToString( categories() ) + "\" ";
826 buf += "Uid=\"" + QString::number( uid() ) + "\" ";
827 // You need to close this yourself
828}
829
830/*!
831 \internal
832 Returns the list of fields belonging to a contact
833*/
834QStringList OContact::fields()
835{
836 QStringList list;
837
838 list.append( "Title" ); // Not Used!
839 list.append( "FirstName" );
840 list.append( "MiddleName" );
841 list.append( "LastName" );
842 list.append( "Suffix" );
843 list.append( "FileAs" );
844
845 list.append( "JobTitle" );
846 list.append( "Department" );
847 list.append( "Company" );
848 list.append( "BusinessPhone" );
849 list.append( "BusinessFax" );
850 list.append( "BusinessMobile" );
851
852 list.append( "DefaultEmail" );
853 list.append( "Emails" );
854
855 list.append( "HomePhone" );
856 list.append( "HomeFax" );
857 list.append( "HomeMobile" );
858
859 list.append( "BusinessStreet" );
860 list.append( "BusinessCity" );
861 list.append( "BusinessState" );
862 list.append( "BusinessZip" );
863 list.append( "BusinessCountry" );
864 list.append( "BusinessPager" );
865 list.append( "BusinessWebPage" );
866
867 list.append( "Office" );
868 list.append( "Profession" );
869 list.append( "Assistant" );
870 list.append( "Manager" );
871
872 list.append( "HomeStreet" );
873 list.append( "HomeCity" );
874 list.append( "HomeState" );
875 list.append( "HomeZip" );
876 list.append( "HomeCountry" );
877 list.append( "HomeWebPage" );
878
879 list.append( "Spouse" );
880 list.append( "Gender" );
881 list.append( "Birthday" );
882 list.append( "Anniversary" );
883 list.append( "Nickname" );
884 list.append( "Children" );
885
886 list.append( "Notes" );
887 list.append( "Groups" );
888
889 return list;
890}
891
892/*!
893 \internal
894 Returns a translated list of field names for a contact.
895*/
896QStringList OContact::trfields()
897{
898 QStringList list;
899
900 list.append( QObject::tr( "Name Title") );
901 list.append( QObject::tr( "First Name" ) );
902 list.append( QObject::tr( "Middle Name" ) );
903 list.append( QObject::tr( "Last Name" ) );
904 list.append( QObject::tr( "Suffix" ) );
905 list.append( QObject::tr( "File As" ) );
906
907 list.append( QObject::tr( "Job Title" ) );
908 list.append( QObject::tr( "Department" ) );
909 list.append( QObject::tr( "Company" ) );
910 list.append( QObject::tr( "Business Phone" ) );
911 list.append( QObject::tr( "Business Fax" ) );
912 list.append( QObject::tr( "Business Mobile" ) );
913
914 list.append( QObject::tr( "Default Email" ) );
915 list.append( QObject::tr( "Emails" ) );
916
917 list.append( QObject::tr( "Home Phone" ) );
918 list.append( QObject::tr( "Home Fax" ) );
919 list.append( QObject::tr( "Home Mobile" ) );
920
921 list.append( QObject::tr( "Business Street" ) );
922 list.append( QObject::tr( "Business City" ) );
923 list.append( QObject::tr( "Business State" ) );
924 list.append( QObject::tr( "Business Zip" ) );
925 list.append( QObject::tr( "Business Country" ) );
926 list.append( QObject::tr( "Business Pager" ) );
927 list.append( QObject::tr( "Business WebPage" ) );
928
929 list.append( QObject::tr( "Office" ) );
930 list.append( QObject::tr( "Profession" ) );
931 list.append( QObject::tr( "Assistant" ) );
932 list.append( QObject::tr( "Manager" ) );
933
934 list.append( QObject::tr( "Home Street" ) );
935 list.append( QObject::tr( "Home City" ) );
936 list.append( QObject::tr( "Home State" ) );
937 list.append( QObject::tr( "Home Zip" ) );
938 list.append( QObject::tr( "Home Country" ) );
939 list.append( QObject::tr( "Home Web Page" ) );
940
941 list.append( QObject::tr( "Spouse" ) );
942 list.append( QObject::tr( "Gender" ) );
943 list.append( QObject::tr( "Birthday" ) );
944 list.append( QObject::tr( "Anniversary" ) );
945 list.append( QObject::tr( "Nickname" ) );
946 list.append( QObject::tr( "Children" ) );
947
948 list.append( QObject::tr( "Notes" ) );
949 list.append( QObject::tr( "Groups" ) );
950
951 return list;
952}
953
954/*!
955 Sets the list of email address for contact to those contained in \a str.
956 Email address should be separated by ';'s.
957*/
958void OContact::setEmails( const QString &str )
959{
960 replace( Qtopia::Emails, str );
961 if ( str.isEmpty() )
962 setDefaultEmail( QString::null );
963}
964
965/*!
966 Sets the list of children for the contact to those contained in \a str.
967*/
968void OContact::setChildren( const QString &str )
969{
970 replace( Qtopia::Children, str );
971}
972
973// vcard conversion code
974/*!
975 \internal
976*/
977static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value )
978{
979 VObject *ret = 0;
980 if ( o && !value.isEmpty() )
981 ret = addPropValue( o, prop, value.latin1() );
982 return ret;
983}
984
985/*!
986 \internal
987*/
988static inline VObject *safeAddProp( VObject *o, const char *prop)
989{
990 VObject *ret = 0;
991 if ( o )
992 ret = addProp( o, prop );
993 return ret;
994}
995
996/*!
997 \internal
998*/
999static VObject *createVObject( const OContact &c )
1000{
1001 VObject *vcard = newVObject( VCCardProp );
1002 safeAddPropValue( vcard, VCVersionProp, "2.1" );
1003 safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) );
1004 safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) );
1005
1006 // full name
1007 safeAddPropValue( vcard, VCFullNameProp, c.fullName() );
1008
1009 // name properties
1010 VObject *name = safeAddProp( vcard, VCNameProp );
1011 safeAddPropValue( name, VCFamilyNameProp, c.lastName() );
1012 safeAddPropValue( name, VCGivenNameProp, c.firstName() );
1013 safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() );
1014 safeAddPropValue( name, VCNamePrefixesProp, c.title() );
1015 safeAddPropValue( name, VCNameSuffixesProp, c.suffix() );
1016
1017 // home properties
1018 VObject *home_adr= safeAddProp( vcard, VCAdrProp );
1019 safeAddProp( home_adr, VCHomeProp );
1020 safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() );
1021 safeAddPropValue( home_adr, VCCityProp, c.homeCity() );
1022 safeAddPropValue( home_adr, VCRegionProp, c.homeState() );
1023 safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() );
1024 safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() );
1025
1026 VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() );
1027 safeAddProp( home_phone, VCHomeProp );
1028 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() );
1029 safeAddProp( home_phone, VCHomeProp );
1030 safeAddProp( home_phone, VCCellularProp );
1031 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() );
1032 safeAddProp( home_phone, VCHomeProp );
1033 safeAddProp( home_phone, VCFaxProp );
1034
1035 VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() );
1036 safeAddProp( url, VCHomeProp );
1037
1038 // work properties
1039 VObject *work_adr= safeAddProp( vcard, VCAdrProp );
1040 safeAddProp( work_adr, VCWorkProp );
1041 safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() );
1042 safeAddPropValue( work_adr, VCCityProp, c.businessCity() );
1043 safeAddPropValue( work_adr, VCRegionProp, c.businessState() );
1044 safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() );
1045 safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() );
1046
1047 VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() );
1048 safeAddProp( work_phone, VCWorkProp );
1049 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() );
1050 safeAddProp( work_phone, VCWorkProp );
1051 safeAddProp( work_phone, VCCellularProp );
1052 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() );
1053 safeAddProp( work_phone, VCWorkProp );
1054 safeAddProp( work_phone, VCFaxProp );
1055 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() );
1056 safeAddProp( work_phone, VCWorkProp );
1057 safeAddProp( work_phone, VCPagerProp );
1058
1059 url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() );
1060 safeAddProp( url, VCWorkProp );
1061
1062 VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() );
1063 safeAddProp( title, VCWorkProp );
1064
1065
1066 QStringList emails = c.emailList();
1067 emails.prepend( c.defaultEmail() );
1068 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) {
1069 VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it );
1070 safeAddProp( email, VCInternetProp );
1071 }
1072
1073 safeAddPropValue( vcard, VCNoteProp, c.notes() );
1074
1075 safeAddPropValue( vcard, VCBirthDateProp, c.birthday() );
1076
1077 if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) {
1078 VObject *org = safeAddProp( vcard, VCOrgProp );
1079 safeAddPropValue( org, VCOrgNameProp, c.company() );
1080 safeAddPropValue( org, VCOrgUnitProp, c.department() );
1081 safeAddPropValue( org, VCOrgUnit2Prop, c.office() );
1082 }
1083
1084 // some values we have to export as custom fields
1085 safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() );
1086 safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() );
1087 safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() );
1088
1089 safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() );
1090 safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() );
1091 safeAddPropValue( vcard, "X-Qtopia-Anniversary", c.anniversary() );
1092 safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() );
1093 safeAddPropValue( vcard, "X-Qtopia-Children", c.children() );
1094
1095 return vcard;
1096}
1097
1098
1099/*!
1100 \internal
1101*/
1102static OContact parseVObject( VObject *obj )
1103{
1104 OContact c;
1105
1106 VObjectIterator it;
1107 initPropIterator( &it, obj );
1108 while( moreIteration( &it ) ) {
1109 VObject *o = nextVObject( &it );
1110 QCString name = vObjectName( o );
1111 QCString value = vObjectStringZValue( o );
1112 if ( name == VCNameProp ) {
1113 VObjectIterator nit;
1114 initPropIterator( &nit, o );
1115 while( moreIteration( &nit ) ) {
1116 VObject *o = nextVObject( &nit );
1117 QCString name = vObjectTypeInfo( o );
1118 QString value = vObjectStringZValue( o );
1119 if ( name == VCNamePrefixesProp )
1120 c.setTitle( value );
1121 else if ( name == VCNameSuffixesProp )
1122 c.setSuffix( value );
1123 else if ( name == VCFamilyNameProp )
1124 c.setLastName( value );
1125 else if ( name == VCGivenNameProp )
1126 c.setFirstName( value );
1127 else if ( name == VCAdditionalNamesProp )
1128 c.setMiddleName( value );
1129 }
1130 }
1131 else if ( name == VCAdrProp ) {
1132 bool work = TRUE; // default address is work address
1133 QString street;
1134 QString city;
1135 QString region;
1136 QString postal;
1137 QString country;
1138
1139 VObjectIterator nit;
1140 initPropIterator( &nit, o );
1141 while( moreIteration( &nit ) ) {
1142 VObject *o = nextVObject( &nit );
1143 QCString name = vObjectName( o );
1144 QString value = vObjectStringZValue( o );
1145 if ( name == VCHomeProp )
1146 work = FALSE;
1147 else if ( name == VCWorkProp )
1148 work = TRUE;
1149 else if ( name == VCStreetAddressProp )
1150 street = value;
1151 else if ( name == VCCityProp )
1152 city = value;
1153 else if ( name == VCRegionProp )
1154 region = value;
1155 else if ( name == VCPostalCodeProp )
1156 postal = value;
1157 else if ( name == VCCountryNameProp )
1158 country = value;
1159 }
1160 if ( work ) {
1161 c.setBusinessStreet( street );
1162 c.setBusinessCity( city );
1163 c.setBusinessCountry( country );
1164 c.setBusinessZip( postal );
1165 c.setBusinessState( region );
1166 } else {
1167 c.setHomeStreet( street );
1168 c.setHomeCity( city );
1169 c.setHomeCountry( country );
1170 c.setHomeZip( postal );
1171 c.setHomeState( region );
1172 }
1173 }
1174 else if ( name == VCTelephoneProp ) {
1175 enum {
1176 HOME = 0x01,
1177 WORK = 0x02,
1178 VOICE = 0x04,
1179 CELL = 0x08,
1180 FAX = 0x10,
1181 PAGER = 0x20,
1182 UNKNOWN = 0x80
1183 };
1184 int type = 0;
1185
1186 VObjectIterator nit;
1187 initPropIterator( &nit, o );
1188 while( moreIteration( &nit ) ) {
1189 VObject *o = nextVObject( &nit );
1190 QCString name = vObjectTypeInfo( o );
1191 if ( name == VCHomeProp )
1192 type |= HOME;
1193 else if ( name == VCWorkProp )
1194 type |= WORK;
1195 else if ( name == VCVoiceProp )
1196 type |= VOICE;
1197 else if ( name == VCCellularProp )
1198 type |= CELL;
1199 else if ( name == VCFaxProp )
1200 type |= FAX;
1201 else if ( name == VCPagerProp )
1202 type |= PAGER;
1203 else if ( name == VCPreferredProp )
1204 ;
1205 else
1206 type |= UNKNOWN;
1207 }
1208 if ( (type & UNKNOWN) != UNKNOWN ) {
1209 if ( ( type & (HOME|WORK) ) == 0 ) // default
1210 type |= HOME;
1211 if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default
1212 type |= VOICE;
1213
1214 if ( (type & (VOICE|HOME) ) == (VOICE|HOME) )
1215 c.setHomePhone( value );
1216 if ( ( type & (FAX|HOME) ) == (FAX|HOME) )
1217 c.setHomeFax( value );
1218 if ( ( type & (CELL|HOME) ) == (CELL|HOME) )
1219 c.setHomeMobile( value );
1220 if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) )
1221 c.setBusinessPhone( value );
1222 if ( ( type & (FAX|WORK) ) == (FAX|WORK) )
1223 c.setBusinessFax( value );
1224 if ( ( type & (CELL|WORK) ) == (CELL|WORK) )
1225 c.setBusinessMobile( value );
1226 if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) )
1227 c.setBusinessPager( value );
1228 }
1229 }
1230 else if ( name == VCEmailAddressProp ) {
1231 QString email = vObjectStringZValue( o );
1232 bool valid = TRUE;
1233 VObjectIterator nit;
1234 initPropIterator( &nit, o );
1235 while( moreIteration( &nit ) ) {
1236 VObject *o = nextVObject( &nit );
1237 QCString name = vObjectTypeInfo( o );
1238 if ( name != VCInternetProp && name != VCHomeProp &&
1239 name != VCWorkProp &&
1240 name != VCPreferredProp )
1241 // ### preffered should map to default email
1242 valid = FALSE;
1243 }
1244 if ( valid ) {
1245 c.insertEmail( email );
1246 }
1247 }
1248 else if ( name == VCURLProp ) {
1249 VObjectIterator nit;
1250 initPropIterator( &nit, o );
1251 while( moreIteration( &nit ) ) {
1252 VObject *o = nextVObject( &nit );
1253 QCString name = vObjectTypeInfo( o );
1254 if ( name == VCHomeProp )
1255 c.setHomeWebpage( value );
1256 else if ( name == VCWorkProp )
1257 c.setBusinessWebpage( value );
1258 }
1259 }
1260 else if ( name == VCOrgProp ) {
1261 VObjectIterator nit;
1262 initPropIterator( &nit, o );
1263 while( moreIteration( &nit ) ) {
1264 VObject *o = nextVObject( &nit );
1265 QCString name = vObjectName( o );
1266 QString value = vObjectStringZValue( o );
1267 if ( name == VCOrgNameProp )
1268 c.setCompany( value );
1269 else if ( name == VCOrgUnitProp )
1270 c.setDepartment( value );
1271 else if ( name == VCOrgUnit2Prop )
1272 c.setOffice( value );
1273 }
1274 }
1275 else if ( name == VCTitleProp ) {
1276 c.setJobTitle( value );
1277 }
1278 else if ( name == "X-Qtopia-Profession" ) {
1279 c.setProfession( value );
1280 }
1281 else if ( name == "X-Qtopia-Manager" ) {
1282 c.setManager( value );
1283 }
1284 else if ( name == "X-Qtopia-Assistant" ) {
1285 c.setAssistant( value );
1286 }
1287 else if ( name == "X-Qtopia-Spouse" ) {
1288 c.setSpouse( value );
1289 }
1290 else if ( name == "X-Qtopia-Gender" ) {
1291 c.setGender( value );
1292 }
1293 else if ( name == "X-Qtopia-Anniversary" ) {
1294 c.setAnniversary( value );
1295 }
1296 else if ( name == "X-Qtopia-Nickname" ) {
1297 c.setNickname( value );
1298 }
1299 else if ( name == "X-Qtopia-Children" ) {
1300 c.setChildren( value );
1301 }
1302
1303
1304#if 0
1305 else {
1306 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
1307 VObjectIterator nit;
1308 initPropIterator( &nit, o );
1309 while( moreIteration( &nit ) ) {
1310 VObject *o = nextVObject( &nit );
1311 QCString name = vObjectName( o );
1312 QString value = vObjectStringZValue( o );
1313 printf(" subprop: %s = %s\n", name.data(), value.latin1() );
1314 }
1315 }
1316#endif
1317 }
1318 c.setFileAs();
1319 return c;
1320}
1321
1322/*!
1323 Writes the list of \a contacts as a set of VCards to the file \a filename.
1324*/
1325void OContact::writeVCard( const QString &filename, const QValueList<OContact> &contacts)
1326{
1327 QFileDirect f( filename.utf8().data() );
1328 if ( !f.open( IO_WriteOnly ) ) {
1329 qWarning("Unable to open vcard write");
1330 return;
1331 }
1332
1333 QValueList<OContact>::ConstIterator it;
1334 for( it = contacts.begin(); it != contacts.end(); ++it ) {
1335 VObject *obj = createVObject( *it );
1336 writeVObject(f.directHandle() , obj );
1337 cleanVObject( obj );
1338 }
1339 cleanStrTbl();
1340}
1341
1342/*!
1343 writes \a contact as a VCard to the file \a filename.
1344*/
1345void OContact::writeVCard( const QString &filename, const OContact &contact)
1346{
1347 QFileDirect f( filename.utf8().data() );
1348 if ( !f.open( IO_WriteOnly ) ) {
1349 qWarning("Unable to open vcard write");
1350 return;
1351 }
1352
1353 VObject *obj = createVObject( contact );
1354 writeVObject( f.directHandle() , obj );
1355 cleanVObject( obj );
1356
1357 cleanStrTbl();
1358}
1359
1360/*!
1361 Returns the set of contacts read as VCards from the file \a filename.
1362*/
1363QValueList<OContact> OContact::readVCard( const QString &filename )
1364{
1365 qDebug("trying to open %s, exists=%d", filename.utf8().data(), QFileInfo( filename.utf8().data() ).size() );
1366 VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() );
1367
1368 qDebug("vobject = %p", obj );
1369
1370 QValueList<OContact> contacts;
1371
1372 while ( obj ) {
1373 contacts.append( parseVObject( obj ) );
1374
1375 VObject *t = obj;
1376 obj = nextVObjectInList(obj);
1377 cleanVObject( t );
1378 }
1379
1380 return contacts;
1381}
1382
1383/*!
1384 Returns TRUE if the contact matches the regular expression \a regexp.
1385 Otherwise returns FALSE.
1386*/
1387bool OContact::match( const QString &regexp ) const
1388{
1389 return match(QRegExp(regexp));
1390}
1391
1392/*!
1393 \overload
1394 Returns TRUE if the contact matches the regular expression \a regexp.
1395 Otherwise returns FALSE.
1396*/
1397bool OContact::match( const QRegExp &r ) const
1398{
1399 bool match;
1400 match = false;
1401 QMap<int, QString>::ConstIterator it;
1402 for ( it = mMap.begin(); it != mMap.end(); ++it ) {
1403 if ( (*it).find( r ) > -1 ) {
1404 match = true;
1405 break;
1406 }
1407 }
1408 return match;
1409}
1410
1411
1412// Noch nicht definiert ! :SX
1413QString OContact::toShortText() const
1414{
1415 return ( QString::fromLatin1( "Not defined!") );
1416}
1417QString OContact::type() const
1418{
1419 return QString::fromLatin1( "OContact" );
1420}
1421
1422// Noch nicht definiert ! :SX
1423QMap<QString,QString> OContact::toExtraMap() const
1424{
1425 QMap <QString,QString> useless;
1426 return useless;
1427}
1428
1429// Noch nicht definiert ! :SX
1430class QString OContact::recordField(int) const
1431{
1432 return QString::fromLatin1( "Noch nicht implementiert !" );
1433}
diff --git a/libopie2/opiepim/ocontact.h b/libopie2/opiepim/ocontact.h
new file mode 100644
index 0000000..e0555c8
--- a/dev/null
+++ b/libopie2/opiepim/ocontact.h
@@ -0,0 +1,311 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#ifndef __OCONTACT_H__
22#define __OCONTACT_H__
23
24#include <opie/opimrecord.h>
25#include <qpe/recordfields.h>
26
27#include <qstringlist.h>
28
29#if defined(QPC_TEMPLATEDLL)
30// MOC_SKIP_BEGIN
31QPC_TEMPLATEEXTERN template class QPC_EXPORT QMap<int, QString>;
32// MOC_SKIP_END
33#endif
34
35class ContactPrivate; // Wozu ist das gut und wo ist das decrariert ? (se)
36class QPC_EXPORT OContact : public OPimRecord
37{
38 friend class DataSet;
39public:
40 OContact();
41 OContact( const QMap<int, QString> &fromMap );
42 virtual ~OContact();
43
44 static void writeVCard( const QString &filename, const QValueList<OContact> &contacts);
45 static void writeVCard( const QString &filename, const OContact &c );
46 static QValueList<OContact> readVCard( const QString &filename );
47
48 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE };
49
50 void setTitle( const QString &v ) { replace( Qtopia::Title, v ); }
51 void setFirstName( const QString &v ) { replace( Qtopia::FirstName, v ); }
52 void setMiddleName( const QString &v ) { replace( Qtopia::MiddleName, v ); }
53 void setLastName( const QString &v ) { replace( Qtopia::LastName, v ); }
54 void setSuffix( const QString &v ) { replace( Qtopia::Suffix, v ); }
55 void setFileAs( const QString &v ) { replace( Qtopia::FileAs, v ); }
56 void setFileAs();
57
58 // default email address
59 void setDefaultEmail( const QString &v );
60 // inserts email to list and ensure's doesn't already exist
61 void insertEmail( const QString &v );
62 void removeEmail( const QString &v );
63 void clearEmails();
64 void insertEmails( const QStringList &v );
65
66 // home
67 void setHomeStreet( const QString &v ) { replace( Qtopia::HomeStreet, v ); }
68 void setHomeCity( const QString &v ) { replace( Qtopia::HomeCity, v ); }
69 void setHomeState( const QString &v ) { replace( Qtopia::HomeState, v ); }
70 void setHomeZip( const QString &v ) { replace( Qtopia::HomeZip, v ); }
71 void setHomeCountry( const QString &v ) { replace( Qtopia::HomeCountry, v ); }
72 void setHomePhone( const QString &v ) { replace( Qtopia::HomePhone, v ); }
73 void setHomeFax( const QString &v ) { replace( Qtopia::HomeFax, v ); }
74 void setHomeMobile( const QString &v ) { replace( Qtopia::HomeMobile, v ); }
75 void setHomeWebpage( const QString &v ) { replace( Qtopia::HomeWebPage, v ); }
76
77 // business
78 void setCompany( const QString &v ) { replace( Qtopia::Company, v ); }
79 void setBusinessStreet( const QString &v ) { replace( Qtopia::BusinessStreet, v ); }
80 void setBusinessCity( const QString &v ) { replace( Qtopia::BusinessCity, v ); }
81 void setBusinessState( const QString &v ) { replace( Qtopia::BusinessState, v ); }
82 void setBusinessZip( const QString &v ) { replace( Qtopia::BusinessZip, v ); }
83 void setBusinessCountry( const QString &v ) { replace( Qtopia::BusinessCountry, v ); }
84 void setBusinessWebpage( const QString &v ) { replace( Qtopia::BusinessWebPage, v ); }
85 void setJobTitle( const QString &v ) { replace( Qtopia::JobTitle, v ); }
86 void setDepartment( const QString &v ) { replace( Qtopia::Department, v ); }
87 void setOffice( const QString &v ) { replace( Qtopia::Office, v ); }
88 void setBusinessPhone( const QString &v ) { replace( Qtopia::BusinessPhone, v ); }
89 void setBusinessFax( const QString &v ) { replace( Qtopia::BusinessFax, v ); }
90 void setBusinessMobile( const QString &v ) { replace( Qtopia::BusinessMobile, v ); }
91 void setBusinessPager( const QString &v ) { replace( Qtopia::BusinessPager, v ); }
92 void setProfession( const QString &v ) { replace( Qtopia::Profession, v ); }
93 void setAssistant( const QString &v ) { replace( Qtopia::Assistant, v ); }
94 void setManager( const QString &v ) { replace( Qtopia::Manager, v ); }
95
96 // personal
97 void setSpouse( const QString &v ) { replace( Qtopia::Spouse, v ); }
98 void setGender( const QString &v ) { replace( Qtopia::Gender, v ); }
99 void setBirthday( const QString &v ) { replace( Qtopia::Birthday, v ); }
100 void setAnniversary( const QString &v ) { replace( Qtopia::Anniversary, v ); }
101 void setNickname( const QString &v ) { replace( Qtopia::Nickname, v ); }
102 void setChildren( const QString &v );
103
104 // other
105 void setNotes( const QString &v ) { replace( Qtopia::Notes, v); }
106
107 bool match( const QString &regexp ) const;
108
109// DON'T ATTEMPT TO USE THIS
110#ifdef QTOPIA_INTERNAL_CONTACT_MRE
111 bool match( const QRegExp &regexp ) const;
112#endif
113
114// // custom
115// void setCustomField( const QString &key, const QString &v )
116// { replace(Custom- + key, v ); }
117
118 // name
119 QString fullName() const;
120 QString title() const { return find( Qtopia::Title ); }
121 QString firstName() const { return find( Qtopia::FirstName ); }
122 QString middleName() const { return find( Qtopia::MiddleName ); }
123 QString lastName() const { return find( Qtopia::LastName ); }
124 QString suffix() const { return find( Qtopia::Suffix ); }
125 QString fileAs() const { return find( Qtopia::FileAs ); }
126
127 // email
128 QString defaultEmail() const { return find( Qtopia::DefaultEmail ); }
129 QStringList emailList() const;
130
131 // home
132 QString homeStreet() const { return find( Qtopia::HomeStreet ); }
133 QString homeCity() const { return find( Qtopia::HomeCity ); }
134 QString homeState() const { return find( Qtopia::HomeState ); }
135 QString homeZip() const { return find( Qtopia::HomeZip ); }
136 QString homeCountry() const { return find( Qtopia::HomeCountry ); }
137 QString homePhone() const { return find( Qtopia::HomePhone ); }
138 QString homeFax() const { return find( Qtopia::HomeFax ); }
139 QString homeMobile() const { return find( Qtopia::HomeMobile ); }
140 QString homeWebpage() const { return find( Qtopia::HomeWebPage ); }
141 /** Multi line string containing all non-empty address info in the form
142 * Street
143 * City, State Zip
144 * Country
145 */
146 QString displayHomeAddress() const;
147
148 // business
149 QString company() const { return find( Qtopia::Company ); }
150 QString businessStreet() const { return find( Qtopia::BusinessStreet ); }
151 QString businessCity() const { return find( Qtopia::BusinessCity ); }
152 QString businessState() const { return find( Qtopia::BusinessState ); }
153 QString businessZip() const { return find( Qtopia::BusinessZip ); }
154 QString businessCountry() const { return find( Qtopia::BusinessCountry ); }
155 QString businessWebpage() const { return find( Qtopia::BusinessWebPage ); }
156 QString jobTitle() const { return find( Qtopia::JobTitle ); }
157 QString department() const { return find( Qtopia::Department ); }
158 QString office() const { return find( Qtopia::Office ); }
159 QString businessPhone() const { return find( Qtopia::BusinessPhone ); }
160 QString businessFax() const { return find( Qtopia::BusinessFax ); }
161 QString businessMobile() const { return find( Qtopia::BusinessMobile ); }
162 QString businessPager() const { return find( Qtopia::BusinessPager ); }
163 QString profession() const { return find( Qtopia::Profession ); }
164 QString assistant() const { return find( Qtopia::Assistant ); }
165 QString manager() const { return find( Qtopia::Manager ); }
166 /** Multi line string containing all non-empty address info in the form
167 * Street
168 * City, State Zip
169 * Country
170 */
171 QString displayBusinessAddress() const;
172
173 //personal
174 QString spouse() const { return find( Qtopia::Spouse ); }
175 QString gender() const { return find( Qtopia::Gender ); }
176 QString birthday() const { return find( Qtopia::Birthday ); }
177 QString anniversary() const { return find( Qtopia::Anniversary ); }
178 QString nickname() const { return find( Qtopia::Nickname ); }
179 QString children() const { return find( Qtopia::Children ); }
180 QStringList childrenList() const;
181
182 // other
183 QString notes() const { return find( Qtopia::Notes ); }
184 QString groups() const { return find( Qtopia::Groups ); }
185 QStringList groupList() const;
186
187// // custom
188// const QString &customField( const QString &key )
189// { return find( Custom- + key ); }
190
191 static QStringList fields();
192 static QStringList trfields();
193
194 QString toRichText() const;
195 QMap<int, QString> toMap() const;
196 QString field( int key ) const { return find( key ); }
197
198
199 // journaling...
200 void saveJournal( journal_action action, const QString &key = QString::null );
201 void save( QString &buf ) const;
202
203 void setUid( int i )
204{ Record::setUid(i); replace( Qtopia::AddressUid , QString::number(i)); }
205
206 QString toShortText()const;
207 QString OContact::type()const;
208 QMap<QString,QString> OContact::toExtraMap() const;
209 class QString OContact::recordField(int) const;
210
211private:
212 friend class AbEditor;
213 friend class AbTable;
214 friend class AddressBookAccessPrivate;
215 friend class XMLIO;
216
217 QString emailSeparator() const { return " "; }
218 // the emails should be seperated by a comma
219 void setEmails( const QString &v );
220 QString emails() const { return find( Qtopia::Emails ); }
221
222 void insert( int key, const QString &value );
223 void replace( int key, const QString &value );
224 QString find( int key ) const;
225
226 QString displayAddress( const QString &street,
227 const QString &city,
228 const QString &state,
229 const QString &zip,
230 const QString &country ) const;
231
232 Qtopia::UidGen &uidGen() { return sUidGen; }
233 static Qtopia::UidGen sUidGen;
234 QMap<int, QString> mMap;
235 ContactPrivate *d;
236};
237
238// these methods are inlined to keep binary compatability with Qtopia 1.5
239inline void OContact::insertEmail( const QString &v )
240{
241 //qDebug("insertEmail %s", v.latin1());
242 QString e = v.simplifyWhiteSpace();
243 QString def = defaultEmail();
244
245 // if no default, set it as the default email and don't insert
246 if ( def.isEmpty() ) {
247 setDefaultEmail( e ); // will insert into the list for us
248 return;
249 }
250
251 // otherwise, insert assuming doesn't already exist
252 QString emailsStr = find( Qtopia::Emails );
253 if ( emailsStr.contains( e ))
254 return;
255 if ( !emailsStr.isEmpty() )
256 emailsStr += emailSeparator();
257 emailsStr += e;
258 replace( Qtopia::Emails, emailsStr );
259}
260
261inline void OContact::removeEmail( const QString &v )
262{
263 QString e = v.simplifyWhiteSpace();
264 QString def = defaultEmail();
265 QString emailsStr = find( Qtopia::Emails );
266 QStringList emails = emailList();
267
268 // otherwise, must first contain it
269 if ( !emailsStr.contains( e ) )
270 return;
271
272 // remove it
273 //qDebug(" removing email from list %s", e.latin1());
274 emails.remove( e );
275 // reset the string
276 emailsStr = emails.join(emailSeparator()); // Sharp's brain dead separator
277 replace( Qtopia::Emails, emailsStr );
278
279 // if default, then replace the default email with the first one
280 if ( def == e ) {
281 //qDebug("removeEmail is default; setting new default");
282 if ( !emails.count() )
283 clearEmails();
284 else // setDefaultEmail will remove e from the list
285 setDefaultEmail( emails.first() );
286 }
287}
288inline void OContact::clearEmails()
289{
290 mMap.remove( Qtopia::DefaultEmail );
291 mMap.remove( Qtopia::Emails );
292}
293inline void OContact::setDefaultEmail( const QString &v )
294{
295 QString e = v.simplifyWhiteSpace();
296
297 //qDebug("OContact::setDefaultEmail %s", e.latin1());
298 replace( Qtopia::DefaultEmail, e );
299
300 if ( !e.isEmpty() )
301 insertEmail( e );
302
303}
304
305inline void OContact::insertEmails( const QStringList &v )
306{
307 for ( QStringList::ConstIterator it = v.begin(); it != v.end(); ++it )
308 insertEmail( *it );
309}
310
311#endif