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       QString name = realName();
00384       name.replace( "\"", "\\\"" );
00385       text = "\"" + name + "\" <" + e + ">";
00386     } else
00387       text = realName() + " <" + e + ">";
00388   }
00389 
00390   return text;
00391 }
00392 
00393 void Addressee::insertEmail( const QString &email, bool preferred )
00394 {
00395   if ( email.simplifyWhiteSpace().isEmpty() )
00396     return;
00397 
00398   detach();
00399   mData->empty = false;
00400 
00401   QStringList::Iterator it = mData->emails.find( email );
00402 
00403   if ( it != mData->emails.end() ) {
00404     if ( !preferred || it == mData->emails.begin() ) return;
00405     mData->emails.remove( it );
00406     mData->emails.prepend( email );
00407   } else {
00408     if ( preferred ) {
00409       mData->emails.prepend( email );
00410     } else {
00411       mData->emails.append( email );
00412     }
00413   }
00414 }
00415 
00416 void Addressee::removeEmail( const QString &email )
00417 {
00418   detach();
00419 
00420   QStringList::Iterator it = mData->emails.find( email );
00421   if ( it == mData->emails.end() ) return;
00422 
00423   mData->emails.remove( it );
00424 }
00425 
00426 QString Addressee::preferredEmail() const
00427 {
00428   if ( mData->emails.count() == 0 ) return QString::null;
00429   else return mData->emails.first();
00430 }
00431 
00432 QStringList Addressee::emails() const
00433 {
00434   return mData->emails;
00435 }
00436 void Addressee::setEmails( const QStringList& emails ) {
00437   detach();
00438 
00439   mData->emails = emails;
00440 }
00441 void Addressee::insertPhoneNumber( const PhoneNumber &phoneNumber )
00442 {
00443   detach();
00444   mData->empty = false;
00445 
00446   PhoneNumber::List::Iterator it;
00447   for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00448     if ( (*it).id() == phoneNumber.id() ) {
00449       *it = phoneNumber;
00450       return;
00451     }
00452   }
00453   if ( !phoneNumber.number().simplifyWhiteSpace().isEmpty() )
00454     mData->phoneNumbers.append( phoneNumber );
00455 }
00456 
00457 void Addressee::removePhoneNumber( const PhoneNumber &phoneNumber )
00458 {
00459   detach();
00460 
00461   PhoneNumber::List::Iterator it;
00462   for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00463     if ( (*it).id() == phoneNumber.id() ) {
00464       mData->phoneNumbers.remove( it );
00465       return;
00466     }
00467   }
00468 }
00469 
00470 PhoneNumber Addressee::phoneNumber( int type ) const
00471 {
00472   PhoneNumber phoneNumber( "", type );
00473   PhoneNumber::List::ConstIterator it;
00474   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00475     if ( matchBinaryPattern( (*it).type(), type ) ) {
00476       if ( (*it).type() & PhoneNumber::Pref )
00477         return (*it);
00478       else if ( phoneNumber.number().isEmpty() )
00479         phoneNumber = (*it);
00480     }
00481   }
00482 
00483   return phoneNumber;
00484 }
00485 
00486 PhoneNumber::List Addressee::phoneNumbers() const
00487 {
00488   return mData->phoneNumbers;
00489 }
00490 
00491 PhoneNumber::List Addressee::phoneNumbers( int type ) const
00492 {
00493   PhoneNumber::List list;
00494 
00495   PhoneNumber::List::ConstIterator it;
00496   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00497     if ( matchBinaryPattern( (*it).type(), type ) ) {
00498       list.append( *it );
00499     }
00500   }
00501   return list;
00502 }
00503 
00504 PhoneNumber Addressee::findPhoneNumber( const QString &id ) const
00505 {
00506   PhoneNumber::List::ConstIterator it;
00507   for( it = mData->phoneNumbers.constBegin(); it != mData->phoneNumbers.constEnd(); ++it ) {
00508     if ( (*it).id() == id ) {
00509       return *it;
00510     }
00511   }
00512   return PhoneNumber();
00513 }
00514 
00515 void Addressee::insertKey( const Key &key )
00516 {
00517   detach();
00518   mData->empty = false;
00519 
00520   Key::List::Iterator it;
00521   for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00522     if ( (*it).id() == key.id() ) {
00523       *it = key;
00524       return;
00525     }
00526   }
00527   mData->keys.append( key );
00528 }
00529 
00530 void Addressee::removeKey( const Key &key )
00531 {
00532   detach();
00533 
00534   Key::List::Iterator it;
00535   for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00536     if ( (*it).id() == key.id() ) {
00537       mData->keys.remove( key );
00538       return;
00539     }
00540   }
00541 }
00542 
00543 Key Addressee::key( int type, QString customTypeString ) const
00544 {
00545   Key::List::ConstIterator it;
00546   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00547     if ( (*it).type() == type ) {
00548       if ( type == Key::Custom ) {
00549         if ( customTypeString.isEmpty() ) {
00550           return *it;
00551         } else {
00552           if ( (*it).customTypeString() == customTypeString )
00553             return (*it);
00554         }
00555       } else {
00556         return *it;
00557       }
00558     }
00559   }
00560   return Key( QString(), type );
00561 }
00562 
00563 void Addressee::setKeys( const Key::List& list )
00564 {
00565   detach();
00566   mData->keys = list;
00567 }
00568 
00569 Key::List Addressee::keys() const
00570 {
00571   return mData->keys;
00572 }
00573 
00574 Key::List Addressee::keys( int type, QString customTypeString ) const
00575 {
00576   Key::List list;
00577 
00578   Key::List::ConstIterator it;
00579   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00580     if ( (*it).type() == type ) {
00581       if ( type == Key::Custom ) {
00582         if ( customTypeString.isEmpty() ) {
00583           list.append( *it );
00584         } else {
00585           if ( (*it).customTypeString() == customTypeString )
00586             list.append( *it );
00587         }
00588       } else {
00589         list.append( *it );
00590       }
00591     }
00592   }
00593   return list;
00594 }
00595 
00596 Key Addressee::findKey( const QString &id ) const
00597 {
00598   Key::List::ConstIterator it;
00599   for( it = mData->keys.constBegin(); it != mData->keys.constEnd(); ++it ) {
00600     if ( (*it).id() == id ) {
00601       return *it;
00602     }
00603   }
00604   return Key();
00605 }
00606 
00607 QString Addressee::asString() const
00608 {
00609   return "Smith, agent Smith...";
00610 }
00611 
00612 void Addressee::dump() const
00613 {
00614   kdDebug(5700) << "Addressee {" << endl;
00615 
00616   kdDebug(5700) << "  Uid: '" << uid() << "'" << endl;
00617 
00618   --DEBUG--
00619 
00620   kdDebug(5700) << "  Emails {" << endl;
00621   const QStringList e = emails();
00622   QStringList::ConstIterator it;
00623   for( it = e.begin(); it != e.end(); ++it ) {
00624     kdDebug(5700) << "    " << (*it) << endl;
00625   }
00626   kdDebug(5700) << "  }" << endl;
00627 
00628   kdDebug(5700) << "  PhoneNumbers {" << endl;
00629   const PhoneNumber::List p = phoneNumbers();
00630   PhoneNumber::List::ConstIterator it2;
00631   for( it2 = p.begin(); it2 != p.end(); ++it2 ) {
00632     kdDebug(5700) << "    Type: " << int((*it2).type()) << " Number: " << (*it2).number() << endl;
00633   }
00634   kdDebug(5700) << "  }" << endl;
00635 
00636   const Address::List a = addresses();
00637   Address::List::ConstIterator it3;
00638   for( it3 = a.begin(); it3 != a.end(); ++it3 ) {
00639     (*it3).dump();
00640   }
00641 
00642   kdDebug(5700) << "  Keys {" << endl;
00643   const Key::List k = keys();
00644   Key::List::ConstIterator it4;
00645   for( it4 = k.begin(); it4 != k.end(); ++it4 ) {
00646     kdDebug(5700) << "    Type: " << int((*it4).type()) <<
00647                      " Key: " << (*it4).textData() <<
00648                      " CustomString: " << (*it4).customTypeString() << endl;
00649   }
00650   kdDebug(5700) << "  }" << endl;
00651 
00652   kdDebug(5700) << "}" << endl;
00653 }
00654 
00655 
00656 void Addressee::insertAddress( const Address &address )
00657 {
00658   if ( address.isEmpty() )
00659     return;
00660 
00661   detach();
00662   mData->empty = false;
00663 
00664   Address::List::Iterator it;
00665   for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00666     if ( (*it).id() == address.id() ) {
00667       *it = address;
00668       return;
00669     }
00670   }
00671 
00672   mData->addresses.append( address );
00673 }
00674 
00675 void Addressee::removeAddress( const Address &address )
00676 {
00677   detach();
00678 
00679   Address::List::Iterator it;
00680   for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00681     if ( (*it).id() == address.id() ) {
00682       mData->addresses.remove( it );
00683       return;
00684     }
00685   }
00686 }
00687 
00688 Address Addressee::address( int type ) const
00689 {
00690   Address address( type );
00691   Address::List::ConstIterator it;
00692   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00693     if ( matchBinaryPattern( (*it).type(), type ) ) {
00694       if ( (*it).type() & Address::Pref )
00695         return (*it);
00696       else if ( address.isEmpty() )
00697         address = (*it);
00698     }
00699   }
00700 
00701   return address;
00702 }
00703 
00704 Address::List Addressee::addresses() const
00705 {
00706   return mData->addresses;
00707 }
00708 
00709 Address::List Addressee::addresses( int type ) const
00710 {
00711   Address::List list;
00712 
00713   Address::List::ConstIterator it;
00714   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00715     if ( matchBinaryPattern( (*it).type(), type ) ) {
00716       list.append( *it );
00717     }
00718   }
00719 
00720   return list;
00721 }
00722 
00723 Address Addressee::findAddress( const QString &id ) const
00724 {
00725   Address::List::ConstIterator it;
00726   for( it = mData->addresses.constBegin(); it != mData->addresses.constEnd(); ++it ) {
00727     if ( (*it).id() == id ) {
00728       return *it;
00729     }
00730   }
00731   return Address();
00732 }
00733 
00734 void Addressee::insertCategory( const QString &c )
00735 {
00736   detach();
00737   mData->empty = false;
00738 
00739   if ( mData->categories.findIndex( c ) != -1 ) return;
00740 
00741   mData->categories.append( c );
00742 }
00743 
00744 void Addressee::removeCategory( const QString &c )
00745 {
00746   detach();
00747 
00748   QStringList::Iterator it = mData->categories.find( c );
00749   if ( it == mData->categories.end() ) return;
00750 
00751   mData->categories.remove( it );
00752 }
00753 
00754 bool Addressee::hasCategory( const QString &c ) const
00755 {
00756   return ( mData->categories.findIndex( c ) != -1 );
00757 }
00758 
00759 void Addressee::setCategories( const QStringList &c )
00760 {
00761   detach();
00762   mData->empty = false;
00763 
00764   mData->categories = c;
00765 }
00766 
00767 QStringList Addressee::categories() const
00768 {
00769   return mData->categories;
00770 }
00771 
00772 void Addressee::insertCustom( const QString &app, const QString &name,
00773                               const QString &value )
00774 {
00775   if ( value.isEmpty() || name.isEmpty() || app.isEmpty() ) return;
00776 
00777   detach();
00778   mData->empty = false;
00779 
00780   QString qualifiedName = app + "-" + name + ":";
00781 
00782   QStringList::Iterator it;
00783   for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00784     if ( (*it).startsWith( qualifiedName ) ) {
00785       (*it) = qualifiedName + value;
00786       return;
00787     }
00788   }
00789 
00790   mData->custom.append( qualifiedName + value );
00791 }
00792 
00793 void Addressee::removeCustom( const QString &app, const QString &name)
00794 {
00795   detach();
00796 
00797   QString qualifiedName = app + "-" + name + ":";
00798 
00799   QStringList::Iterator it;
00800   for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00801     if ( (*it).startsWith( qualifiedName ) ) {
00802       mData->custom.remove( it );
00803       return;
00804     }
00805   }
00806 }
00807 
00808 QString Addressee::custom( const QString &app, const QString &name ) const
00809 {
00810   QString qualifiedName = app + "-" + name + ":";
00811   QString value;
00812 
00813   QStringList::ConstIterator it;
00814   for( it = mData->custom.constBegin(); it != mData->custom.constEnd(); ++it ) {
00815     if ( (*it).startsWith( qualifiedName ) ) {
00816       value = (*it).mid( (*it).find( ":" ) + 1 );
00817       break;
00818     }
00819   }
00820 
00821   return value;
00822 }
00823 
00824 void Addressee::setCustoms( const QStringList &l )
00825 {
00826   detach();
00827   mData->empty = false;
00828 
00829   mData->custom = l;
00830 }
00831 
00832 QStringList Addressee::customs() const
00833 {
00834   return mData->custom;
00835 }
00836 
00837 void Addressee::parseEmailAddress( const QString &rawEmail, QString &fullName,
00838                                    QString &email)
00839 {
00840   // This is a simplified version of KPIM::splitAddress().
00841 
00842   fullName = "";
00843   email = "";
00844   if ( rawEmail.isEmpty() )
00845     return; // KPIM::AddressEmpty;
00846 
00847   // The code works on 8-bit strings, so convert the input to UTF-8.
00848   QCString address = rawEmail.utf8();
00849 
00850   QCString displayName;
00851   QCString addrSpec;
00852   QCString comment;
00853 
00854   // The following is a primitive parser for a mailbox-list (cf. RFC 2822).
00855   // The purpose is to extract a displayable string from the mailboxes.
00856   // Comments in the addr-spec are not handled. No error checking is done.
00857 
00858   enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
00859   bool inQuotedString = false;
00860   int commentLevel = 0;
00861   bool stop = false;
00862 
00863   for ( char* p = address.data(); *p && !stop; ++p ) {
00864     switch ( context ) {
00865     case TopLevel : {
00866       switch ( *p ) {
00867       case '"' : inQuotedString = !inQuotedString;
00868                  displayName += *p;
00869                  break;
00870       case '(' : if ( !inQuotedString ) {
00871                    context = InComment;
00872                    commentLevel = 1;
00873                  }
00874                  else
00875                    displayName += *p;
00876                  break;
00877       case '<' : if ( !inQuotedString ) {
00878                    context = InAngleAddress;
00879                  }
00880                  else
00881                    displayName += *p;
00882                  break;
00883       case '\\' : // quoted character
00884                  displayName += *p;
00885                  ++p; // skip the '\'
00886                  if ( *p )
00887                    displayName += *p;
00888                  else
00889                    //return KPIM::UnexpectedEnd;
00890                    goto ABORT_PARSING;
00891                  break;
00892       case ',' : if ( !inQuotedString ) {
00893                    //if ( allowMultipleAddresses )
00894                    //  stop = true;
00895                    //else
00896                    //  return KPIM::UnexpectedComma;
00897                    goto ABORT_PARSING;
00898                  }
00899                  else
00900                    displayName += *p;
00901                  break;
00902       default :  displayName += *p;
00903       }
00904       break;
00905     }
00906     case InComment : {
00907       switch ( *p ) {
00908       case '(' : ++commentLevel;
00909                  comment += *p;
00910                  break;
00911       case ')' : --commentLevel;
00912                  if ( commentLevel == 0 ) {
00913                    context = TopLevel;
00914                    comment += ' '; // separate the text of several comments
00915                  }
00916                  else
00917                    comment += *p;
00918                  break;
00919       case '\\' : // quoted character
00920                  comment += *p;
00921                  ++p; // skip the '\'
00922                  if ( *p )
00923                    comment += *p;
00924                  else
00925                    //return KPIM::UnexpectedEnd;
00926                    goto ABORT_PARSING;
00927                  break;
00928       default :  comment += *p;
00929       }
00930       break;
00931     }
00932     case InAngleAddress : {
00933       switch ( *p ) {
00934       case '"' : inQuotedString = !inQuotedString;
00935                  addrSpec += *p;
00936                  break;
00937       case '>' : if ( !inQuotedString ) {
00938                    context = TopLevel;
00939                  }
00940                  else
00941                    addrSpec += *p;
00942                  break;
00943       case '\\' : // quoted character
00944                  addrSpec += *p;
00945                  ++p; // skip the '\'
00946                  if ( *p )
00947                    addrSpec += *p;
00948                  else
00949                    //return KPIM::UnexpectedEnd;
00950                    goto ABORT_PARSING;
00951                  break;
00952       default :  addrSpec += *p;
00953       }
00954       break;
00955     }
00956     } // switch ( context )
00957   }
00958 
00959 ABORT_PARSING:
00960   displayName = displayName.stripWhiteSpace();
00961   comment = comment.stripWhiteSpace();
00962   addrSpec = addrSpec.stripWhiteSpace();
00963 
00964   fullName = QString::fromUtf8( displayName );
00965   email = QString::fromUtf8( addrSpec );
00966 
00967   // check for errors
00968   if ( inQuotedString )
00969     return; // KPIM::UnbalancedQuote;
00970   if ( context == InComment )
00971     return; // KPIM::UnbalancedParens;
00972   if ( context == InAngleAddress )
00973     return; // KPIM::UnclosedAngleAddr;
00974 
00975   if ( addrSpec.isEmpty() ) {
00976     if ( displayName.isEmpty() )
00977       return; // KPIM::NoAddressSpec;
00978     else {
00979       //addrSpec = displayName;
00980       //displayName.truncate( 0 );
00981       // Address of the form "foo@bar" or "foo@bar (Name)".
00982       email = fullName;
00983       fullName = QString::fromUtf8( comment );
00984     }
00985   }
00986 
00987   // Check that we do not have any extra characters on the end of the
00988   // strings
00989   unsigned int len = fullName.length();
00990   if ( fullName[ 0 ] == '"' && fullName[ len - 1 ] == '"' )
00991     fullName = fullName.mid( 1, len - 2 );
00992 }
00993 
00994 void Addressee::setResource( Resource *resource )
00995 {
00996   detach();
00997   mData->resource = resource;
00998 }
00999 
01000 Resource *Addressee::resource() const
01001 {
01002   return mData->resource;
01003 }
01004 
01005 void Addressee::setChanged( bool value )
01006 {
01007   detach();
01008   mData->changed = value;
01009 }
01010 
01011 bool Addressee::changed() const
01012 {
01013   return mData->changed;
01014 }
01015 
01016 void Addressee::setSortMode( KABC::SortMode *mode )
01017 {
01018   mSortMode = mode;
01019 }
01020 
01021 bool Addressee::operator< ( const Addressee &addr )
01022 {
01023   if ( !mSortMode )
01024     return false;
01025   else
01026     return mSortMode->lesser( *this, addr );
01027 }
01028 
01029 QDataStream &KABC::operator<<( QDataStream &s, const Addressee &a )
01030 {
01031   if (!a.mData) return s;
01032 
01033   s << a.uid();
01034 
01035   --STREAMOUT--
01036   s << a.mData->phoneNumbers;
01037   s << a.mData->addresses;
01038   s << a.mData->emails;
01039   s << a.mData->categories;
01040   s << a.mData->custom;
01041   s << a.mData->keys;
01042   return s;
01043 }
01044 
01045 QDataStream &KABC::operator>>( QDataStream &s, Addressee &a )
01046 {
01047   if (!a.mData)
01048     return s;
01049 
01050   a.detach();
01051 
01052   s >> a.mData->uid;
01053 
01054   --STREAMIN--
01055   s >> a.mData->phoneNumbers;
01056   s >> a.mData->addresses;
01057   s >> a.mData->emails;
01058   s >> a.mData->categories;
01059   s >> a.mData->custom;
01060   s >> a.mData->keys;
01061 
01062   a.mData->empty = false;
01063 
01064   return s;
01065 }
01066 
01067 bool matchBinaryPattern( int value, int pattern )
01068 {
01075   if ( pattern == 0 )
01076     return ( value == 0 );
01077   else
01078     return ( pattern == ( pattern & value ) );
01079 }
01080 
01081 template <class L>
01082 bool listEquals( const QValueList<L> &list, const QValueList<L> &pattern )
01083 {
01084   if ( list.count() != pattern.count() )
01085     return false;
01086 
01087   for ( uint i = 0; i < list.count(); ++i )
01088     if ( pattern.find( list[ i ] ) == pattern.end() )
01089       return false;
01090 
01091   return true;
01092 }
01093 
01094 bool emailsEquals( const QStringList &list, const QStringList &pattern )
01095 {
01096   if ( list.count() != pattern.count() )
01097     return false;
01098 
01099   if ( list.first() != pattern.first() )
01100     return false;
01101 
01102   QStringList::ConstIterator it;
01103   for ( it = list.begin(); it != list.end(); ++it )
01104     if ( pattern.find( *it ) == pattern.end() )
01105       return false;
01106 
01107   return true;
01108 }
KDE Home | KDE Accessibility Home | Description of Access Keys