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