addressee.src.cpp

00001 /*
00002     This file is part of libkabc.
00003     Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
00004     Copyright (c) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
00005     Copyright (c) 2005 Ingo Kloecker <kloecker@kde.org>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020     Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include <qregexp.h>
00024 
00025 #include <ksharedptr.h>
00026 #include <kdebug.h>
00027 #include <kapplication.h>
00028 #include <klocale.h>
00029 
00030 #include "addresseehelper.h"
00031 #include "field.h"
00032 #include "resource.h"
00033 #include "sortmode.h"
00034 
00035 #include "addressee.h"
00036 
00037 using namespace KABC;
00038 
00039 static bool matchBinaryPattern( int value, int pattern );
00040 
00041 template <class L>
00042 static bool listEquals( const QValueList<L>&, const QValueList<L>& );
00043 static bool emailsEquals( const QStringList&, const QStringList& );
00044 
00045 KABC::SortMode *Addressee::mSortMode = 0;
00046 
00047 struct Addressee::AddresseeData : public KShared
00048 {
00049   QString uid;
00050   --VARIABLES--
00051 
00052   PhoneNumber::List phoneNumbers;
00053   Address::List addresses;
00054   Key::List keys;
00055   QStringList emails;
00056   QStringList categories;
00057   QStringList custom;
00058 
00059   Resource *resource;
00060 
00061   bool empty    :1;
00062   bool changed  :1;
00063 };
00064 
00065 Addressee::AddresseeData* Addressee::shared_null = 0;
00066 
00067 Addressee::AddresseeData* Addressee::makeSharedNull()
00068 {
00069   Addressee::shared_null = new AddresseeData;
00070   shared_null->_KShared_ref(); //just in case (we should add KSD)
00071   shared_null->empty = true;
00072   shared_null->changed = false;
00073   shared_null->resource = 0;
00074   return shared_null;
00075 }
00076 
00077 Addressee::Addressee()
00078 {
00079   mData = shared_null ? shared_null : makeSharedNull();
00080 }
00081 
00082 Addressee::~Addressee()
00083 {
00084 }
00085 
00086 Addressee::Addressee( const Addressee &a )
00087 {
00088   mData = a.mData;
00089 }
00090 
00091 Addressee &Addressee::operator=( const Addressee &a )
00092 {
00093   if ( this == &a )
00094     return (*this);
00095 
00096   mData = a.mData;
00097   return (*this);
00098 }
00099 
00100 void Addressee::detach()
00101 {
00102   if ( mData.data() == shared_null ) {
00103     mData = new AddresseeData;
00104     mData->empty = true;
00105     mData->changed = false;
00106     mData->resource = 0;
00107     mData->uid = KApplication::randomString( 10 );
00108     return;
00109   } else if ( mData.count() == 1 ) return;
00110 
00111   AddresseeData data = *mData;
00112   mData = new AddresseeData( data );
00113 }
00114 
00115 bool Addressee::operator==( const Addressee &a ) const
00116 {
00117   if ( uid() != a.uid() ) {
00118     kdDebug(5700) << "uid differs" << endl;
00119     return false;
00120   }
00121   --EQUALSTEST--
00122   if ( ( mData->url.isValid() || a.mData->url.isValid() ) &&
00123        ( mData->url != a.mData->url ) ) {
00124     kdDebug(5700) << "url differs" << endl;
00125     return false;
00126   }
00127   if ( !listEquals( mData->phoneNumbers, a.mData->phoneNumbers ) ) {
00128     kdDebug(5700) << "phoneNumbers differs" << endl;
00129     return false;
00130   }
00131   if ( !listEquals( mData->addresses, a.mData->addresses ) ) {
00132     kdDebug(5700) << "addresses differs" << endl;
00133     return false;
00134   }
00135   if ( !listEquals( mData->keys, a.mData->keys ) ) {
00136     kdDebug(5700) << "keys differs" << endl;
00137     return false;
00138   }
00139   if ( !emailsEquals( mData->emails, a.mData->emails ) ) {
00140     kdDebug(5700) << "emails differs" << endl;
00141     return false;
00142   }
00143   if ( !listEquals( mData->categories, a.mData->categories ) ) {
00144     kdDebug(5700) << "categories differs" << endl;
00145     return false;
00146   }
00147   if ( !listEquals( mData->custom, a.mData->custom ) ) {
00148     kdDebug(5700) << "custom differs" << endl;
00149     return false;
00150   }
00151 
00152   return true;
00153 }
00154 
00155 bool Addressee::operator!=( const Addressee &a ) const
00156 {
00157   return !( a == *this );
00158 }
00159 
00160 bool Addressee::isEmpty() const
00161 {
00162   return mData->empty;
00163 }
00164 
00165 void Addressee::setUid( const QString &id )
00166 {
00167   if ( id == mData->uid ) return;
00168   detach();
00169   mData->empty = false;
00170   mData->uid = id;
00171 }
00172 
00173 QString Addressee::uid() const
00174 {
00175   return mData->uid;
00176 }
00177 
00178 QString Addressee::uidLabel()
00179 {
00180   return i18n("Unique Identifier");
00181 }
00182 
00183 --DEFINITIONS--
00184 
00185 void Addressee::setNameFromString( const QString &s )
00186 {
00187   QString str = s;
00188   //remove enclosing quotes from string
00189   if ( str.length() > 1  && s[ 0 ] == '"' && s[ s.length() - 1 ] == '"' )
00190     str = s.mid( 1, s.length() - 2 );
00191 
00192   setFormattedName( str );
00193   setName( str );
00194 
00195   // clear all name parts
00196   setPrefix( QString::null );
00197   setGivenName( QString::null );
00198   setAdditionalName( QString::null );
00199   setFamilyName( QString::null );
00200   setSuffix( QString::null );
00201 
00202   if ( str.isEmpty() )
00203     return;
00204 
00205   QString spaceStr = " ";
00206   QString emptyStr = "";
00207   AddresseeHelper *helper = AddresseeHelper::self();
00208 
00209   int i = str.find( ',' );
00210   if( i < 0 ) {
00211     QStringList parts = QStringList::split( spaceStr, str );
00212     int leftOffset = 0;
00213     int rightOffset = parts.count() - 1;
00214 
00215     QString suffix;
00216     while ( rightOffset >= 0 ) {
00217       if ( helper->containsSuffix( parts[ rightOffset ] ) ) {
00218         suffix.prepend(parts[ rightOffset ] + (suffix.isEmpty() ? emptyStr : spaceStr));
00219         rightOffset--;
00220       } else
00221         break;
00222     }
00223     setSuffix( suffix );
00224 
00225     if ( rightOffset < 0 )
00226       return;
00227 
00228     QStringList inclusionList;
00229     for ( int n = 1; (rightOffset - n >= 0) && (n < 4); ++n ) {
00230       if ( helper->containsPrefix( parts[ rightOffset - n ].lower() ) ) {
00231         inclusionList.prepend( parts[ rightOffset - n ] );
00232       } else
00233         break;
00234     }
00235 
00236     if ( !inclusionList.isEmpty() ) {
00237       setFamilyName( inclusionList.join( " " ) + spaceStr + parts[ rightOffset ] );
00238       rightOffset -= inclusionList.count();
00239     } else {
00240       if ( helper->tradeAsFamilyName() )
00241         setFamilyName( parts[ rightOffset ] );
00242       else
00243         setGivenName( parts[ rightOffset ] );
00244     }
00245 
00246     QString prefix;
00247     while ( leftOffset < rightOffset ) {
00248       if ( helper->containsTitle( parts[ leftOffset ] ) ) {
00249         prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00250         leftOffset++;
00251       } else
00252         break;
00253     }
00254     setPrefix( prefix );
00255 
00256     if ( leftOffset < rightOffset ) {
00257       setGivenName( parts[ leftOffset ] );
00258       leftOffset++;
00259     }
00260 
00261     QString additionalName;
00262     while ( leftOffset < rightOffset ) {
00263       additionalName.append( ( additionalName.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00264       leftOffset++;
00265     }
00266     setAdditionalName( additionalName );
00267   } else {
00268     QString part1 = str.left( i );
00269     QString part2 = str.mid( i + 1 );
00270 
00271     QStringList parts = QStringList::split( spaceStr, part1 );
00272     int leftOffset = 0;
00273     int rightOffset = parts.count() - 1;
00274 
00275     if ( parts.count() > 0 ) {
00276 
00277       QString suffix;
00278       while ( rightOffset >= 0 ) {
00279         if ( helper->containsSuffix( parts[ rightOffset ] ) ) {
00280           suffix.prepend(parts[ rightOffset ] + (suffix.isEmpty() ? emptyStr : spaceStr));
00281           rightOffset--;
00282         } else
00283           break;
00284       }
00285       setSuffix( suffix );
00286 
00287       if ( rightOffset - 1 >= 0 && helper->containsPrefix( parts[ rightOffset - 1 ].lower() ) ) {
00288         setFamilyName( parts[ rightOffset - 1 ] + spaceStr + parts[ rightOffset ] );
00289         rightOffset--;
00290       } else
00291         setFamilyName( parts[ rightOffset ] );
00292 
00293       QString prefix;
00294       while ( leftOffset < rightOffset ) {
00295         if ( helper->containsTitle( parts[ leftOffset ] ) ) {
00296           prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00297           leftOffset++;
00298         } else
00299           break;
00300       }
00301     } else {
00302       setPrefix( "" );
00303       setFamilyName( "" );
00304       setSuffix( "" );
00305     }
00306 
00307     parts = QStringList::split( spaceStr, part2 );
00308 
00309     leftOffset = 0;
00310     rightOffset = parts.count();
00311 
00312     if ( parts.count() > 0 ) {
00313 
00314       QString prefix;
00315       while ( leftOffset < rightOffset ) {
00316         if ( helper->containsTitle( parts[ leftOffset ] ) ) {
00317           prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00318           leftOffset++;
00319         } else
00320           break;
00321       }
00322       setPrefix( prefix );
00323 
00324       if ( leftOffset < rightOffset ) {
00325         setGivenName( parts[ leftOffset ] );
00326         leftOffset++;
00327       }
00328 
00329       QString additionalName;
00330       while ( leftOffset < rightOffset ) {
00331         additionalName.append( ( additionalName.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00332         leftOffset++;
00333       }
00334       setAdditionalName( additionalName );
00335     } else {
00336       setGivenName( "" );
00337       setAdditionalName( "" );
00338     }
00339   }
00340 }
00341 
00342 QString Addressee::realName() const
00343 {
00344   QString n( formattedName() );
00345   if ( !n.isEmpty() )
00346     return n;
00347 
00348   n = assembledName();
00349   if ( !n.isEmpty() )
00350     return n;
00351 
00352   n = name();
00353   if ( !n.isEmpty() )
00354     return n;
00355 
00356   return organization();
00357 }
00358 
00359 QString Addressee::assembledName() const
00360 {
00361   QString name = prefix() + " " + givenName() + " " + additionalName() + " " +
00362               familyName() + " " + suffix();
00363 
00364   return name.simplifyWhiteSpace();
00365 }
00366 
00367 QString Addressee::fullEmail( const QString &email ) const
00368 {
00369   QString e;
00370   if ( email.isNull() ) {
00371     e = preferredEmail();
00372   } else {
00373     e = email;
00374   }
00375   if ( e.isEmpty() ) return QString::null;
00376 
00377   QString text;
00378   if ( realName().isEmpty() )
00379     text = e;
00380   else {
00381     QRegExp needQuotes( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" );
00382     if ( realName().find( needQuotes ) != -1 )
00383       text = "\"" + realName() + "\" <" + e + ">";
00384     else
00385       text = realName() + " <" + e + ">";
00386   }
00387 
00388   return text;
00389 }
00390 
00391 void Addressee::insertEmail( const QString &email, bool preferred )
00392 {
00393   if ( email.simplifyWhiteSpace().isEmpty() )
00394     return;
00395 
00396   detach();
00397   mData->empty = false;
00398 
00399   QStringList::Iterator it = mData->emails.find( email );
00400 
00401   if ( it != mData->emails.end() ) {
00402     if ( !preferred || it == mData->emails.begin() ) return;
00403     mData->emails.remove( it );
00404     mData->emails.prepend( email );
00405   } else {
00406     if ( preferred ) {
00407       mData->emails.prepend( email );
00408     } else {
00409       mData->emails.append( email );
00410     }
00411   }
00412 }
00413 
00414 void Addressee::removeEmail( const QString &email )
00415 {
00416   detach();
00417 
00418   QStringList::Iterator it = mData->emails.find( email );
00419   if ( it == mData->emails.end() ) return;
00420 
00421   mData->emails.remove( it );
00422 }
00423 
00424 QString Addressee::preferredEmail() const
00425 {
00426   if ( mData->emails.count() == 0 ) return QString::null;
00427   else return mData->emails.first();
00428 }
00429 
00430 QStringList Addressee::emails() const
00431 {
00432   return mData->emails;
00433 }
00434 void Addressee::setEmails( const QStringList& emails ) {
00435   detach();
00436 
00437   mData->emails = emails;
00438 }
00439 void Addressee::insertPhoneNumber( const PhoneNumber &phoneNumber )
00440 {
00441   detach();
00442   mData->empty = false;
00443 
00444   PhoneNumber::List::Iterator it;
00445   for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00446     if ( (*it).id() == phoneNumber.id() ) {
00447       *it = phoneNumber;
00448       return;
00449     }
00450   }
00451   if ( !phoneNumber.number().simplifyWhiteSpace().isEmpty() )
00452     mData->phoneNumbers.append( phoneNumber );
00453 }
00454 
00455 void Addressee::removePhoneNumber( const PhoneNumber &phoneNumber )
00456 {
00457   detach();
00458 
00459   PhoneNumber::List::Iterator it;
00460   for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00461     if ( (*it).id() == phoneNumber.id() ) {
00462       mData->phoneNumbers.remove( it );
00463       return;
00464     }
00465   }
00466 }
00467 
00468 PhoneNumber Addressee::phoneNumber( int type ) const
00469 {
00470   PhoneNumber phoneNumber( "", type );
00471   PhoneNumber::List::ConstIterator it;
00472   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00473     if ( matchBinaryPattern( (*it).type(), type ) ) {
00474       if ( (*it).type() & PhoneNumber::Pref )
00475         return (*it);
00476       else if ( phoneNumber.number().isEmpty() )
00477         phoneNumber = (*it);
00478     }
00479   }
00480 
00481   return phoneNumber;
00482 }
00483 
00484 PhoneNumber::List Addressee::phoneNumbers() const
00485 {
00486   return mData->phoneNumbers;
00487 }
00488 
00489 PhoneNumber::List Addressee::phoneNumbers( int type ) const
00490 {
00491   PhoneNumber::List list;
00492 
00493   PhoneNumber::List::ConstIterator it;
00494   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00495     if ( matchBinaryPattern( (*it).type(), type ) ) {
00496       list.append( *it );
00497     }
00498   }
00499   return list;
00500 }
00501 
00502 PhoneNumber Addressee::findPhoneNumber( const QString &id ) const
00503 {
00504   PhoneNumber::List::ConstIterator it;
00505   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00506     if ( (*it).id() == id ) {
00507       return *it;
00508     }
00509   }
00510   return PhoneNumber();
00511 }
00512 
00513 void Addressee::insertKey( const Key &key )
00514 {
00515   detach();
00516   mData->empty = false;
00517 
00518   Key::List::Iterator it;
00519   for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00520     if ( (*it).id() == key.id() ) {
00521       *it = key;
00522       return;
00523     }
00524   }
00525   mData->keys.append( key );
00526 }
00527 
00528 void Addressee::removeKey( const Key &key )
00529 {
00530   detach();
00531 
00532   Key::List::Iterator it;
00533   for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00534     if ( (*it).id() == key.id() ) {
00535       mData->keys.remove( key );
00536       return;
00537     }
00538   }
00539 }
00540 
00541 Key Addressee::key( int type, QString customTypeString ) const
00542 {
00543   Key::List::ConstIterator it;
00544   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00545     if ( (*it).type() == type ) {
00546       if ( type == Key::Custom ) {
00547         if ( customTypeString.isEmpty() ) {
00548           return *it;
00549         } else {
00550           if ( (*it).customTypeString() == customTypeString )
00551             return (*it);
00552         }
00553       } else {
00554         return *it;
00555       }
00556     }
00557   }
00558   return Key( QString(), type );
00559 }
00560 
00561 void Addressee::setKeys( const Key::List& list )
00562 {
00563   detach();
00564   mData->keys = list;
00565 }
00566 
00567 Key::List Addressee::keys() const
00568 {
00569   return mData->keys;
00570 }
00571 
00572 Key::List Addressee::keys( int type, QString customTypeString ) const
00573 {
00574   Key::List list;
00575 
00576   Key::List::ConstIterator it;
00577   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00578     if ( (*it).type() == type ) {
00579       if ( type == Key::Custom ) {
00580         if ( customTypeString.isEmpty() ) {
00581           list.append( *it );
00582         } else {
00583           if ( (*it).customTypeString() == customTypeString )
00584             list.append( *it );
00585         }
00586       } else {
00587         list.append( *it );
00588       }
00589     }
00590   }
00591   return list;
00592 }
00593 
00594 Key Addressee::findKey( const QString &id ) const
00595 {
00596   Key::List::ConstIterator it;
00597   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00598     if ( (*it).id() == id ) {
00599       return *it;
00600     }
00601   }
00602   return Key();
00603 }
00604 
00605 QString Addressee::asString() const
00606 {
00607   return "Smith, agent Smith...";
00608 }
00609 
00610 void Addressee::dump() const
00611 {
00612   kdDebug(5700) << "Addressee {" << endl;
00613 
00614   kdDebug(5700) << "  Uid: '" << uid() << "'" << endl;
00615 
00616   --DEBUG--
00617 
00618   kdDebug(5700) << "  Emails {" << endl;
00619   const QStringList e = emails();
00620   QStringList::ConstIterator it;
00621   for( it = e.begin(); it != e.end(); ++it ) {
00622     kdDebug(5700) << "    " << (*it) << endl;
00623   }
00624   kdDebug(5700) << "  }" << endl;
00625 
00626   kdDebug(5700) << "  PhoneNumbers {" << endl;
00627   const PhoneNumber::List p = phoneNumbers();
00628   PhoneNumber::List::ConstIterator it2;
00629   for( it2 = p.begin(); it2 != p.end(); ++it2 ) {
00630     kdDebug(5700) << "    Type: " << int((*it2).type()) << " Number: " << (*it2).number() << endl;
00631   }
00632   kdDebug(5700) << "  }" << endl;
00633 
00634   const Address::List a = addresses();
00635   Address::List::ConstIterator it3;
00636   for( it3 = a.begin(); it3 != a.end(); ++it3 ) {
00637     (*it3).dump();
00638   }
00639 
00640   kdDebug(5700) << "  Keys {" << endl;
00641   const Key::List k = keys();
00642   Key::List::ConstIterator it4;
00643   for( it4 = k.begin(); it4 != k.end(); ++it4 ) {
00644     kdDebug(5700) << "    Type: " << int((*it4).type()) <<
00645                      " Key: " << (*it4).textData() <<
00646                      " CustomString: " << (*it4).customTypeString() << endl;
00647   }
00648   kdDebug(5700) << "  }" << endl;
00649 
00650   kdDebug(5700) << "}" << endl;
00651 }
00652 
00653 
00654 void Addressee::insertAddress( const Address &address )
00655 {
00656   if ( address.isEmpty() )
00657     return;
00658 
00659   detach();
00660   mData->empty = false;
00661 
00662   Address::List::Iterator it;
00663   for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00664     if ( (*it).id() == address.id() ) {
00665       *it = address;
00666       return;
00667     }
00668   }
00669 
00670   mData->addresses.append( address );
00671 }
00672 
00673 void Addressee::removeAddress( const Address &address )
00674 {
00675   detach();
00676 
00677   Address::List::Iterator it;
00678   for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00679     if ( (*it).id() == address.id() ) {
00680       mData->addresses.remove( it );
00681       return;
00682     }
00683   }
00684 }
00685 
00686 Address Addressee::address( int type ) const
00687 {
00688   Address address( type );
00689   Address::List::ConstIterator it;
00690   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00691     if ( matchBinaryPattern( (*it).type(), type ) ) {
00692       if ( (*it).type() & Address::Pref )
00693         return (*it);
00694       else if ( address.isEmpty() )
00695         address = (*it);
00696     }
00697   }
00698 
00699   return address;
00700 }
00701 
00702 Address::List Addressee::addresses() const
00703 {
00704   return mData->addresses;
00705 }
00706 
00707 Address::List Addressee::addresses( int type ) const
00708 {
00709   Address::List list;
00710 
00711   Address::List::ConstIterator it;
00712   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00713     if ( matchBinaryPattern( (*it).type(), type ) ) {
00714       list.append( *it );
00715     }
00716   }
00717 
00718   return list;
00719 }
00720 
00721 Address Addressee::findAddress( const QString &id ) const
00722 {
00723   Address::List::ConstIterator it;
00724   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00725     if ( (*it).id() == id ) {
00726       return *it;
00727     }
00728   }
00729   return Address();
00730 }
00731 
00732 void Addressee::insertCategory( const QString &c )
00733 {
00734   detach();
00735   mData->empty = false;
00736 
00737   if ( mData->categories.findIndex( c ) != -1 ) return;
00738 
00739   mData->categories.append( c );
00740 }
00741 
00742 void Addressee::removeCategory( const QString &c )
00743 {
00744   detach();
00745 
00746   QStringList::Iterator it = mData->categories.find( c );
00747   if ( it == mData->categories.end() ) return;
00748 
00749   mData->categories.remove( it );
00750 }
00751 
00752 bool Addressee::hasCategory( const QString &c ) const
00753 {
00754   return ( mData->categories.findIndex( c ) != -1 );
00755 }
00756 
00757 void Addressee::setCategories( const QStringList &c )
00758 {
00759   detach();
00760   mData->empty = false;
00761 
00762   mData->categories = c;
00763 }
00764 
00765 QStringList Addressee::categories() const
00766 {
00767   return mData->categories;
00768 }
00769 
00770 void Addressee::insertCustom( const QString &app, const QString &name,
00771                               const QString &value )
00772 {
00773   if ( value.isEmpty() || name.isEmpty() || app.isEmpty() ) return;
00774 
00775   detach();
00776   mData->empty = false;
00777 
00778   QString qualifiedName = app + "-" + name + ":";
00779 
00780   QStringList::Iterator it;
00781   for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00782     if ( (*it).startsWith( qualifiedName ) ) {
00783       (*it) = qualifiedName + value;
00784       return;
00785     }
00786   }
00787 
00788   mData->custom.append( qualifiedName + value );
00789 }
00790 
00791 void Addressee::removeCustom( const QString &app, const QString &name)
00792 {
00793   detach();
00794 
00795   QString qualifiedName = app + "-" + name + ":";
00796 
00797   QStringList::Iterator it;
00798   for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00799     if ( (*it).startsWith( qualifiedName ) ) {
00800       mData->custom.remove( it );
00801       return;
00802     }
00803   }
00804 }
00805 
00806 QString Addressee::custom( const QString &app, const QString &name ) const
00807 {
00808   QString qualifiedName = app + "-" + name + ":";
00809   QString value;
00810 
00811   QStringList::ConstIterator it;
00812   for( it = mData->custom.constBegin(); it != mData->custom.constEnd(); ++it ) {
00813     if ( (*it).startsWith( qualifiedName ) ) {
00814       value = (*it).mid( (*it).find( ":" ) + 1 );
00815       break;
00816     }
00817   }
00818 
00819   return value;
00820 }
00821 
00822 void Addressee::setCustoms( const QStringList &l )
00823 {
00824   detach();
00825   mData->empty = false;
00826 
00827   mData->custom = l;
00828 }
00829 
00830 QStringList Addressee::customs() const
00831 {
00832   return mData->custom;
00833 }
00834 
00835 void Addressee::parseEmailAddress( const QString &rawEmail, QString &fullName,
00836                                    QString &email)
00837 {
00838   // This is a simplified version of KPIM::splitAddress().
00839 
00840   fullName = "";
00841   email = "";
00842   if ( rawEmail.isEmpty() )
00843     return; // KPIM::AddressEmpty;
00844 
00845   // The code works on 8-bit strings, so convert the input to UTF-8.
00846   QCString address = rawEmail.utf8();
00847 
00848   QCString displayName;
00849   QCString addrSpec;
00850   QCString comment;
00851 
00852   // The following is a primitive parser for a mailbox-list (cf. RFC 2822).
00853   // The purpose is to extract a displayable string from the mailboxes.
00854   // Comments in the addr-spec are not handled. No error checking is done.
00855 
00856   enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
00857   bool inQuotedString = false;
00858   int commentLevel = 0;
00859   bool stop = false;
00860 
00861   for ( char* p = address.data(); *p && !stop; ++p ) {
00862     switch ( context ) {
00863     case TopLevel : {
00864       switch ( *p ) {
00865       case '"' : inQuotedString = !inQuotedString;
00866                  displayName += *p;
00867                  break;
00868       case '(' : if ( !inQuotedString ) {
00869                    context = InComment;
00870                    commentLevel = 1;
00871                  }
00872                  else
00873                    displayName += *p;
00874                  break;
00875       case '<' : if ( !inQuotedString ) {
00876                    context = InAngleAddress;
00877                  }
00878                  else
00879                    displayName += *p;
00880                  break;
00881       case '\\' : // quoted character
00882                  displayName += *p;
00883                  ++p; // skip the '\'
00884                  if ( *p )
00885                    displayName += *p;
00886                  else
00887                    //return KPIM::UnexpectedEnd;
00888                    goto ABORT_PARSING;
00889                  break;
00890       case ',' : if ( !inQuotedString ) {
00891                    //if ( allowMultipleAddresses )
00892                    //  stop = true;
00893                    //else
00894                    //  return KPIM::UnexpectedComma;
00895                    goto ABORT_PARSING;
00896                  }
00897                  else
00898                    displayName += *p;
00899                  break;
00900       default :  displayName += *p;
00901       }
00902       break;
00903     }
00904     case InComment : {
00905       switch ( *p ) {
00906       case '(' : ++commentLevel;
00907                  comment += *p;
00908                  break;
00909       case ')' : --commentLevel;
00910                  if ( commentLevel == 0 ) {
00911                    context = TopLevel;
00912                    comment += ' '; // separate the text of several comments
00913                  }
00914                  else
00915                    comment += *p;
00916                  break;
00917       case '\\' : // quoted character
00918                  comment += *p;
00919                  ++p; // skip the '\'
00920                  if ( *p )
00921                    comment += *p;
00922                  else
00923                    //return KPIM::UnexpectedEnd;
00924                    goto ABORT_PARSING;
00925                  break;
00926       default :  comment += *p;
00927       }
00928       break;
00929     }
00930     case InAngleAddress : {
00931       switch ( *p ) {
00932       case '"' : inQuotedString = !inQuotedString;
00933                  addrSpec += *p;
00934                  break;
00935       case '>' : if ( !inQuotedString ) {
00936                    context = TopLevel;
00937                  }
00938                  else
00939                    addrSpec += *p;
00940                  break;
00941       case '\\' : // quoted character
00942                  addrSpec += *p;
00943                  ++p; // skip the '\'
00944                  if ( *p )
00945                    addrSpec += *p;
00946                  else
00947                    //return KPIM::UnexpectedEnd;
00948                    goto ABORT_PARSING;
00949                  break;
00950       default :  addrSpec += *p;
00951       }
00952       break;
00953     }
00954     } // switch ( context )
00955   }
00956 
00957 ABORT_PARSING:
00958   displayName = displayName.stripWhiteSpace();
00959   comment = comment.stripWhiteSpace();
00960   addrSpec = addrSpec.stripWhiteSpace();
00961 
00962   fullName = QString::fromUtf8( displayName );
00963   email = QString::fromUtf8( addrSpec );
00964 
00965   // check for errors
00966   if ( inQuotedString )
00967     return; // KPIM::UnbalancedQuote;
00968   if ( context == InComment )
00969     return; // KPIM::UnbalancedParens;
00970   if ( context == InAngleAddress )
00971     return; // KPIM::UnclosedAngleAddr;
00972 
00973   if ( addrSpec.isEmpty() ) {
00974     if ( displayName.isEmpty() )
00975       return; // KPIM::NoAddressSpec;
00976     else {
00977       //addrSpec = displayName;
00978       //displayName.truncate( 0 );
00979       // Address of the form "foo@bar" or "foo@bar (Name)".
00980       email = fullName;
00981       fullName = QString::fromUtf8( comment );
00982     }
00983   }
00984 
00985   // Check that we do not have any extra characters on the end of the
00986   // strings
00987   unsigned int len = fullName.length();
00988   if ( fullName[ 0 ] == '"' && fullName[ len - 1 ] == '"' )
00989     fullName = fullName.mid( 1, len - 2 );
00990 }
00991 
00992 void Addressee::setResource( Resource *resource )
00993 {
00994   detach();
00995   mData->resource = resource;
00996 }
00997 
00998 Resource *Addressee::resource() const
00999 {
01000   return mData->resource;
01001 }
01002 
01003 void Addressee::setChanged( bool value )
01004 {
01005   detach();
01006   mData->changed = value;
01007 }
01008 
01009 bool Addressee::changed() const
01010 {
01011   return mData->changed;
01012 }
01013 
01014 void Addressee::setSortMode( KABC::SortMode *mode )
01015 {
01016   mSortMode = mode;
01017 }
01018 
01019 bool Addressee::operator< ( const Addressee &addr )
01020 {
01021   if ( !mSortMode )
01022     return false;
01023   else
01024     return mSortMode->lesser( *this, addr );
01025 }
01026 
01027 QDataStream &KABC::operator<<( QDataStream &s, const Addressee &a )
01028 {
01029   if (!a.mData) return s;
01030 
01031   s << a.uid();
01032 
01033   --STREAMOUT--
01034   s << a.mData->phoneNumbers;
01035   s << a.mData->addresses;
01036   s << a.mData->emails;
01037   s << a.mData->categories;
01038   s << a.mData->custom;
01039   s << a.mData->keys;
01040   return s;
01041 }
01042 
01043 QDataStream &KABC::operator>>( QDataStream &s, Addressee &a )
01044 {
01045   if (!a.mData)
01046     return s;
01047 
01048   a.detach();
01049 
01050   s >> a.mData->uid;
01051 
01052   --STREAMIN--
01053   s >> a.mData->phoneNumbers;
01054   s >> a.mData->addresses;
01055   s >> a.mData->emails;
01056   s >> a.mData->categories;
01057   s >> a.mData->custom;
01058   s >> a.mData->keys;
01059 
01060   a.mData->empty = false;
01061 
01062   return s;
01063 }
01064 
01065 bool matchBinaryPattern( int value, int pattern )
01066 {
01073   if ( pattern == 0 )
01074     return ( value == 0 );
01075   else
01076     return ( pattern == ( pattern & value ) );
01077 }
01078 
01079 template <class L>
01080 bool listEquals( const QValueList<L> &list, const QValueList<L> &pattern )
01081 {
01082   if ( list.count() != pattern.count() )
01083     return false;
01084 
01085   for ( uint i = 0; i < list.count(); ++i )
01086     if ( pattern.find( list[ i ] ) == pattern.end() )
01087       return false;
01088 
01089   return true;
01090 }
01091 
01092 bool emailsEquals( const QStringList &list, const QStringList &pattern )
01093 {
01094   if ( list.count() != pattern.count() )
01095     return false;
01096 
01097   if ( list.first() != pattern.first() )
01098     return false;
01099 
01100   QStringList::ConstIterator it;
01101   for ( it = list.begin(); it != list.end(); ++it )
01102     if ( pattern.find( *it ) == pattern.end() )
01103       return false;
01104 
01105   return true;
01106 }
KDE Home | KDE Accessibility Home | Description of Access Keys