• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • 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   for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
00130         it != mIdentities.constEnd(); ++it ) {
00131     seenUOIDs << (*it).uoid();
00132   }
00133 
00134   QList<uint> changedUOIDs;
00135   // find added and changed identities:
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 );  // look up in mIdentities
00142       if ( *it != orig ) {
00143         // changed identity
00144         kDebug( 5325 ) << "emitting changed() for identity" << uoid;
00145         emit changed(*it);
00146         changedUOIDs << uoid;
00147       }
00148       seenUOIDs.removeAll( uoid );
00149     } else {
00150       // new identity
00151       kDebug( 5325 ) << "emitting added() for identity" << (*it).uoid();
00152       emit added(*it);
00153     }
00154   }
00155 
00156   // what's left are deleted identities:
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   // now that mIdentities has all the new info, we can emit the added/changed
00167   // signals that ship a uoid. This is because the slots might use
00168   // identityForUoid(uoid)...
00169   for ( QList<uint>::ConstIterator it = changedUOIDs.constBegin();
00170         it != changedUOIDs.constEnd(); ++it )
00171     emit changed(*it);
00172 
00173   emit changed(); // normal signal
00174 
00175   // DBus signal for other IdentityManager instances
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       // remember which one is default:
00227       KConfigGroup general( mConfig, "General" );
00228       general.writeEntry( configKeyDefaultIdentity, (*it).uoid() );
00229 
00230       // Also write the default identity to emailsettings
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; // nothing to be done...
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   // First, check if the identity actually exists:
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   // Then, change the default as requested:
00399   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00400     (*it).setIsDefault( (*it).uoid() == uoid );
00401   }
00402 
00403   // and re-sort:
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 );  // we don't want two default identities!
00465   result.setUoid( newUoid() );  // we don't want two identies w/ same UOID
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   // Check if the application has any settings
00478   createDefaultIdentity( fullName, emailAddress );
00479 
00480   // If not, then use the kcontrol settings
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       // If KEmailSettings doesn't have name and address, generate something from KUser
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     // Default identity name
00513     QString name( i18nc( "Default name for new email accounts/identities.", "Unnamed" ) );
00514 
00515     if ( !emailAddress.isEmpty() ) {
00516       // If we have an email address, create a default identity name from it
00517       QString idName = emailAddress;
00518       int pos = idName.indexOf( '@' );
00519       if ( pos != -1 ) {
00520         name = idName.mid( pos + 1, -1 );
00521       }
00522 
00523       // Make the name a bit more human friendly
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       // If we have a full name, create a default identity name from it
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 ) { // commit won't do it in readonly mode
00540     mIdentities = mShadowIdentities;
00541   }
00542 }
00543 
00544 int IdentityManager::newUoid()
00545 {
00546   int uoid;
00547 
00548   // determine the UOIDs of all saved identities
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     // add UOIDs of all shadow identities. Yes, we will add a lot of duplicate
00556     // UOIDs, but avoiding duplicate UOIDs isn't worth the effort.
00557     for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
00558           it != mShadowIdentities.constEnd(); ++it ) {
00559       usedUOIDs << (*it).uoid();
00560     }
00561   }
00562 
00563   usedUOIDs << 0; // no UOID must be 0 because this value always refers to the
00564   // default identity
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"

kpimidentities

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • 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
Generated for KDE-PIM Libraries by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal