00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 static const char configKeyDefaultIdentity[] = "Default Identity";
00022
00023 #include "identitymanager.h"
00024 #include "identity.h"
00025
00026 #include <kpimutils/email.h>
00027
00028 #include <kemailsettings.h>
00029 #include <klocale.h>
00030 #include <kglobal.h>
00031 #include <kdebug.h>
00032 #include <kconfig.h>
00033 #include <kuser.h>
00034 #include <kconfiggroup.h>
00035
00036 #include <QList>
00037 #include <QRegExp>
00038 #include <QtDBus/QtDBus>
00039
00040 #include <assert.h>
00041 #include <krandom.h>
00042
00043 #include "identitymanageradaptor.h"
00044
00045 using namespace KPIMIdentities;
00046
00047 static QString newDBusObjectName()
00048 {
00049 static int s_count = 0;
00050 QString name( "/KPIMIDENTITIES_IdentityManager" );
00051 if ( s_count++ ) {
00052 name += '_';
00053 name += QString::number( s_count );
00054 }
00055 return name;
00056 }
00057
00058 IdentityManager::IdentityManager( bool readonly, QObject *parent,
00059 const char *name )
00060 : QObject( parent )
00061 {
00062 setObjectName( name );
00063 KGlobal::locale()->insertCatalog("libkpimidentities");
00064 new IdentityManagerAdaptor( this );
00065 QDBusConnection dbus = QDBusConnection::sessionBus();
00066 const QString dbusPath = newDBusObjectName();
00067 setProperty( "uniqueDBusPath", dbusPath );
00068 const QString dbusInterface = "org.kde.pim.IdentityManager";
00069 dbus.registerObject( dbusPath, this );
00070 dbus.connect( QString(), QString(), dbusInterface, "identitiesChanged", this,
00071 SLOT( slotIdentitiesChanged( QString ) ) );
00072
00073 mReadOnly = readonly;
00074 mConfig = new KConfig( "emailidentities" );
00075 readConfig( mConfig );
00076 if ( mIdentities.isEmpty() ) {
00077 kDebug( 5325 ) << "emailidentities is empty -> convert from kmailrc";
00078
00079
00080
00081 KConfig kmailConf( "kmailrc" );
00082 readConfig( &kmailConf );
00083 }
00084
00085 if ( mIdentities.isEmpty() ) {
00086 kDebug( 5325 ) << "IdentityManager: No identity found. Creating default.";
00087 createDefaultIdentity();
00088 commit();
00089 }
00090
00091 if ( KEMailSettings().getSetting( KEMailSettings::EmailAddress ).isEmpty() ) {
00092 writeConfig();
00093 }
00094 }
00095
00096 IdentityManager::~IdentityManager()
00097 {
00098 kWarning( hasPendingChanges(), 5325 )
00099 << "IdentityManager: There were uncommitted changes!";
00100 delete mConfig;
00101 }
00102
00103 QString IdentityManager::makeUnique( const QString &name ) const
00104 {
00105 int suffix = 1;
00106 QString result = name;
00107 while ( identities().contains( result ) ) {
00108 result = i18nc( "%1: name; %2: number appended to it to make it unique "
00109 "among a list of names", "%1 #%2",
00110 name, suffix );
00111 suffix++;
00112 }
00113 return result;
00114 }
00115
00116 bool IdentityManager::isUnique( const QString &name ) const
00117 {
00118 return !identities().contains( name );
00119 }
00120
00121 void IdentityManager::commit()
00122 {
00123
00124 if ( !hasPendingChanges() || mReadOnly ) {
00125 return;
00126 }
00127
00128 QList<uint> seenUOIDs;
00129 for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
00130 it != mIdentities.constEnd(); ++it ) {
00131 seenUOIDs << (*it).uoid();
00132 }
00133
00134 QList<uint> changedUOIDs;
00135
00136 for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
00137 it != mShadowIdentities.constEnd(); ++it ) {
00138 int index = seenUOIDs.indexOf( (*it).uoid() );
00139 if ( index != -1 ) {
00140 uint uoid = seenUOIDs.at( index );
00141 const Identity &orig = identityForUoid( uoid );
00142 if ( *it != orig ) {
00143
00144 kDebug( 5325 ) << "emitting changed() for identity" << uoid;
00145 emit changed(*it);
00146 changedUOIDs << uoid;
00147 }
00148 seenUOIDs.removeAll( uoid );
00149 } else {
00150
00151 kDebug( 5325 ) << "emitting added() for identity" << (*it).uoid();
00152 emit added(*it);
00153 }
00154 }
00155
00156
00157 for ( QList<uint>::ConstIterator it = seenUOIDs.constBegin();
00158 it != seenUOIDs.constEnd(); ++it ) {
00159 kDebug( 5325 ) << "emitting deleted() for identity" << (*it);
00160 emit deleted(*it);
00161 }
00162
00163 mIdentities = mShadowIdentities;
00164 writeConfig();
00165
00166
00167
00168
00169 for ( QList<uint>::ConstIterator it = changedUOIDs.constBegin();
00170 it != changedUOIDs.constEnd(); ++it )
00171 emit changed(*it);
00172
00173 emit changed();
00174
00175
00176 const QString ourIdentifier = QString::fromLatin1( "%1/%2" ).arg( QDBusConnection::sessionBus().baseService() )
00177 .arg( property( "uniqueDBusPath" ).toString() );
00178 emit identitiesChanged( ourIdentifier );
00179 }
00180
00181 void IdentityManager::rollback()
00182 {
00183 mShadowIdentities = mIdentities;
00184 }
00185
00186 bool IdentityManager::hasPendingChanges() const
00187 {
00188 return mIdentities != mShadowIdentities;
00189 }
00190
00191 QStringList IdentityManager::identities() const
00192 {
00193 QStringList result;
00194 for ( ConstIterator it = mIdentities.begin();
00195 it != mIdentities.end(); ++it )
00196 result << (*it).identityName();
00197 return result;
00198 }
00199
00200 QStringList IdentityManager::shadowIdentities() const
00201 {
00202 QStringList result;
00203 for ( ConstIterator it = mShadowIdentities.begin();
00204 it != mShadowIdentities.end(); ++it )
00205 result << (*it).identityName();
00206 return result;
00207 }
00208
00209 void IdentityManager::sort()
00210 {
00211 qSort( mShadowIdentities );
00212 }
00213
00214 void IdentityManager::writeConfig() const
00215 {
00216 const QStringList identities = groupList( mConfig );
00217 for ( QStringList::const_iterator group = identities.begin();
00218 group != identities.end(); ++group )
00219 mConfig->deleteGroup( *group );
00220 int i = 0;
00221 for ( ConstIterator it = mIdentities.begin();
00222 it != mIdentities.end(); ++it, ++i ) {
00223 KConfigGroup cg( mConfig, QString::fromLatin1( "Identity #%1" ).arg( i ) );
00224 (*it).writeConfig( cg );
00225 if ( (*it).isDefault() ) {
00226
00227 KConfigGroup general( mConfig, "General" );
00228 general.writeEntry( configKeyDefaultIdentity, (*it).uoid() );
00229
00230
00231 KEMailSettings es;
00232 es.setSetting( KEMailSettings::RealName, (*it).fullName() );
00233 es.setSetting( KEMailSettings::EmailAddress, (*it).primaryEmailAddress() );
00234 es.setSetting( KEMailSettings::Organization, (*it).organization() );
00235 es.setSetting( KEMailSettings::ReplyToAddress, (*it).replyToAddr() );
00236 }
00237 }
00238 mConfig->sync();
00239
00240 }
00241
00242 void IdentityManager::readConfig( KConfig *config )
00243 {
00244 mIdentities.clear();
00245
00246 const QStringList identities = groupList( config );
00247 if ( identities.isEmpty() ) {
00248 return;
00249 }
00250
00251 KConfigGroup general( config, "General" );
00252 uint defaultIdentity = general.readEntry( configKeyDefaultIdentity, 0 );
00253 bool haveDefault = false;
00254
00255 for ( QStringList::const_iterator group = identities.begin();
00256 group != identities.end(); ++group ) {
00257 KConfigGroup configGroup( config, *group );
00258 mIdentities << Identity();
00259 mIdentities.last().readConfig( configGroup );
00260 if ( !haveDefault && mIdentities.last().uoid() == defaultIdentity ) {
00261 haveDefault = true;
00262 mIdentities.last().setIsDefault( true );
00263 }
00264 }
00265 if ( !haveDefault ) {
00266 kWarning( 5325 ) << "IdentityManager: There was no default identity."
00267 << "Marking first one as default.";
00268 mIdentities.first().setIsDefault( true );
00269 }
00270 qSort( mIdentities );
00271
00272 mShadowIdentities = mIdentities;
00273 }
00274
00275 QStringList IdentityManager::groupList( KConfig *config ) const
00276 {
00277 return config->groupList().filter( QRegExp( "^Identity #\\d+$" ) );
00278 }
00279
00280 IdentityManager::ConstIterator IdentityManager::begin() const
00281 {
00282 return mIdentities.begin();
00283 }
00284
00285 IdentityManager::ConstIterator IdentityManager::end() const
00286 {
00287 return mIdentities.end();
00288 }
00289
00290 IdentityManager::Iterator IdentityManager::modifyBegin()
00291 {
00292 return mShadowIdentities.begin();
00293 }
00294
00295 IdentityManager::Iterator IdentityManager::modifyEnd()
00296 {
00297 return mShadowIdentities.end();
00298 }
00299
00300 const Identity &IdentityManager::identityForUoid( uint uoid ) const
00301 {
00302 for ( ConstIterator it = begin(); it != end(); ++it ) {
00303 if ( (*it).uoid() == uoid ) {
00304 return (*it);
00305 }
00306 }
00307 return Identity::null();
00308 }
00309
00310 const Identity &IdentityManager::identityForUoidOrDefault( uint uoid ) const
00311 {
00312 const Identity &ident = identityForUoid( uoid );
00313 if ( ident.isNull() ) {
00314 return defaultIdentity();
00315 } else {
00316 return ident;
00317 }
00318 }
00319
00320 const Identity &IdentityManager::identityForAddress(
00321 const QString &addresses ) const
00322 {
00323 const QStringList addressList = KPIMUtils::splitAddressList( addresses );
00324 foreach ( const QString &fullAddress, addressList ) {
00325 const QString addrSpec = KPIMUtils::extractEmailAddress( fullAddress ).toLower();
00326 for ( ConstIterator it = begin(); it != end(); ++it ) {
00327 const Identity &identity = *it;
00328 if ( identity.matchesEmailAddress( addrSpec ) )
00329 return identity;
00330 }
00331 }
00332 return Identity::null();
00333 }
00334
00335 bool IdentityManager::thatIsMe( const QString &addressList ) const
00336 {
00337 return !identityForAddress( addressList ).isNull();
00338 }
00339
00340 Identity &IdentityManager::modifyIdentityForName( const QString &name )
00341 {
00342 for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00343 if ( (*it).identityName() == name ) {
00344 return (*it);
00345 }
00346 }
00347
00348 kWarning( 5325 ) << "IdentityManager::modifyIdentityForName() used as"
00349 << "newFromScratch() replacement!"
00350 << endl << " name == \"" << name << "\"";
00351 return newFromScratch( name );
00352 }
00353
00354 Identity &IdentityManager::modifyIdentityForUoid( uint uoid )
00355 {
00356 for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00357 if ( (*it).uoid() == uoid ) {
00358 return (*it);
00359 }
00360 }
00361
00362 kWarning( 5325 ) << "IdentityManager::identityForUoid() used as"
00363 << "newFromScratch() replacement!"
00364 << endl << " uoid == \"" << uoid << "\"";
00365 return newFromScratch( i18n( "Unnamed" ) );
00366 }
00367
00368 const Identity &IdentityManager::defaultIdentity() const
00369 {
00370 for ( ConstIterator it = begin(); it != end(); ++it ) {
00371 if ( (*it).isDefault() ) {
00372 return (*it);
00373 }
00374 }
00375
00376 if ( mIdentities.isEmpty() )
00377 kFatal( 5325 ) << "IdentityManager: No default identity found!";
00378 else
00379 kWarning( 5325 ) << "IdentityManager: No default identity found!";
00380 return *begin();
00381 }
00382
00383 bool IdentityManager::setAsDefault( uint uoid )
00384 {
00385
00386 bool found = false;
00387 for ( ConstIterator it = mShadowIdentities.constBegin();
00388 it != mShadowIdentities.constEnd(); ++it )
00389 if ( (*it).uoid() == uoid ) {
00390 found = true;
00391 break;
00392 }
00393
00394 if ( !found ) {
00395 return false;
00396 }
00397
00398
00399 for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00400 (*it).setIsDefault( (*it).uoid() == uoid );
00401 }
00402
00403
00404 sort();
00405 return true;
00406 }
00407
00408 bool IdentityManager::removeIdentity( const QString &name )
00409 {
00410 if ( mShadowIdentities.size() <= 1 )
00411 return false;
00412
00413 for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00414 if ( (*it).identityName() == name ) {
00415 bool removedWasDefault = (*it).isDefault();
00416 mShadowIdentities.erase( it );
00417 if ( removedWasDefault ) {
00418 mShadowIdentities.first().setIsDefault( true );
00419 }
00420 return true;
00421 }
00422 }
00423 return false;
00424 }
00425
00426 bool IdentityManager::removeIdentityForced( const QString &name )
00427 {
00428 for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00429 if ( (*it).identityName() == name ) {
00430 bool removedWasDefault = (*it).isDefault();
00431 mShadowIdentities.erase( it );
00432 if ( removedWasDefault && !mShadowIdentities.isEmpty() ) {
00433 mShadowIdentities.first().setIsDefault( true );
00434 }
00435 return true;
00436 }
00437 }
00438 return false;
00439 }
00440
00441 Identity &IdentityManager::newFromScratch( const QString &name )
00442 {
00443 return newFromExisting( Identity( name ) );
00444 }
00445
00446 Identity &IdentityManager::newFromControlCenter( const QString &name )
00447 {
00448 KEMailSettings es;
00449 es.setProfile( es.defaultProfileName() );
00450
00451 return
00452 newFromExisting( Identity( name,
00453 es.getSetting( KEMailSettings::RealName ),
00454 es.getSetting( KEMailSettings::EmailAddress ),
00455 es.getSetting( KEMailSettings::Organization ),
00456 es.getSetting( KEMailSettings::ReplyToAddress ) ) );
00457 }
00458
00459 Identity &IdentityManager::newFromExisting( const Identity &other,
00460 const QString &name )
00461 {
00462 mShadowIdentities << other;
00463 Identity &result = mShadowIdentities.last();
00464 result.setIsDefault( false );
00465 result.setUoid( newUoid() );
00466 if ( !name.isNull() ) {
00467 result.setIdentityName( name );
00468 }
00469 return result;
00470 }
00471
00472 void IdentityManager::createDefaultIdentity()
00473 {
00474 QString fullName, emailAddress;
00475 bool done = false;
00476
00477
00478 createDefaultIdentity( fullName, emailAddress );
00479
00480
00481 if ( fullName.isEmpty() && emailAddress.isEmpty() ) {
00482 KEMailSettings emailSettings;
00483 fullName = emailSettings.getSetting( KEMailSettings::RealName );
00484 emailAddress = emailSettings.getSetting( KEMailSettings::EmailAddress );
00485
00486 if ( !fullName.isEmpty() && !emailAddress.isEmpty() ) {
00487 newFromControlCenter( i18nc( "use default address from control center",
00488 "Default" ) );
00489 done = true;
00490 } else {
00491
00492 KUser user;
00493 if ( fullName.isEmpty() ) {
00494 fullName = user.property( KUser::FullName ).toString();
00495 }
00496 if ( emailAddress.isEmpty() ) {
00497 emailAddress = user.loginName();
00498 if ( !emailAddress.isEmpty() ) {
00499 KConfigGroup general( mConfig, "General" );
00500 QString defaultdomain = general.readEntry( "Default domain" );
00501 if ( !defaultdomain.isEmpty() ) {
00502 emailAddress += '@' + defaultdomain;
00503 } else {
00504 emailAddress.clear();
00505 }
00506 }
00507 }
00508 }
00509 }
00510
00511 if ( !done ) {
00512
00513 QString name( i18nc( "Default name for new email accounts/identities.", "Unnamed" ) );
00514
00515 if ( !emailAddress.isEmpty() ) {
00516
00517 QString idName = emailAddress;
00518 int pos = idName.indexOf( '@' );
00519 if ( pos != -1 ) {
00520 name = idName.mid( pos + 1, -1 );
00521 }
00522
00523
00524 name.replace( '.', ' ' );
00525 pos = name.indexOf( ' ' );
00526 if ( pos != 0 ) {
00527 name[pos + 1] = name[pos + 1].toUpper();
00528 }
00529 name[0] = name[0].toUpper();
00530 } else if ( !fullName.isEmpty() ) {
00531
00532 name = fullName;
00533 }
00534 mShadowIdentities << Identity( name, fullName, emailAddress );
00535 }
00536
00537 mShadowIdentities.last().setIsDefault( true );
00538 mShadowIdentities.last().setUoid( newUoid() );
00539 if ( mReadOnly ) {
00540 mIdentities = mShadowIdentities;
00541 }
00542 }
00543
00544 int IdentityManager::newUoid()
00545 {
00546 int uoid;
00547
00548
00549 QList<uint> usedUOIDs;
00550 for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
00551 it != mIdentities.constEnd(); ++it )
00552 usedUOIDs << (*it).uoid();
00553
00554 if ( hasPendingChanges() ) {
00555
00556
00557 for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
00558 it != mShadowIdentities.constEnd(); ++it ) {
00559 usedUOIDs << (*it).uoid();
00560 }
00561 }
00562
00563 usedUOIDs << 0;
00564
00565
00566 do {
00567 uoid = KRandom::random();
00568 } while ( usedUOIDs.indexOf( uoid ) != -1 );
00569
00570 return uoid;
00571 }
00572
00573 QStringList KPIMIdentities::IdentityManager::allEmails() const
00574 {
00575 QStringList lst;
00576 for ( ConstIterator it = begin(); it != end(); ++it ) {
00577 lst << (*it).primaryEmailAddress();
00578 if ( !(*it).emailAliases().isEmpty() )
00579 lst << (*it).emailAliases();
00580 }
00581 return lst;
00582 }
00583
00584 void KPIMIdentities::IdentityManager::slotRollback()
00585 {
00586 rollback();
00587 }
00588
00589 void KPIMIdentities::IdentityManager::slotIdentitiesChanged( const QString &id )
00590 {
00591 kDebug( 5325 ) <<" KPIMIdentities::IdentityManager::slotIdentitiesChanged :" << id;
00592 const QString ourIdentifier = QString::fromLatin1( "%1/%2" ).arg( QDBusConnection::sessionBus().baseService() )
00593 .arg( property( "uniqueDBusPath" ).toString() );
00594 if ( id != ourIdentifier ) {
00595 mConfig->reparseConfiguration();
00596 Q_ASSERT( !hasPendingChanges() );
00597 readConfig( mConfig );
00598 emit changed();
00599 }
00600 }
00601
00602 #include "identitymanager.moc"