• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • 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   const QString dbusInterface = "org.kde.pim.IdentityManager";
00068   dbus.registerObject( dbusPath, this );
00069   dbus.connect( QString(), dbusPath, dbusInterface, "identitiesChanged", this,
00070                 SLOT( slotIdentitiesChanged( QString ) ) );
00071 
00072   mReadOnly = readonly;
00073   mConfig = new KConfig( "emailidentities" );
00074   readConfig( mConfig );
00075   if ( mIdentities.isEmpty() ) {
00076     kDebug( 5325 ) << "emailidentities is empty -> convert from kmailrc";
00077     // No emailidentities file, or an empty one due to broken conversion
00078     // (kconf_update bug in kdelibs <= 3.2.2)
00079     // => convert it, i.e. read settings from kmailrc
00080     KConfig kmailConf( "kmailrc" );
00081     readConfig( &kmailConf );
00082   }
00083   // we need at least a default identity:
00084   if ( mIdentities.isEmpty() ) {
00085     kDebug( 5325 ) << "IdentityManager: No identity found. Creating default.";
00086     createDefaultIdentity();
00087     commit();
00088   }
00089   // Migration: people without settings in kemailsettings should get some
00090   if ( KEMailSettings().getSetting( KEMailSettings::EmailAddress ).isEmpty() ) {
00091     writeConfig();
00092   }
00093 }
00094 
00095 IdentityManager::~IdentityManager()
00096 {
00097   kWarning( hasPendingChanges(), 5325 )
00098   << "IdentityManager: There were uncommitted changes!";
00099   delete mConfig;
00100 }
00101 
00102 QString IdentityManager::makeUnique( const QString &name ) const
00103 {
00104   int suffix = 1;
00105   QString result = name;
00106   while ( identities().contains( result ) ) {
00107     result = i18nc( "%1: name; %2: number appended to it to make it unique "
00108                     "among a list of names", "%1 #%2",
00109                     name, suffix );
00110     suffix++;
00111   }
00112   return result;
00113 }
00114 
00115 bool IdentityManager::isUnique( const QString &name ) const
00116 {
00117   return !identities().contains( name );
00118 }
00119 
00120 void IdentityManager::commit()
00121 {
00122   // early out:
00123   if ( !hasPendingChanges() || mReadOnly ) {
00124     return;
00125   }
00126 
00127   QList<uint> seenUOIDs;
00128   for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
00129         it != mIdentities.constEnd(); ++it ) {
00130     seenUOIDs << (*it).uoid();
00131   }
00132 
00133   QList<uint> changedUOIDs;
00134   // find added and changed identities:
00135   for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
00136         it != mShadowIdentities.constEnd(); ++it ) {
00137     int index = seenUOIDs.indexOf( (*it).uoid() );
00138     if ( index != -1 ) {
00139       uint uoid = seenUOIDs.at( index );
00140       const Identity &orig = identityForUoid( uoid );  // look up in mIdentities
00141       if ( *it != orig ) {
00142         // changed identity
00143         kDebug( 5325 ) << "emitting changed() for identity" << uoid;
00144         emit changed(*it);
00145         changedUOIDs << uoid;
00146       }
00147       seenUOIDs.removeAll( uoid );
00148     } else {
00149       // new identity
00150       kDebug( 5325 ) << "emitting added() for identity" << (*it).uoid();
00151       emit added(*it);
00152     }
00153   }
00154 
00155   // what's left are deleted identities:
00156   for ( QList<uint>::ConstIterator it = seenUOIDs.constBegin();
00157         it != seenUOIDs.constEnd(); ++it ) {
00158     kDebug( 5325 ) << "emitting deleted() for identity" << (*it);
00159     emit deleted(*it);
00160   }
00161 
00162   mIdentities = mShadowIdentities;
00163   writeConfig();
00164 
00165   // now that mIdentities has all the new info, we can emit the added/changed
00166   // signals that ship a uoid. This is because the slots might use
00167   // identityForUoid(uoid)...
00168   for ( QList<uint>::ConstIterator it = changedUOIDs.constBegin();
00169         it != changedUOIDs.constEnd(); ++it )
00170     emit changed(*it);
00171 
00172   emit changed(); // normal signal
00173 
00174   // DBus signal for other IdentityManager instances
00175   emit identitiesChanged( QDBusConnection::sessionBus().baseService() );
00176 }
00177 
00178 void IdentityManager::rollback()
00179 {
00180   mShadowIdentities = mIdentities;
00181 }
00182 
00183 bool IdentityManager::hasPendingChanges() const
00184 {
00185   return mIdentities != mShadowIdentities;
00186 }
00187 
00188 QStringList IdentityManager::identities() const
00189 {
00190   QStringList result;
00191   for ( ConstIterator it = mIdentities.begin();
00192         it != mIdentities.end(); ++it )
00193     result << (*it).identityName();
00194   return result;
00195 }
00196 
00197 QStringList IdentityManager::shadowIdentities() const
00198 {
00199   QStringList result;
00200   for ( ConstIterator it = mShadowIdentities.begin();
00201         it != mShadowIdentities.end(); ++it )
00202     result << (*it).identityName();
00203   return result;
00204 }
00205 
00206 void IdentityManager::sort()
00207 {
00208   qSort( mShadowIdentities );
00209 }
00210 
00211 void IdentityManager::writeConfig() const
00212 {
00213   const QStringList identities = groupList( mConfig );
00214   for ( QStringList::const_iterator group = identities.begin();
00215         group != identities.end(); ++group )
00216     mConfig->deleteGroup( *group );
00217   int i = 0;
00218   for ( ConstIterator it = mIdentities.begin();
00219         it != mIdentities.end(); ++it, ++i ) {
00220     KConfigGroup cg( mConfig, QString::fromLatin1( "Identity #%1" ).arg( i ) );
00221     (*it).writeConfig( cg );
00222     if ( (*it).isDefault() ) {
00223       // remember which one is default:
00224       KConfigGroup general( mConfig, "General" );
00225       general.writeEntry( configKeyDefaultIdentity, (*it).uoid() );
00226 
00227       // Also write the default identity to emailsettings
00228       KEMailSettings es;
00229       es.setSetting( KEMailSettings::RealName, (*it).fullName() );
00230       es.setSetting( KEMailSettings::EmailAddress, (*it).emailAddr() );
00231       es.setSetting( KEMailSettings::Organization, (*it).organization() );
00232       es.setSetting( KEMailSettings::ReplyToAddress, (*it).replyToAddr() );
00233     }
00234   }
00235   mConfig->sync();
00236 
00237 }
00238 
00239 void IdentityManager::readConfig( KConfig *config )
00240 {
00241   mIdentities.clear();
00242 
00243   const QStringList identities = groupList( config );
00244   if ( identities.isEmpty() ) {
00245     return; // nothing to be done...
00246   }
00247 
00248   KConfigGroup general( config, "General" );
00249   uint defaultIdentity = general.readEntry( configKeyDefaultIdentity, 0 );
00250   bool haveDefault = false;
00251 
00252   for ( QStringList::const_iterator group = identities.begin();
00253         group != identities.end(); ++group ) {
00254     KConfigGroup configGroup( config, *group );
00255     mIdentities << Identity();
00256     mIdentities.last().readConfig( configGroup );
00257     if ( !haveDefault && mIdentities.last().uoid() == defaultIdentity ) {
00258       haveDefault = true;
00259       mIdentities.last().setIsDefault( true );
00260     }
00261   }
00262   if ( !haveDefault ) {
00263     kWarning( 5325 ) << "IdentityManager: There was no default identity."
00264                      << "Marking first one as default.";
00265     mIdentities.first().setIsDefault( true );
00266   }
00267   qSort( mIdentities );
00268 
00269   mShadowIdentities = mIdentities;
00270 }
00271 
00272 QStringList IdentityManager::groupList( KConfig *config ) const
00273 {
00274   return config->groupList().filter( QRegExp( "^Identity #\\d+$" ) );
00275 }
00276 
00277 IdentityManager::ConstIterator IdentityManager::begin() const
00278 {
00279   return mIdentities.begin();
00280 }
00281 
00282 IdentityManager::ConstIterator IdentityManager::end() const
00283 {
00284   return mIdentities.end();
00285 }
00286 
00287 IdentityManager::Iterator IdentityManager::modifyBegin()
00288 {
00289   return mShadowIdentities.begin();
00290 }
00291 
00292 IdentityManager::Iterator IdentityManager::modifyEnd()
00293 {
00294   return mShadowIdentities.end();
00295 }
00296 
00297 const Identity &IdentityManager::identityForUoid( uint uoid ) const
00298 {
00299   for ( ConstIterator it = begin(); it != end(); ++it ) {
00300     if ( (*it).uoid() == uoid ) {
00301       return (*it);
00302     }
00303   }
00304   return Identity::null();
00305 }
00306 
00307 const Identity &IdentityManager::identityForUoidOrDefault( uint uoid ) const
00308 {
00309   const Identity &ident = identityForUoid( uoid );
00310   if ( ident.isNull() ) {
00311     return defaultIdentity();
00312   } else {
00313     return ident;
00314   }
00315 }
00316 
00317 const Identity &IdentityManager::identityForAddress(
00318   const QString &addresses ) const
00319 {
00320   QStringList addressList = KPIMUtils::splitAddressList( addresses );
00321   for ( ConstIterator it = begin(); it != end(); ++it ) {
00322     for ( QStringList::ConstIterator addrIt = addressList.constBegin();
00323           addrIt != addressList.constEnd(); ++addrIt ) {
00324       if ( (*it).emailAddr().toLower() == KPIMUtils::extractEmailAddress( *addrIt ).toLower() ) {
00325         return (*it);
00326       }
00327     }
00328   }
00329   return Identity::null();
00330 }
00331 
00332 bool IdentityManager::thatIsMe( const QString &addressList ) const
00333 {
00334   return !identityForAddress( addressList ).isNull();
00335 }
00336 
00337 Identity &IdentityManager::modifyIdentityForName( const QString &name )
00338 {
00339   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00340     if ( (*it).identityName() == name ) {
00341       return (*it);
00342     }
00343   }
00344 
00345   kWarning( 5325 ) << "IdentityManager::modifyIdentityForName() used as"
00346                    << "newFromScratch() replacement!"
00347                    << endl << "  name == \"" << name << "\"";
00348   return newFromScratch( name );
00349 }
00350 
00351 Identity &IdentityManager::modifyIdentityForUoid( uint uoid )
00352 {
00353   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00354     if ( (*it).uoid() == uoid ) {
00355       return (*it);
00356     }
00357   }
00358 
00359   kWarning( 5325 ) << "IdentityManager::identityForUoid() used as"
00360                    << "newFromScratch() replacement!"
00361                    << endl << "  uoid == \"" << uoid << "\"";
00362   return newFromScratch( i18n( "Unnamed" ) );
00363 }
00364 
00365 const Identity &IdentityManager::defaultIdentity() const
00366 {
00367   for ( ConstIterator it = begin(); it != end(); ++it ) {
00368     if ( (*it).isDefault() ) {
00369       return (*it);
00370     }
00371   }
00372 
00373   if ( mIdentities.isEmpty() )
00374       kFatal( 5325 ) << "IdentityManager: No default identity found!";
00375   else
00376       kWarning( 5325 ) << "IdentityManager: No default identity found!";
00377   return *begin();
00378 }
00379 
00380 bool IdentityManager::setAsDefault( uint uoid )
00381 {
00382   // First, check if the identity actually exists:
00383   bool found = false;
00384   for ( ConstIterator it = mShadowIdentities.constBegin();
00385         it != mShadowIdentities.constEnd(); ++it )
00386     if ( (*it).uoid() == uoid ) {
00387       found = true;
00388       break;
00389     }
00390 
00391   if ( !found ) {
00392     return false;
00393   }
00394 
00395   // Then, change the default as requested:
00396   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00397     (*it).setIsDefault( (*it).uoid() == uoid );
00398   }
00399 
00400   // and re-sort:
00401   sort();
00402   return true;
00403 }
00404 
00405 bool IdentityManager::removeIdentity( const QString &name )
00406 {
00407   if ( mShadowIdentities.size() <= 1 )
00408     return false;
00409 
00410   for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
00411     if ( (*it).identityName() == name ) {
00412       bool removedWasDefault = (*it).isDefault();
00413       mShadowIdentities.erase( it );
00414       if ( removedWasDefault ) {
00415         mShadowIdentities.first().setIsDefault( true );
00416       }
00417       return true;
00418     }
00419   }
00420   return false;
00421 }
00422 
00423 Identity &IdentityManager::newFromScratch( const QString &name )
00424 {
00425   return newFromExisting( Identity( name ) );
00426 }
00427 
00428 Identity &IdentityManager::newFromControlCenter( const QString &name )
00429 {
00430   KEMailSettings es;
00431   es.setProfile( es.defaultProfileName() );
00432 
00433   return
00434     newFromExisting( Identity( name,
00435                                es.getSetting( KEMailSettings::RealName ),
00436                                es.getSetting( KEMailSettings::EmailAddress ),
00437                                es.getSetting( KEMailSettings::Organization ),
00438                                es.getSetting( KEMailSettings::ReplyToAddress ) ) );
00439 }
00440 
00441 Identity &IdentityManager::newFromExisting( const Identity &other,
00442     const QString &name )
00443 {
00444   mShadowIdentities << other;
00445   Identity &result = mShadowIdentities.last();
00446   result.setIsDefault( false );  // we don't want two default identities!
00447   result.setUoid( newUoid() );  // we don't want two identies w/ same UOID
00448   if ( !name.isNull() ) {
00449     result.setIdentityName( name );
00450   }
00451   return result;
00452 }
00453 
00454 void IdentityManager::createDefaultIdentity()
00455 {
00456   QString fullName, emailAddress;
00457   bool done = false;
00458 
00459   // Check if the application has any settings
00460   createDefaultIdentity( fullName, emailAddress );
00461 
00462   // If not, then use the kcontrol settings
00463   if ( fullName.isEmpty() && emailAddress.isEmpty() ) {
00464     KEMailSettings emailSettings;
00465     fullName = emailSettings.getSetting( KEMailSettings::RealName );
00466     emailAddress = emailSettings.getSetting( KEMailSettings::EmailAddress );
00467 
00468     if ( !fullName.isEmpty() && !emailAddress.isEmpty() ) {
00469       newFromControlCenter( i18nc( "use default address from control center",
00470                                    "Default" ) );
00471       done = true;
00472     } else {
00473       // If KEmailSettings doesn't have name and address, generate something from KUser
00474       KUser user;
00475       if ( fullName.isEmpty() ) {
00476         fullName = user.property( KUser::FullName ).toString();
00477       }
00478       if ( emailAddress.isEmpty() ) {
00479         emailAddress = user.loginName();
00480         if ( !emailAddress.isEmpty() ) {
00481           KConfigGroup general( mConfig, "General" );
00482           QString defaultdomain = general.readEntry( "Default domain" );
00483           if ( !defaultdomain.isEmpty() ) {
00484             emailAddress += '@' + defaultdomain;
00485           } else {
00486             emailAddress.clear();
00487           }
00488         }
00489       }
00490     }
00491   }
00492 
00493   if ( !done ) {
00494     // Default identity name
00495     QString name( i18nc( "Default name for new email accounts/identities.", "Unnamed" ) );
00496 
00497     if ( !emailAddress.isEmpty() ) {
00498       // If we have an email address, create a default identity name from it
00499       QString idName = emailAddress;
00500       int pos = idName.indexOf( '@' );
00501       if ( pos != -1 ) {
00502         name = idName.mid( pos + 1, -1 );
00503       }
00504 
00505       // Make the name a bit more human friendly
00506       name.replace( '.', ' ' );
00507       pos = name.indexOf( ' ' );
00508       if ( pos != 0 ) {
00509         name[pos + 1] = name[pos + 1].toUpper();
00510       }
00511       name[0] = name[0].toUpper();
00512     } else if ( !fullName.isEmpty() ) {
00513       // If we have a full name, create a default identity name from it
00514       name = fullName;
00515     }
00516     mShadowIdentities << Identity( name, fullName, emailAddress );
00517   }
00518 
00519   mShadowIdentities.last().setIsDefault( true );
00520   mShadowIdentities.last().setUoid( newUoid() );
00521   if ( mReadOnly ) { // commit won't do it in readonly mode
00522     mIdentities = mShadowIdentities;
00523   }
00524 }
00525 
00526 int IdentityManager::newUoid()
00527 {
00528   int uoid;
00529 
00530   // determine the UOIDs of all saved identities
00531   QList<uint> usedUOIDs;
00532   for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
00533         it != mIdentities.constEnd(); ++it )
00534     usedUOIDs << (*it).uoid();
00535 
00536   if ( hasPendingChanges() ) {
00537     // add UOIDs of all shadow identities. Yes, we will add a lot of duplicate
00538     // UOIDs, but avoiding duplicate UOIDs isn't worth the effort.
00539     for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
00540           it != mShadowIdentities.constEnd(); ++it ) {
00541       usedUOIDs << (*it).uoid();
00542     }
00543   }
00544 
00545   usedUOIDs << 0; // no UOID must be 0 because this value always refers to the
00546   // default identity
00547 
00548   do {
00549     uoid = KRandom::random();
00550   } while ( usedUOIDs.indexOf( uoid ) != -1 );
00551 
00552   return uoid;
00553 }
00554 
00555 QStringList KPIMIdentities::IdentityManager::allEmails() const
00556 {
00557   QStringList lst;
00558   for ( ConstIterator it = begin(); it != end(); ++it ) {
00559     lst << (*it).emailAddr();
00560   }
00561   return lst;
00562 }
00563 
00564 void KPIMIdentities::IdentityManager::slotRollback()
00565 {
00566   rollback();
00567 }
00568 
00569 void KPIMIdentities::IdentityManager::slotIdentitiesChanged( const QString &id )
00570 {
00571   kDebug( 5325 ) <<" KPIMIdentities::IdentityManager::slotIdentitiesChanged :" << id;
00572   if ( id != QDBusConnection::sessionBus().baseService() ) {
00573     mConfig->reparseConfiguration();
00574     Q_ASSERT( !hasPendingChanges() );
00575     readConfig( mConfig );
00576     emit changed();
00577   }
00578 }
00579 
00580 #include "identitymanager.moc"

kpimidentities

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.6.2-20100208
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