• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

kpimidentities

identitymanager.cpp
00001 /*
00002     Copyright (c) 2002 Marc Mutz <mutz@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 // config keys:
00021 static const char configKeyDefaultIdentity[] = "Default Identity";
00022 
00023 #include "identitymanager.h"
00024 #include "identity.h" // for IdentityList::{export,import}Data
00025 
00026 #include <kpimutils/email.h> // for static helper functions
00027 
00028 #include <kemailsettings.h> // for IdentityEntry::fromControlCenter()
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     // No emailidentities file, or an empty one due to broken conversion
00079     // (kconf_update bug in kdelibs <= 3.2.2)
00080     // => convert it, i.e. read settings from kmailrc
00081     KConfig kmailConf( "kmailrc" );
00082     readConfig( &kmailConf );
00083   }
00084   // we need at least a default identity:
00085   if ( mIdentities.isEmpty() ) {
00086     kDebug( 5325 ) << "IdentityManager: No identity found. Creating default.";
00087     createDefaultIdentity();
00088     commit();
00089   }
00090   // Migration: people without settings in kemailsettings should get some
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   // early out:
00124   if ( !hasPendingChanges() || mReadOnly ) {
00125     return;
00126   }
00127 
00128   QList<uint> seenUOIDs;
00129   QList<Identity>::ConstIterator end = mIdentities.constEnd();
00130   for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
00131         it != end; ++it ) {
00132     seenUOIDs << (*it).uoid();
00133   }
00134 
00135   QList<uint> changedUOIDs;
00136   // find added and changed identities:
00137   for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
00138         it != mShadowIdentities.constEnd(); ++it ) {
00139     int index = seenUOIDs.indexOf( (*it).uoid() );
00140     if ( index != -1 ) {
00141       uint uoid = seenUOIDs.at( index );
00142       const Identity &orig = identityForUoid( uoid );  // look up in mIdentities
00143       if ( *it != orig ) {
00144         // changed identity
00145         kDebug( 5325 ) << "emitting changed() for identity" << uoid;
00146         emit changed(*it);
00147         changedUOIDs << uoid;
00148       }
00149       seenUOIDs.removeAll( uoid );
00150     } else {
00151       // new identity
00152       kDebug( 5325 ) << "emitting added() for identity" << (*it).uoid();
00153       emit added(*it);
00154     }
00155   }
00156 
00157   // what's left are deleted identities:
00158   for ( QList<uint>::ConstIterator it = seenUOIDs.constBegin();
00159         it != seenUOIDs.constEnd(); ++it ) {
00160     kDebug( 5325 ) << "emitting deleted() for identity" << (*it);
00161     emit deleted(*it);
00162   }
00163 
00164   mIdentities = mShadowIdentities;
00165   writeConfig();
00166 
00167   // now that mIdentities has all the new info, we can emit the added/changed
00168   // signals that ship a uoid. This is because the slots might use
00169   // identityForUoid(uoid)...
00170   QList<uint>::ConstIterator changedEnd( changedUOIDs.constEnd() );
00171   for ( QList<uint>::ConstIterator it = changedUOIDs.constBegin();
00172         it != changedEnd; ++it )
00173     emit changed(*it);
00174 
00175   emit changed(); // normal signal
00176 
00177   // DBus signal for other IdentityManager instances
00178   const QString ourIdentifier = QString::fromLatin1( "%1/%2" ).
00179                                   arg( QDBusConnection::sessionBus().baseService() ).
00180                                   arg( property( "uniqueDBusPath" ).toString() );
00181   emit identitiesChanged( ourIdentifier );
00182 }
00183 
00184 void IdentityManager::rollback()
00185 {
00186   mShadowIdentities = mIdentities;
00187 }
00188 
00189 bool IdentityManager::hasPendingChanges() const
00190 {
00191   return mIdentities != mShadowIdentities;
00192 }
00193 
00194 QStringList IdentityManager::identities() const
00195 {
00196   QStringList result;
00197   ConstIterator end = mIdentities.constEnd();
00198   for ( ConstIterator it = mIdentities.constBegin();
00199         it != end; ++it )
00200     result << (*it).identityName();
00201   return result;
00202 }
00203 
00204 QStringList IdentityManager::shadowIdentities() const
00205 {
00206   QStringList result;
00207   ConstIterator end = mShadowIdentities.constEnd();
00208   for ( ConstIterator it = mShadowIdentities.constBegin();
00209         it != end; ++it )
00210     result << (*it).identityName();
00211   return result;
00212 }
00213 
00214 void IdentityManager::sort()
00215 {
00216   qSort( mShadowIdentities );
00217 }
00218 
00219 void IdentityManager::writeConfig() const
00220 {
00221   const QStringList identities = groupList( mConfig );
00222   QStringList::const_iterator groupEnd = identities.constEnd();
00223   for ( QStringList::const_iterator group = identities.constBegin();
00224         group != groupEnd; ++group )
00225     mConfig->deleteGroup( *group );
00226   int i = 0;
00227   ConstIterator end = mIdentities.constEnd();
00228   for ( ConstIterator it = mIdentities.constBegin();
00229         it != end; ++it, ++i ) {
00230     KConfigGroup cg( mConfig, QString::fromLatin1( "Identity #%1" ).arg( i ) );
00231     (*it).writeConfig( cg );
00232     if ( (*it).isDefault() ) {
00233       // remember which one is default:
00234       KConfigGroup general( mConfig, "General" );
00235       general.writeEntry( configKeyDefaultIdentity, (*it).uoid() );
00236 
00237       // Also write the default identity to emailsettings
00238       KEMailSettings es;
00239       es.setSetting( KEMailSettings::RealName, (*it).fullName() );
00240       es.setSetting( KEMailSettings::EmailAddress, (*it).primaryEmailAddress() );
00241       es.setSetting( KEMailSettings::Organization, (*it).organization() );
00242       es.setSetting( KEMailSettings::ReplyToAddress, (*it).replyToAddr() );
00243     }
00244   }
00245   mConfig->sync();
00246 
00247 }
00248 
00249 void IdentityManager::readConfig( KConfig *config )
00250 {
00251   mIdentities.clear();
00252 
00253   const QStringList identities = groupList( config );
00254   if ( identities.isEmpty() ) {
00255     return; // nothing to be done...
00256   }
00257 
00258   KConfigGroup general( config, "General" );
00259   uint defaultIdentity = general.readEntry( configKeyDefaultIdentity, 0 );
00260   bool haveDefault = false;
00261   QStringList::const_iterator groupEnd = identities.constEnd();
00262   for ( QStringList::const_iterator group = identities.constBegin();
00263         group != groupEnd; ++group ) {
00264     KConfigGroup configGroup( config, *group );
00265     mIdentities << Identity();
00266     mIdentities.last().readConfig( configGroup );
00267     if ( !haveDefault && mIdentities.last().uoid() == defaultIdentity ) {
00268       haveDefault = true;
00269       mIdentities.last().setIsDefault( true );
00270     }
00271   }
00272 
00273   if ( !haveDefault ) {
00274     kWarning( 5325 ) << "IdentityManager: There was no default identity."
00275                      << "Marking first one as default.";
00276     mIdentities.first().setIsDefault( true );
00277   }
00278   qSort( mIdentities );
00279 
00280   mShadowIdentities = mIdentities;
00281 }
00282 
00283 QStringList IdentityManager::groupList( KConfig *config ) const
00284 {
00285   return config->groupList().filter( QRegExp( "^Identity #\\d+$" ) );
00286 }
00287 
00288 IdentityManager::ConstIterator IdentityManager::begin() const
00289 {
00290   return mIdentities.begin();
00291 }
00292 
00293 IdentityManager::ConstIterator IdentityManager::end() const
00294 {
00295   return mIdentities.end();
00296 }
00297 
00298 IdentityManager::Iterator IdentityManager::modifyBegin()
00299 {
00300   return mShadowIdentities.begin();
00301 }
00302 
00303 IdentityManager::Iterator IdentityManager::modifyEnd()
00304 {
00305   return mShadowIdentities.end();
00306 }
00307 
00308 const Identity &IdentityManager::identityForUoid( uint uoid ) const
00309 {
00310   for ( ConstIterator it = begin(); it != end(); ++it ) {
00311     if ( (*it).uoid() == uoid ) {
00312       return (*it);
00313     }
00314   }
00315   return Identity::null();
00316 }
00317 
00318 const Identity &IdentityManager::identityForUoidOrDefault( uint uoid ) const
00319 {
00320   const Identity &ident = identityForUoid( uoid );
00321   if ( ident.isNull() ) {
00322     return defaultIdentity();
00323   } else {
00324     return ident;
00325   }
00326 }
00327 
00328 const Identity &IdentityManager::identityForAddress(
00329   const QString &addresses ) const
00330 {
00331   const QStringList addressList = KPIMUtils::splitAddressList( addresses );
00332   foreach ( const QString &fullAddress, addressList ) {
00333     const QString addrSpec = KPIMUtils::extractEmailAddress( fullAddress ).toLower();
00334     for ( ConstIterator it = begin(); it != end(); ++it ) {
00335       const Identity &identity = *it;
00336       if ( identity.matchesEmailAddress( addrSpec ) ) {
00337         return identity;
00338       }
00339     }
00340   }
00341   return Identity::null();
00342 }
00343 
00344 bool IdentityManager::thatIsMe( const QString &addressList ) const
00345 {
00346   return !identityForAddress( addressList ).isNull();
00347 }
00348 
00349 Identity &IdentityManager::modifyIdentityForName( const QString &name )
00350 {
00351   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00352     if ( (*it).identityName() == name ) {
00353       return (*it);
00354     }
00355   }
00356 
00357   kWarning( 5325 ) << "IdentityManager::modifyIdentityForName() used as"
00358                    << "newFromScratch() replacement!"
00359                    << endl << "  name == \"" << name << "\"";
00360   return newFromScratch( name );
00361 }
00362 
00363 Identity &IdentityManager::modifyIdentityForUoid( uint uoid )
00364 {
00365   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00366     if ( (*it).uoid() == uoid ) {
00367       return (*it);
00368     }
00369   }
00370 
00371   kWarning( 5325 ) << "IdentityManager::identityForUoid() used as"
00372                    << "newFromScratch() replacement!"
00373                    << endl << "  uoid == \"" << uoid << "\"";
00374   return newFromScratch( i18n( "Unnamed" ) );
00375 }
00376 
00377 const Identity &IdentityManager::defaultIdentity() const
00378 {
00379   for ( ConstIterator it = begin(); it != end(); ++it ) {
00380     if ( (*it).isDefault() ) {
00381       return (*it);
00382     }
00383   }
00384 
00385   if ( mIdentities.isEmpty() ) {
00386     kFatal( 5325 ) << "IdentityManager: No default identity found!";
00387   } else {
00388     kWarning( 5325 ) << "IdentityManager: No default identity found!";
00389   }
00390   return *begin();
00391 }
00392 
00393 bool IdentityManager::setAsDefault( uint uoid )
00394 {
00395   // First, check if the identity actually exists:
00396   bool found = false;
00397   for ( ConstIterator it = mShadowIdentities.constBegin();
00398         it != mShadowIdentities.constEnd(); ++it )
00399     if ( (*it).uoid() == uoid ) {
00400       found = true;
00401       break;
00402     }
00403 
00404   if ( !found ) {
00405     return false;
00406   }
00407 
00408   // Then, change the default as requested:
00409   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00410     (*it).setIsDefault( (*it).uoid() == uoid );
00411   }
00412 
00413   // and re-sort:
00414   sort();
00415   return true;
00416 }
00417 
00418 bool IdentityManager::removeIdentity( const QString &name )
00419 {
00420   if ( mShadowIdentities.size() <= 1 ) {
00421     return false;
00422   }
00423 
00424   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00425     if ( (*it).identityName() == name ) {
00426       bool removedWasDefault = (*it).isDefault();
00427       mShadowIdentities.erase( it );
00428       if ( removedWasDefault && !mShadowIdentities.isEmpty() ) {
00429         mShadowIdentities.first().setIsDefault( true );
00430       }
00431       return true;
00432     }
00433   }
00434   return false;
00435 }
00436 
00437 bool IdentityManager::removeIdentityForced( const QString &name )
00438 {
00439   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00440     if ( (*it).identityName() == name ) {
00441       bool removedWasDefault = (*it).isDefault();
00442       mShadowIdentities.erase( it );
00443       if ( removedWasDefault && !mShadowIdentities.isEmpty() ) {
00444         mShadowIdentities.first().setIsDefault( true );
00445       }
00446       return true;
00447     }
00448   }
00449   return false;
00450 }
00451 
00452 Identity &IdentityManager::newFromScratch( const QString &name )
00453 {
00454   return newFromExisting( Identity( name ) );
00455 }
00456 
00457 Identity &IdentityManager::newFromControlCenter( const QString &name )
00458 {
00459   KEMailSettings es;
00460   es.setProfile( es.defaultProfileName() );
00461 
00462   return
00463     newFromExisting( Identity( name,
00464                                es.getSetting( KEMailSettings::RealName ),
00465                                es.getSetting( KEMailSettings::EmailAddress ),
00466                                es.getSetting( KEMailSettings::Organization ),
00467                                es.getSetting( KEMailSettings::ReplyToAddress ) ) );
00468 }
00469 
00470 Identity &IdentityManager::newFromExisting( const Identity &other, const QString &name )
00471 {
00472   mShadowIdentities << other;
00473   Identity &result = mShadowIdentities.last();
00474   result.setIsDefault( false );  // we don't want two default identities!
00475   result.setUoid( newUoid() );  // we don't want two identies w/ same UOID
00476   if ( !name.isNull() ) {
00477     result.setIdentityName( name );
00478   }
00479   return result;
00480 }
00481 
00482 void IdentityManager::createDefaultIdentity()
00483 {
00484   QString fullName, emailAddress;
00485   bool done = false;
00486 
00487   // Check if the application has any settings
00488   createDefaultIdentity( fullName, emailAddress );
00489 
00490   // If not, then use the kcontrol settings
00491   if ( fullName.isEmpty() && emailAddress.isEmpty() ) {
00492     KEMailSettings emailSettings;
00493     fullName = emailSettings.getSetting( KEMailSettings::RealName );
00494     emailAddress = emailSettings.getSetting( KEMailSettings::EmailAddress );
00495 
00496     if ( !fullName.isEmpty() && !emailAddress.isEmpty() ) {
00497       newFromControlCenter( i18nc( "use default address from control center",
00498                                    "Default" ) );
00499       done = true;
00500     } else {
00501       // If KEmailSettings doesn't have name and address, generate something from KUser
00502       KUser user;
00503       if ( fullName.isEmpty() ) {
00504         fullName = user.property( KUser::FullName ).toString();
00505       }
00506       if ( emailAddress.isEmpty() ) {
00507         emailAddress = user.loginName();
00508         if ( !emailAddress.isEmpty() ) {
00509           KConfigGroup general( mConfig, "General" );
00510           QString defaultdomain = general.readEntry( "Default domain" );
00511           if ( !defaultdomain.isEmpty() ) {
00512             emailAddress += '@' + defaultdomain;
00513           } else {
00514             emailAddress.clear();
00515           }
00516         }
00517       }
00518     }
00519   }
00520 
00521   if ( !done ) {
00522     // Default identity name
00523     QString name( i18nc( "Default name for new email accounts/identities.", "Unnamed" ) );
00524 
00525     if ( !emailAddress.isEmpty() ) {
00526       // If we have an email address, create a default identity name from it
00527       QString idName = emailAddress;
00528       int pos = idName.indexOf( '@' );
00529       if ( pos != -1 ) {
00530         name = idName.mid( pos + 1, -1 );
00531       }
00532 
00533       // Make the name a bit more human friendly
00534       name.replace( '.', ' ' );
00535       pos = name.indexOf( ' ' );
00536       if ( pos != 0 ) {
00537         name[pos + 1] = name[pos + 1].toUpper();
00538       }
00539       name[0] = name[0].toUpper();
00540     } else if ( !fullName.isEmpty() ) {
00541       // If we have a full name, create a default identity name from it
00542       name = fullName;
00543     }
00544     mShadowIdentities << Identity( name, fullName, emailAddress );
00545   }
00546 
00547   mShadowIdentities.last().setIsDefault( true );
00548   mShadowIdentities.last().setUoid( newUoid() );
00549   if ( mReadOnly ) { // commit won't do it in readonly mode
00550     mIdentities = mShadowIdentities;
00551   }
00552 }
00553 
00554 int IdentityManager::newUoid()
00555 {
00556   int uoid;
00557 
00558   // determine the UOIDs of all saved identities
00559   QList<uint> usedUOIDs;
00560   for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
00561         it != mIdentities.constEnd(); ++it )
00562     usedUOIDs << (*it).uoid();
00563 
00564   if ( hasPendingChanges() ) {
00565     // add UOIDs of all shadow identities. Yes, we will add a lot of duplicate
00566     // UOIDs, but avoiding duplicate UOIDs isn't worth the effort.
00567     for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
00568           it != mShadowIdentities.constEnd(); ++it ) {
00569       usedUOIDs << (*it).uoid();
00570     }
00571   }
00572 
00573   usedUOIDs << 0; // no UOID must be 0 because this value always refers to the
00574   // default identity
00575 
00576   do {
00577     uoid = KRandom::random();
00578   } while ( usedUOIDs.indexOf( uoid ) != -1 );
00579 
00580   return uoid;
00581 }
00582 
00583 QStringList KPIMIdentities::IdentityManager::allEmails() const
00584 {
00585   QStringList lst;
00586   for ( ConstIterator it = begin(); it != end(); ++it ) {
00587     lst << (*it).primaryEmailAddress();
00588     if ( !(*it).emailAliases().isEmpty() ) {
00589       lst << (*it).emailAliases();
00590     }
00591   }
00592   return lst;
00593 }
00594 
00595 void KPIMIdentities::IdentityManager::slotRollback()
00596 {
00597   rollback();
00598 }
00599 
00600 void KPIMIdentities::IdentityManager::slotIdentitiesChanged( const QString &id )
00601 {
00602   kDebug( 5325 ) <<" KPIMIdentities::IdentityManager::slotIdentitiesChanged :" << id;
00603   const QString ourIdentifier = QString::fromLatin1( "%1/%2" ).
00604                                   arg( QDBusConnection::sessionBus().baseService() ).
00605                                   arg( property( "uniqueDBusPath" ).toString() );
00606   if ( id != ourIdentifier ) {
00607     mConfig->reparseConfiguration();
00608     Q_ASSERT( !hasPendingChanges() );
00609     readConfig( mConfig );
00610     emit changed();
00611   }
00612 }
00613 
00614 #include "identitymanager.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue May 8 2012 00:09:57 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kpimidentities

Skip menu "kpimidentities"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal