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 &str )
00186 {
00187   setFormattedName( str );
00188   setName( str );
00189 
00190   // clear all name parts
00191   setPrefix( QString::null );
00192   setGivenName( QString::null );
00193   setAdditionalName( QString::null );
00194   setFamilyName( QString::null );
00195   setSuffix( QString::null );
00196 
00197   if ( str.isEmpty() )
00198     return;
00199 
00200   QString spaceStr = " ";
00201   QString emptyStr = "";
00202   AddresseeHelper *helper = AddresseeHelper::self();
00203 
00204   int i = str.find( ',' );
00205   if( i < 0 ) {
00206     QStringList parts = QStringList::split( spaceStr, str );
00207     int leftOffset = 0;
00208     int rightOffset = parts.count() - 1;
00209 
00210     QString suffix;
00211     while ( rightOffset >= 0 ) {
00212       if ( helper->containsSuffix( parts[ rightOffset ] ) ) {
00213         suffix.prepend(parts[ rightOffset ] + (suffix.isEmpty() ? emptyStr : spaceStr));
00214         rightOffset--;
00215       } else
00216         break;
00217     }
00218     setSuffix( suffix );
00219 
00220     if ( rightOffset < 0 )
00221       return;
00222 
00223     QStringList inclusionList;
00224     for ( int n = 1; (rightOffset - n >= 0) && (n < 4); ++n ) {
00225       if ( helper->containsPrefix( parts[ rightOffset - n ].lower() ) ) {
00226         inclusionList.prepend( parts[ rightOffset - n ] );
00227       } else
00228         break;
00229     }
00230 
00231     if ( !inclusionList.isEmpty() ) {
00232       setFamilyName( inclusionList.join( " " ) + spaceStr + parts[ rightOffset ] );
00233       rightOffset -= inclusionList.count();
00234     } else {
00235       if ( helper->tradeAsFamilyName() )
00236         setFamilyName( parts[ rightOffset ] );
00237       else
00238         setGivenName( parts[ rightOffset ] );
00239     }
00240 
00241     QString prefix;
00242     while ( leftOffset < rightOffset ) {
00243       if ( helper->containsTitle( parts[ leftOffset ] ) ) {
00244         prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00245         leftOffset++;
00246       } else
00247         break;
00248     }
00249     setPrefix( prefix );
00250 
00251     if ( leftOffset < rightOffset ) {
00252       setGivenName( parts[ leftOffset ] );
00253       leftOffset++;
00254     }
00255 
00256     QString additionalName;
00257     while ( leftOffset < rightOffset ) {
00258       additionalName.append( ( additionalName.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00259       leftOffset++;
00260     }
00261     setAdditionalName( additionalName );
00262   } else {
00263     QString part1 = str.left( i );
00264     QString part2 = str.mid( i + 1 );
00265 
00266     QStringList parts = QStringList::split( spaceStr, part1 );
00267     int leftOffset = 0;
00268     int rightOffset = parts.count() - 1;
00269 
00270     if ( parts.count() > 0 ) {
00271 
00272       QString suffix;
00273       while ( rightOffset >= 0 ) {
00274         if ( helper->containsSuffix( parts[ rightOffset ] ) ) {
00275           suffix.prepend(parts[ rightOffset ] + (suffix.isEmpty() ? emptyStr : spaceStr));
00276           rightOffset--;
00277         } else
00278           break;
00279       }
00280       setSuffix( suffix );
00281 
00282       if ( rightOffset - 1 >= 0 && helper->containsPrefix( parts[ rightOffset - 1 ].lower() ) ) {
00283         setFamilyName( parts[ rightOffset - 1 ] + spaceStr + parts[ rightOffset ] );
00284         rightOffset--;
00285       } else
00286         setFamilyName( parts[ rightOffset ] );
00287 
00288       QString prefix;
00289       while ( leftOffset < rightOffset ) {
00290         if ( helper->containsTitle( parts[ leftOffset ] ) ) {
00291           prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00292           leftOffset++;
00293         } else
00294           break;
00295       }
00296     } else {
00297       setPrefix( "" );
00298       setFamilyName( "" );
00299       setSuffix( "" );
00300     }
00301 
00302     parts = QStringList::split( spaceStr, part2 );
00303 
00304     leftOffset = 0;
00305     rightOffset = parts.count();
00306 
00307     if ( parts.count() > 0 ) {
00308 
00309       QString prefix;
00310       while ( leftOffset < rightOffset ) {
00311         if ( helper->containsTitle( parts[ leftOffset ] ) ) {
00312           prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00313           leftOffset++;
00314         } else
00315           break;
00316       }
00317       setPrefix( prefix );
00318 
00319       if ( leftOffset < rightOffset ) {
00320         setGivenName( parts[ leftOffset ] );
00321         leftOffset++;
00322       }
00323 
00324       QString additionalName;
00325       while ( leftOffset < rightOffset ) {
00326         additionalName.append( ( additionalName.isEmpty() ? emptyStr : spaceStr) + parts[ leftOffset ] );
00327         leftOffset++;
00328       }
00329       setAdditionalName( additionalName );
00330     } else {
00331       setGivenName( "" );
00332       setAdditionalName( "" );
00333     }
00334   }
00335 }
00336 
00337 QString Addressee::realName() const
00338 {
00339   QString n( formattedName() );
00340   if ( !n.isEmpty() )
00341     return n;
00342 
00343   n = assembledName();
00344   if ( !n.isEmpty() )
00345     return n;
00346 
00347   n = name();
00348   if ( !n.isEmpty() )
00349     return n;
00350 
00351   return organization();
00352 }
00353 
00354 QString Addressee::assembledName() const
00355 {
00356   QString name = prefix() + " " + givenName() + " " + additionalName() + " " +
00357               familyName() + " " + suffix();
00358 
00359   return name.simplifyWhiteSpace();
00360 }
00361 
00362 QString Addressee::fullEmail( const QString &email ) const
00363 {
00364   QString e;
00365   if ( email.isNull() ) {
00366     e = preferredEmail();
00367   } else {
00368     e = email;
00369   }
00370   if ( e.isEmpty() ) return QString::null;
00371 
00372   QString text;
00373   if ( realName().isEmpty() )
00374     text = e;
00375   else {
00376     QRegExp needQuotes( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" );
00377     if ( realName().find( needQuotes ) != -1 )
00378       text = "\"" + realName() + "\" <" + e + ">";
00379     else
00380       text = realName() + " <" + e + ">";
00381   }
00382 
00383   return text;
00384 }
00385 
00386 void Addressee::insertEmail( const QString &email, bool preferred )
00387 {
00388   if ( email.simplifyWhiteSpace().isEmpty() )
00389     return;
00390 
00391   detach();
00392   mData->empty = false;
00393 
00394   QStringList::Iterator it = mData->emails.find( email );
00395 
00396   if ( it != mData->emails.end() ) {
00397     if ( !preferred || it == mData->emails.begin() ) return;
00398     mData->emails.remove( it );
00399     mData->emails.prepend( email );
00400   } else {
00401     if ( preferred ) {
00402       mData->emails.prepend( email );
00403     } else {
00404       mData->emails.append( email );
00405     }
00406   }
00407 }
00408 
00409 void Addressee::removeEmail( const QString &email )
00410 {
00411   detach();
00412 
00413   QStringList::Iterator it = mData->emails.find( email );
00414   if ( it == mData->emails.end() ) return;
00415 
00416   mData->emails.remove( it );
00417 }
00418 
00419 QString Addressee::preferredEmail() const
00420 {
00421   if ( mData->emails.count() == 0 ) return QString::null;
00422   else return mData->emails.first();
00423 }
00424 
00425 QStringList Addressee::emails() const
00426 {
00427   return mData->emails;
00428 }
00429 void Addressee::setEmails( const QStringList& emails ) {
00430   detach();
00431 
00432   mData->emails = emails;
00433 }
00434 void Addressee::insertPhoneNumber( const PhoneNumber &phoneNumber )
00435 {
00436   detach();
00437   mData->empty = false;
00438 
00439   PhoneNumber::List::Iterator it;
00440   for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00441     if ( (*it).id() == phoneNumber.id() ) {
00442       *it = phoneNumber;
00443       return;
00444     }
00445   }
00446   if ( !phoneNumber.number().simplifyWhiteSpace().isEmpty() )
00447     mData->phoneNumbers.append( phoneNumber );
00448 }
00449 
00450 void Addressee::removePhoneNumber( const PhoneNumber &phoneNumber )
00451 {
00452   detach();
00453 
00454   PhoneNumber::List::Iterator it;
00455   for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00456     if ( (*it).id() == phoneNumber.id() ) {
00457       mData->phoneNumbers.remove( it );
00458       return;
00459     }
00460   }
00461 }
00462 
00463 PhoneNumber Addressee::phoneNumber( int type ) const
00464 {
00465   PhoneNumber phoneNumber( "", type );
00466   PhoneNumber::List::ConstIterator it;
00467   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00468     if ( matchBinaryPattern( (*it).type(), type ) ) {
00469       if ( (*it).type() & PhoneNumber::Pref )
00470         return (*it);
00471       else if ( phoneNumber.number().isEmpty() )
00472         phoneNumber = (*it);
00473     }
00474   }
00475 
00476   return phoneNumber;
00477 }
00478 
00479 PhoneNumber::List Addressee::phoneNumbers() const
00480 {
00481   return mData->phoneNumbers;
00482 }
00483 
00484 PhoneNumber::List Addressee::phoneNumbers( int type ) const
00485 {
00486   PhoneNumber::List list;
00487 
00488   PhoneNumber::List::ConstIterator it;
00489   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00490     if ( matchBinaryPattern( (*it).type(), type ) ) {
00491       list.append( *it );
00492     }
00493   }
00494   return list;
00495 }
00496 
00497 PhoneNumber Addressee::findPhoneNumber( const QString &id ) const
00498 {
00499   PhoneNumber::List::ConstIterator it;
00500   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00501     if ( (*it).id() == id ) {
00502       return *it;
00503     }
00504   }
00505   return PhoneNumber();
00506 }
00507 
00508 void Addressee::insertKey( const Key &key )
00509 {
00510   detach();
00511   mData->empty = false;
00512 
00513   Key::List::Iterator it;
00514   for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00515     if ( (*it).id() == key.id() ) {
00516       *it = key;
00517       return;
00518     }
00519   }
00520   mData->keys.append( key );
00521 }
00522 
00523 void Addressee::removeKey( const Key &key )
00524 {
00525   detach();
00526 
00527   Key::List::Iterator it;
00528   for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00529     if ( (*it).id() == key.id() ) {
00530       mData->keys.remove( key );
00531       return;
00532     }
00533   }
00534 }
00535 
00536 Key Addressee::key( int type, QString customTypeString ) const
00537 {
00538   Key::List::ConstIterator it;
00539   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00540     if ( (*it).type() == type ) {
00541       if ( type == Key::Custom ) {
00542         if ( customTypeString.isEmpty() ) {
00543           return *it;
00544         } else {
00545           if ( (*it).customTypeString() == customTypeString )
00546             return (*it);
00547         }
00548       } else {
00549         return *it;
00550       }
00551     }
00552   }
00553   return Key( QString(), type );
00554 }
00555 
00556 void Addressee::setKeys( const Key::List& list )
00557 {
00558   detach();
00559   mData->keys = list;
00560 }
00561 
00562 Key::List Addressee::keys() const
00563 {
00564   return mData->keys;
00565 }
00566 
00567 Key::List Addressee::keys( int type, QString customTypeString ) const
00568 {
00569   Key::List list;
00570 
00571   Key::List::ConstIterator it;
00572   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00573     if ( (*it).type() == type ) {
00574       if ( type == Key::Custom ) {
00575         if ( customTypeString.isEmpty() ) {
00576           list.append( *it );
00577         } else {
00578           if ( (*it).customTypeString() == customTypeString )
00579             list.append( *it );
00580         }
00581       } else {
00582         list.append( *it );
00583       }
00584     }
00585   }
00586   return list;
00587 }
00588 
00589 Key Addressee::findKey( const QString &id ) const
00590 {
00591   Key::List::ConstIterator it;
00592   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00593     if ( (*it).id() == id ) {
00594       return *it;
00595     }
00596   }
00597   return Key();
00598 }
00599 
00600 QString Addressee::asString() const
00601 {
00602   return "Smith, agent Smith...";
00603 }
00604 
00605 void Addressee::dump() const
00606 {
00607   kdDebug(5700) << "Addressee {" << endl;
00608 
00609   kdDebug(5700) << "  Uid: '" << uid() << "'" << endl;
00610 
00611   --DEBUG--
00612 
00613   kdDebug(5700) << "  Emails {" << endl;
00614   const QStringList e = emails();
00615   QStringList::ConstIterator it;
00616   for( it = e.begin(); it != e.end(); ++it ) {
00617     kdDebug(5700) << "    " << (*it) << endl;
00618   }
00619   kdDebug(5700) << "  }" << endl;
00620 
00621   kdDebug(5700) << "  PhoneNumbers {" << endl;
00622   const PhoneNumber::List p = phoneNumbers();
00623   PhoneNumber::List::ConstIterator it2;
00624   for( it2 = p.begin(); it2 != p.end(); ++it2 ) {
00625     kdDebug(5700) << "    Type: " << int((*it2).type()) << " Number: " << (*it2).number() << endl;
00626   }
00627   kdDebug(5700) << "  }" << endl;
00628 
00629   const Address::List a = addresses();
00630   Address::List::ConstIterator it3;
00631   for( it3 = a.begin(); it3 != a.end(); ++it3 ) {
00632     (*it3).dump();
00633   }
00634 
00635   kdDebug(5700) << "  Keys {" << endl;
00636   const Key::List k = keys();
00637   Key::List::ConstIterator it4;
00638   for( it4 = k.begin(); it4 != k.end(); ++it4 ) {
00639     kdDebug(5700) << "    Type: " << int((*it4).type()) <<
00640                      " Key: " << (*it4).textData() <<
00641                      " CustomString: " << (*it4).customTypeString() << endl;
00642   }
00643   kdDebug(5700) << "  }" << endl;
00644 
00645   kdDebug(5700) << "}" << endl;
00646 }
00647 
00648 
00649 void Addressee::insertAddress( const Address &address )
00650 {
00651   if ( address.isEmpty() )
00652     return;
00653 
00654   detach();
00655   mData->empty = false;
00656 
00657   Address::List::Iterator it;
00658   for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00659     if ( (*it).id() == address.id() ) {
00660       *it = address;
00661       return;
00662     }
00663   }
00664 
00665   mData->addresses.append( address );
00666 }
00667 
00668 void Addressee::removeAddress( const Address &address )
00669 {
00670   detach();
00671 
00672   Address::List::Iterator it;
00673   for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00674     if ( (*it).id() == address.id() ) {
00675       mData->addresses.remove( it );
00676       return;
00677     }
00678   }
00679 }
00680 
00681 Address Addressee::address( int type ) const
00682 {
00683   Address address( type );
00684   Address::List::ConstIterator it;
00685   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00686     if ( matchBinaryPattern( (*it).type(), type ) ) {
00687       if ( (*it).type() & Address::Pref )
00688         return (*it);
00689       else if ( address.isEmpty() )
00690         address = (*it);
00691     }
00692   }
00693 
00694   return address;
00695 }
00696 
00697 Address::List Addressee::addresses() const
00698 {
00699   return mData->addresses;
00700 }
00701 
00702 Address::List Addressee::addresses( int type ) const
00703 {
00704   Address::List list;
00705 
00706   Address::List::ConstIterator it;
00707   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00708     if ( matchBinaryPattern( (*it).type(), type ) ) {
00709       list.append( *it );
00710     }
00711   }
00712 
00713   return list;
00714 }
00715 
00716 Address Addressee::findAddress( const QString &id ) const
00717 {
00718   Address::List::ConstIterator it;
00719   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00720     if ( (*it).id() == id ) {
00721       return *it;
00722     }
00723   }
00724   return Address();
00725 }
00726 
00727 void Addressee::insertCategory( const QString &c )
00728 {
00729   detach();
00730   mData->empty = false;
00731 
00732   if ( mData->categories.findIndex( c ) != -1 ) return;
00733 
00734   mData->categories.append( c );
00735 }
00736 
00737 void Addressee::removeCategory( const QString &c )
00738 {
00739   detach();
00740 
00741   QStringList::Iterator it = mData->categories.find( c );
00742   if ( it == mData->categories.end() ) return;
00743 
00744   mData->categories.remove( it );
00745 }
00746 
00747 bool Addressee::hasCategory( const QString &c ) const
00748 {
00749   return ( mData->categories.findIndex( c ) != -1 );
00750 }
00751 
00752 void Addressee::setCategories( const QStringList &c )
00753 {
00754   detach();
00755   mData->empty = false;
00756 
00757   mData->categories = c;
00758 }
00759 
00760 QStringList Addressee::categories() const
00761 {
00762   return mData->categories;
00763 }
00764 
00765 void Addressee::insertCustom( const QString &app, const QString &name,
00766                               const QString &value )
00767 {
00768   if ( value.isEmpty() || name.isEmpty() || app.isEmpty() ) return;
00769 
00770   detach();
00771   mData->empty = false;
00772 
00773   QString qualifiedName = app + "-" + name + ":";
00774 
00775   QStringList::Iterator it;
00776   for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00777     if ( (*it).startsWith( qualifiedName ) ) {
00778       (*it) = qualifiedName + value;
00779       return;
00780     }
00781   }
00782 
00783   mData->custom.append( qualifiedName + value );
00784 }
00785 
00786 void Addressee::removeCustom( const QString &app, const QString &name)
00787 {
00788   detach();
00789 
00790   QString qualifiedName = app + "-" + name + ":";
00791 
00792   QStringList::Iterator it;
00793   for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00794     if ( (*it).startsWith( qualifiedName ) ) {
00795       mData->custom.remove( it );
00796       return;
00797     }
00798   }
00799 }
00800 
00801 QString Addressee::custom( const QString &app, const QString &name ) const
00802 {
00803   QString qualifiedName = app + "-" + name + ":";
00804   QString value;
00805 
00806   QStringList::ConstIterator it;
00807   for( it = mData->custom.constBegin(); it != mData->custom.constEnd(); ++it ) {
00808     if ( (*it).startsWith( qualifiedName ) ) {
00809       value = (*it).mid( (*it).find( ":" ) + 1 );
00810       break;
00811     }
00812   }
00813 
00814   return value;
00815 }
00816 
00817 void Addressee::setCustoms( const QStringList &l )
00818 {
00819   detach();
00820   mData->empty = false;
00821 
00822   mData->custom = l;
00823 }
00824 
00825 QStringList Addressee::customs() const
00826 {
00827   return mData->custom;
00828 }
00829 
00830 void Addressee::parseEmailAddress( const QString &rawEmail, QString &fullName,
00831                                    QString &email)
00832 {
00833   // This is a simplified version of KPIM::splitAddress().
00834 
00835   fullName = "";
00836   email = "";
00837   if ( rawEmail.isEmpty() )
00838     return; // KPIM::AddressEmpty;
00839 
00840   // The code works on 8-bit strings, so convert the input to UTF-8.
00841   QCString address = rawEmail.utf8();
00842 
00843   QCString displayName;
00844   QCString addrSpec;
00845   QCString comment;
00846 
00847   // The following is a primitive parser for a mailbox-list (cf. RFC 2822).
00848   // The purpose is to extract a displayable string from the mailboxes.
00849   // Comments in the addr-spec are not handled. No error checking is done.
00850 
00851   enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
00852   bool inQuotedString = false;
00853   int commentLevel = 0;
00854   bool stop = false;
00855 
00856   for ( char* p = address.data(); *p && !stop; ++p ) {
00857     switch ( context ) {
00858     case TopLevel : {
00859       switch ( *p ) {
00860       case '"' : inQuotedString = !inQuotedString;
00861                  displayName += *p;
00862                  break;
00863       case '(' : if ( !inQuotedString ) {
00864                    context = InComment;
00865                    commentLevel = 1;
00866                  }
00867                  else
00868                    displayName += *p;
00869                  break;
00870       case '<' : if ( !inQuotedString ) {
00871                    context = InAngleAddress;
00872                  }
00873                  else
00874                    displayName += *p;
00875                  break;
00876       case '\\' : // quoted character
00877                  displayName += *p;
00878                  ++p; // skip the '\'
00879                  if ( *p )
00880                    displayName += *p;
00881                  else
00882                    //return KPIM::UnexpectedEnd;
00883                    goto ABORT_PARSING;
00884                  break;
00885       case ',' : if ( !inQuotedString ) {
00886                    //if ( allowMultipleAddresses )
00887                    //  stop = true;
00888                    //else
00889                    //  return KPIM::UnexpectedComma;
00890                    goto ABORT_PARSING;
00891                  }
00892                  else
00893                    displayName += *p;
00894                  break;
00895       default :  displayName += *p;
00896       }
00897       break;
00898     }
00899     case InComment : {
00900       switch ( *p ) {
00901       case '(' : ++commentLevel;
00902                  comment += *p;
00903                  break;
00904       case ')' : --commentLevel;
00905                  if ( commentLevel == 0 ) {
00906                    context = TopLevel;
00907                    comment += ' '; // separate the text of several comments
00908                  }
00909                  else
00910                    comment += *p;
00911                  break;
00912       case '\\' : // quoted character
00913                  comment += *p;
00914                  ++p; // skip the '\'
00915                  if ( *p )
00916                    comment += *p;
00917                  else
00918                    //return KPIM::UnexpectedEnd;
00919                    goto ABORT_PARSING;
00920                  break;
00921       default :  comment += *p;
00922       }
00923       break;
00924     }
00925     case InAngleAddress : {
00926       switch ( *p ) {
00927       case '"' : inQuotedString = !inQuotedString;
00928                  addrSpec += *p;
00929                  break;
00930       case '>' : if ( !inQuotedString ) {
00931                    context = TopLevel;
00932                  }
00933                  else
00934                    addrSpec += *p;
00935                  break;
00936       case '\\' : // quoted character
00937                  addrSpec += *p;
00938                  ++p; // skip the '\'
00939                  if ( *p )
00940                    addrSpec += *p;
00941                  else
00942                    //return KPIM::UnexpectedEnd;
00943                    goto ABORT_PARSING;
00944                  break;
00945       default :  addrSpec += *p;
00946       }
00947       break;
00948     }
00949     } // switch ( context )
00950   }
00951 
00952 ABORT_PARSING:
00953   displayName = displayName.stripWhiteSpace();
00954   comment = comment.stripWhiteSpace();
00955   addrSpec = addrSpec.stripWhiteSpace();
00956 
00957   fullName = QString::fromUtf8( displayName );
00958   email = QString::fromUtf8( addrSpec );
00959 
00960   // check for errors
00961   if ( inQuotedString )
00962     return; // KPIM::UnbalancedQuote;
00963   if ( context == InComment )
00964     return; // KPIM::UnbalancedParens;
00965   if ( context == InAngleAddress )
00966     return; // KPIM::UnclosedAngleAddr;
00967 
00968   if ( addrSpec.isEmpty() ) {
00969     if ( displayName.isEmpty() )
00970       return; // KPIM::NoAddressSpec;
00971     else {
00972       //addrSpec = displayName;
00973       //displayName.truncate( 0 );
00974       // Address of the form "foo@bar" or "foo@bar (Name)".
00975       email = fullName;
00976       fullName = QString::fromUtf8( comment );
00977     }
00978   }
00979 
00980   // Check that we do not have any extra characters on the end of the
00981   // strings
00982   unsigned int len = fullName.length();
00983   if ( fullName[ 0 ] == '"' && fullName[ len - 1 ] == '"' )
00984     fullName = fullName.mid( 1, len - 2 );
00985 }
00986 
00987 void Addressee::setResource( Resource *resource )
00988 {
00989   detach();
00990   mData->resource = resource;
00991 }
00992 
00993 Resource *Addressee::resource() const
00994 {
00995   return mData->resource;
00996 }
00997 
00998 void Addressee::setChanged( bool value )
00999 {
01000   detach();
01001   mData->changed = value;
01002 }
01003 
01004 bool Addressee::changed() const
01005 {
01006   return mData->changed;
01007 }
01008 
01009 void Addressee::setSortMode( KABC::SortMode *mode )
01010 {
01011   mSortMode = mode;
01012 }
01013 
01014 bool Addressee::operator< ( const Addressee &addr )
01015 {
01016   if ( !mSortMode )
01017     return false;
01018   else
01019     return mSortMode->lesser( *this, addr );
01020 }
01021 
01022 QDataStream &KABC::operator<<( QDataStream &s, const Addressee &a )
01023 {
01024   if (!a.mData) return s;
01025 
01026   s << a.uid();
01027 
01028   --STREAMOUT--
01029   s << a.mData->phoneNumbers;
01030   s << a.mData->addresses;
01031   s << a.mData->emails;
01032   s << a.mData->categories;
01033   s << a.mData->custom;
01034   s << a.mData->keys;
01035   return s;
01036 }
01037 
01038 QDataStream &KABC::operator>>( QDataStream &s, Addressee &a )
01039 {
01040   if (!a.mData)
01041     return s;
01042 
01043   a.detach();
01044 
01045   s >> a.mData->uid;
01046 
01047   --STREAMIN--
01048   s >> a.mData->phoneNumbers;
01049   s >> a.mData->addresses;
01050   s >> a.mData->emails;
01051   s >> a.mData->categories;
01052   s >> a.mData->custom;
01053   s >> a.mData->keys;
01054 
01055   a.mData->empty = false;
01056 
01057   return s;
01058 }
01059 
01060 bool matchBinaryPattern( int value, int pattern )
01061 {
01068   if ( pattern == 0 )
01069     return ( value == 0 );
01070   else
01071     return ( pattern == ( pattern & value ) );
01072 }
01073 
01074 template <class L>
01075 bool listEquals( const QValueList<L> &list, const QValueList<L> &pattern )
01076 {
01077   if ( list.count() != pattern.count() )
01078     return false;
01079 
01080   for ( uint i = 0; i < list.count(); ++i )
01081     if ( pattern.find( list[ i ] ) == pattern.end() )
01082       return false;
01083 
01084   return true;
01085 }
01086 
01087 bool emailsEquals( const QStringList &list, const QStringList &pattern )
01088 {
01089   if ( list.count() != pattern.count() )
01090     return false;
01091 
01092   if ( list.first() != pattern.first() )
01093     return false;
01094 
01095   QStringList::ConstIterator it;
01096   for ( it = list.begin(); it != list.end(); ++it )
01097     if ( pattern.find( *it ) == pattern.end() )
01098       return false;
01099 
01100   return true;
01101 }
KDE Home | KDE Accessibility Home | Description of Access Keys