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 }