summaryrefslogtreecommitdiffstats
path: root/libkpimidentities/identitymanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libkpimidentities/identitymanager.cpp')
-rw-r--r--libkpimidentities/identitymanager.cpp518
1 files changed, 518 insertions, 0 deletions
diff --git a/libkpimidentities/identitymanager.cpp b/libkpimidentities/identitymanager.cpp
new file mode 100644
index 000000000..00f3eae45
--- /dev/null
+++ b/libkpimidentities/identitymanager.cpp
@@ -0,0 +1,518 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ identitymanager.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2002 Marc Mutz <[email protected]>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+// config keys:
+static const char configKeyDefaultIdentity[] = "Default Identity";
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "identitymanager.h"
+
+#include "identity.h" // for IdentityList::{export,import}Data
+#include <libemailfunctions/email.h> // for static helper functions
+
+#include <kemailsettings.h> // for IdentityEntry::fromControlCenter()
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <kuser.h>
+#include <dcopclient.h>
+
+#include <qregexp.h>
+
+#include <assert.h>
+
+using namespace KPIM;
+
+static QCString newDCOPObjectName()
+{
+ static int s_count = 0;
+ QCString name( "KPIM::IdentityManager" );
+ if ( s_count++ ) {
+ name += '-';
+ name += QCString().setNum( s_count );
+ }
+ return name;
+}
+
+IdentityManager::IdentityManager( bool readonly, QObject * parent, const char * name )
+ : ConfigManager( parent, name ), DCOPObject( newDCOPObjectName() )
+{
+ mReadOnly = readonly;
+ mConfig = new KConfig( "emailidentities", readonly );
+ readConfig(mConfig);
+ if ( mIdentities.isEmpty() ) {
+ kdDebug(5006) << "emailidentities is empty -> convert from kmailrc" << endl;
+ // No emailidentities file, or an empty one due to broken conversion (kconf_update bug in kdelibs <= 3.2.2)
+ // => convert it, i.e. read settings from kmailrc
+ KConfig kmailConf( "kmailrc", true );
+ readConfig( &kmailConf );
+ }
+ // we need at least a default identity:
+ if ( mIdentities.isEmpty() ) {
+ kdDebug( 5006 ) << "IdentityManager: No identity found. Creating default." << endl;
+ createDefaultIdentity();
+ commit();
+ }
+ // Migration: people without settings in kemailsettings should get some
+ if ( KEMailSettings().getSetting( KEMailSettings::EmailAddress ).isEmpty() ) {
+ writeConfig();
+ }
+
+ // The emitter is always called KPIM::IdentityManager even if we are not
+ if ( !connectDCOPSignal( 0, "KPIM::IdentityManager", "identitiesChanged(QCString,QCString)",
+ "slotIdentitiesChanged(QCString,QCString)", false ) )
+ kdError(5650) << "IdentityManager: connection to identitiesChanged failed" << endl;
+}
+
+IdentityManager::~IdentityManager()
+{
+ kdWarning( hasPendingChanges(), 5006 )
+ << "IdentityManager: There were uncommitted changes!" << endl;
+ delete mConfig;
+}
+
+void IdentityManager::commit()
+{
+ // early out:
+ if ( !hasPendingChanges() || mReadOnly ) return;
+
+ QValueList<uint> seenUOIDs;
+ for ( QValueList<Identity>::ConstIterator it = mIdentities.begin() ;
+ it != mIdentities.end() ; ++it )
+ seenUOIDs << (*it).uoid();
+
+ QValueList<uint> changedUOIDs;
+ // find added and changed identities:
+ for ( QValueList<Identity>::ConstIterator it = mShadowIdentities.begin() ;
+ it != mShadowIdentities.end() ; ++it ) {
+ QValueList<uint>::Iterator uoid = seenUOIDs.find( (*it).uoid() );
+ if ( uoid != seenUOIDs.end() ) {
+ const Identity & orig = identityForUoid( *uoid ); // look it up in mIdentities
+ if ( *it != orig ) {
+ // changed identity
+ kdDebug( 5006 ) << "emitting changed() for identity " << *uoid << endl;
+ emit changed( *it );
+ changedUOIDs << *uoid;
+ }
+ seenUOIDs.remove( uoid );
+ } else {
+ // new identity
+ kdDebug( 5006 ) << "emitting added() for identity " << (*it).uoid() << endl;
+ emit added( *it );
+ }
+ }
+
+ // what's left are deleted identities:
+ for ( QValueList<uint>::ConstIterator it = seenUOIDs.begin() ;
+ it != seenUOIDs.end() ; ++it ) {
+ kdDebug( 5006 ) << "emitting deleted() for identity " << (*it) << endl;
+ emit deleted( *it );
+ }
+
+ mIdentities = mShadowIdentities;
+ writeConfig();
+
+ // now that mIdentities has all the new info, we can emit the added/changed
+ // signals that ship a uoid. This is because the slots might use identityForUoid(uoid)...
+ for ( QValueList<uint>::ConstIterator it = changedUOIDs.begin() ;
+ it != changedUOIDs.end() ; ++it )
+ emit changed( *it );
+
+ emit ConfigManager::changed(); // normal signal
+
+ // DCOP signal for other IdentityManager instances
+ // The emitter is always set to KPIM::IdentityManager, so that the connect works
+ // This is why we can't use k_dcop_signals here, but need to use emitDCOPSignal
+ QByteArray data; QDataStream arg( data, IO_WriteOnly );
+ arg << kapp->dcopClient()->appId();
+ arg << DCOPObject::objId(); // the real objId, for checking in slotIdentitiesChanged
+ kapp->dcopClient()->emitDCOPSignal( "KPIM::IdentityManager", "identitiesChanged(QCString,QCString)", data );
+}
+
+void IdentityManager::rollback()
+{
+ mShadowIdentities = mIdentities;
+}
+
+bool IdentityManager::hasPendingChanges() const
+{
+ return mIdentities != mShadowIdentities;
+}
+
+QStringList IdentityManager::identities() const
+{
+ QStringList result;
+ for ( ConstIterator it = mIdentities.begin() ;
+ it != mIdentities.end() ; ++it )
+ result << (*it).identityName();
+ return result;
+}
+
+QStringList IdentityManager::shadowIdentities() const
+{
+ QStringList result;
+ for ( ConstIterator it = mShadowIdentities.begin() ;
+ it != mShadowIdentities.end() ; ++it )
+ result << (*it).identityName();
+ return result;
+}
+
+void IdentityManager::sort() {
+ qHeapSort( mShadowIdentities );
+}
+
+void IdentityManager::writeConfig() const {
+ QStringList identities = groupList(mConfig);
+ for ( QStringList::Iterator group = identities.begin() ;
+ group != identities.end() ; ++group )
+ mConfig->deleteGroup( *group );
+ int i = 0;
+ for ( ConstIterator it = mIdentities.begin() ;
+ it != mIdentities.end() ; ++it, ++i ) {
+ KConfigGroup cg( mConfig, QString::fromLatin1("Identity #%1").arg(i) );
+ (*it).writeConfig( &cg );
+ if ( (*it).isDefault() ) {
+ // remember which one is default:
+ KConfigGroup general( mConfig, "General" );
+ general.writeEntry( configKeyDefaultIdentity, (*it).uoid() );
+
+ // Also write the default identity to emailsettings
+ KEMailSettings es;
+ es.setSetting( KEMailSettings::RealName, (*it).fullName() );
+ es.setSetting( KEMailSettings::EmailAddress, (*it).emailAddr() );
+ es.setSetting( KEMailSettings::Organization, (*it).organization() );
+ es.setSetting( KEMailSettings::ReplyToAddress, (*it).replyToAddr() );
+ }
+ }
+ mConfig->sync();
+
+}
+
+void IdentityManager::readConfig(KConfigBase* config) {
+ mIdentities.clear();
+
+ QStringList identities = groupList(config);
+ if ( identities.isEmpty() ) return; // nothing to be done...
+
+ KConfigGroup general( config, "General" );
+ uint defaultIdentity = general.readUnsignedNumEntry( configKeyDefaultIdentity );
+ bool haveDefault = false;
+
+ for ( QStringList::Iterator group = identities.begin() ;
+ group != identities.end() ; ++group ) {
+ KConfigGroup configGroup( config, *group );
+ mIdentities << Identity();
+ mIdentities.last().readConfig( &configGroup );
+ if ( !haveDefault && mIdentities.last().uoid() == defaultIdentity ) {
+ haveDefault = true;
+ mIdentities.last().setIsDefault( true );
+ }
+ }
+ if ( !haveDefault ) {
+ kdWarning( 5006 ) << "IdentityManager: There was no default identity. Marking first one as default." << endl;
+ mIdentities.first().setIsDefault( true );
+ }
+ qHeapSort( mIdentities );
+
+ mShadowIdentities = mIdentities;
+}
+
+QStringList IdentityManager::groupList(KConfigBase* config) const {
+ return config->groupList().grep( QRegExp("^Identity #\\d+$") );
+}
+
+IdentityManager::ConstIterator IdentityManager::begin() const {
+ return mIdentities.begin();
+}
+
+IdentityManager::ConstIterator IdentityManager::end() const {
+ return mIdentities.end();
+}
+
+IdentityManager::Iterator IdentityManager::modifyBegin() {
+ return mShadowIdentities.begin();
+}
+
+IdentityManager::Iterator IdentityManager::modifyEnd() {
+ return mShadowIdentities.end();
+}
+
+const Identity & IdentityManager::identityForName( const QString & name ) const
+{
+ kdWarning( 5006 )
+ << "deprecated method IdentityManager::identityForName() called!" << endl;
+ for ( ConstIterator it = begin() ; it != end() ; ++it )
+ if ( (*it).identityName() == name ) return (*it);
+ return Identity::null();
+}
+
+const Identity & IdentityManager::identityForUoid( uint uoid ) const {
+ for ( ConstIterator it = begin() ; it != end() ; ++it )
+ if ( (*it).uoid() == uoid ) return (*it);
+ return Identity::null();
+}
+
+const Identity & IdentityManager::identityForNameOrDefault( const QString & name ) const
+{
+ const Identity & ident = identityForName( name );
+ if ( ident.isNull() )
+ return defaultIdentity();
+ else
+ return ident;
+}
+
+const Identity & IdentityManager::identityForUoidOrDefault( uint uoid ) const
+{
+ const Identity & ident = identityForUoid( uoid );
+ if ( ident.isNull() )
+ return defaultIdentity();
+ else
+ return ident;
+}
+
+const Identity & IdentityManager::identityForAddress( const QString & addresses ) const
+{
+ QStringList addressList = KPIM::splitEmailAddrList( addresses );
+ for ( ConstIterator it = begin() ; it != end() ; ++it ) {
+ for( QStringList::ConstIterator addrIt = addressList.begin();
+ addrIt != addressList.end(); ++addrIt ) {
+ // I use QString::utf8() instead of QString::latin1() because I want
+ // a QCString and not a char*. It doesn't matter because emailAddr()
+ // returns a 7-bit string.
+ if( (*it).emailAddr().lower() ==
+ KPIM::getEmailAddress( *addrIt ).lower() ) {
+ return (*it);
+ }
+ }
+ }
+ return Identity::null();
+}
+
+bool IdentityManager::thatIsMe( const QString & addressList ) const {
+ return !identityForAddress( addressList ).isNull();
+}
+
+Identity & IdentityManager::modifyIdentityForName( const QString & name )
+{
+ for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
+ if ( (*it).identityName() == name ) return (*it);
+ kdWarning( 5006 ) << "IdentityManager::identityForName() used as newFromScratch() replacement!"
+ << "\n name == \"" << name << "\"" << endl;
+ return newFromScratch( name );
+}
+
+Identity & IdentityManager::modifyIdentityForUoid( uint uoid )
+{
+ for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
+ if ( (*it).uoid() == uoid ) return (*it);
+ kdWarning( 5006 ) << "IdentityManager::identityForUoid() used as newFromScratch() replacement!"
+ << "\n uoid == \"" << uoid << "\"" << endl;
+ return newFromScratch( i18n("Unnamed") );
+}
+
+const Identity & IdentityManager::defaultIdentity() const {
+ for ( ConstIterator it = begin() ; it != end() ; ++it )
+ if ( (*it).isDefault() ) return (*it);
+ (mIdentities.isEmpty() ? kdFatal( 5006 ) : kdWarning( 5006 ) )
+ << "IdentityManager: No default identity found!" << endl;
+ return *begin();
+}
+
+bool IdentityManager::setAsDefault( const QString & name ) {
+ // First, check if the identity actually exists:
+ QStringList names = shadowIdentities();
+ if ( names.find( name ) == names.end() ) return false;
+ // Then, change the default as requested:
+ for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
+ (*it).setIsDefault( (*it).identityName() == name );
+ // and re-sort:
+ sort();
+ return true;
+}
+
+bool IdentityManager::setAsDefault( uint uoid ) {
+ // First, check if the identity actually exists:
+ bool found = false;
+ for ( ConstIterator it = mShadowIdentities.begin() ;
+ it != mShadowIdentities.end() ; ++it )
+ if ( (*it).uoid() == uoid ) {
+ found = true;
+ break;
+ }
+ if ( !found ) return false;
+
+ // Then, change the default as requested:
+ for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
+ (*it).setIsDefault( (*it).uoid() == uoid );
+ // and re-sort:
+ sort();
+ return true;
+}
+
+bool IdentityManager::removeIdentity( const QString & name ) {
+ for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
+ if ( (*it).identityName() == name ) {
+ bool removedWasDefault = (*it).isDefault();
+ mShadowIdentities.remove( it );
+ if ( removedWasDefault )
+ mShadowIdentities.first().setIsDefault( true );
+ return true;
+ }
+ return false;
+}
+
+Identity & IdentityManager::newFromScratch( const QString & name ) {
+ return newFromExisting( Identity( name ) );
+}
+
+Identity & IdentityManager::newFromControlCenter( const QString & name ) {
+ KEMailSettings es;
+ es.setProfile( es.defaultProfileName() );
+
+ return newFromExisting( Identity( name,
+ es.getSetting( KEMailSettings::RealName ),
+ es.getSetting( KEMailSettings::EmailAddress ),
+ es.getSetting( KEMailSettings::Organization ),
+ es.getSetting( KEMailSettings::ReplyToAddress )
+ ) );
+}
+
+Identity & IdentityManager::newFromExisting( const Identity & other,
+ const QString & name ) {
+ mShadowIdentities << other;
+ Identity & result = mShadowIdentities.last();
+ result.setIsDefault( false ); // we don't want two default identities!
+ result.setUoid( newUoid() ); // we don't want two identies w/ same UOID
+ if ( !name.isNull() )
+ result.setIdentityName( name );
+ return result;
+}
+
+void IdentityManager::createDefaultIdentity() {
+ QString fullName, emailAddress;
+ bool done = false;
+
+ // Check if the application has any settings
+ createDefaultIdentity( fullName, emailAddress );
+
+ // If not, then use the kcontrol settings
+ if ( fullName.isEmpty() && emailAddress.isEmpty() ) {
+ KEMailSettings emailSettings;
+ fullName = emailSettings.getSetting( KEMailSettings::RealName );
+ emailAddress = emailSettings.getSetting( KEMailSettings::EmailAddress );
+
+ if ( !fullName.isEmpty() && !emailAddress.isEmpty() ) {
+ newFromControlCenter( i18n("Default") );
+ done = true;
+ } else {
+ // If KEmailSettings doesn't have name and address, generate something from KUser
+ KUser user;
+ if ( fullName.isEmpty() )
+ fullName = user.fullName();
+ if ( emailAddress.isEmpty() ) {
+ emailAddress = user.loginName();
+ if ( !emailAddress.isEmpty() ) {
+ KConfigGroup general( mConfig, "General" );
+ QString defaultdomain = general.readEntry( "Default domain" );
+ if( !defaultdomain.isEmpty() ) {
+ emailAddress += '@' + defaultdomain;
+ }
+ else {
+ emailAddress = QString::null;
+ }
+ }
+ }
+ }
+ }
+
+ if ( !done )
+ mShadowIdentities << Identity( i18n("Default"), fullName, emailAddress );
+
+ mShadowIdentities.last().setIsDefault( true );
+ mShadowIdentities.last().setUoid( newUoid() );
+ if ( mReadOnly ) // commit won't do it in readonly mode
+ mIdentities = mShadowIdentities;
+}
+
+int IdentityManager::newUoid()
+{
+ int uoid;
+
+ // determine the UOIDs of all saved identities
+ QValueList<uint> usedUOIDs;
+ for ( QValueList<Identity>::ConstIterator it = mIdentities.begin() ;
+ it != mIdentities.end() ; ++it )
+ usedUOIDs << (*it).uoid();
+
+ if ( hasPendingChanges() ) {
+ // add UOIDs of all shadow identities. Yes, we will add a lot of duplicate
+ // UOIDs, but avoiding duplicate UOIDs isn't worth the effort.
+ for ( QValueList<Identity>::ConstIterator it = mShadowIdentities.begin() ;
+ it != mShadowIdentities.end() ; ++it ) {
+ usedUOIDs << (*it).uoid();
+ }
+ }
+
+ usedUOIDs << 0; // no UOID must be 0 because this value always refers to the
+ // default identity
+
+ do {
+ uoid = kapp->random();
+ } while ( usedUOIDs.find( uoid ) != usedUOIDs.end() );
+
+ return uoid;
+}
+
+QStringList KPIM::IdentityManager::allEmails() const
+{
+ QStringList lst;
+ for ( ConstIterator it = begin() ; it != end() ; ++it ) {
+ lst << (*it).emailAddr();
+ }
+ return lst;
+}
+
+void KPIM::IdentityManager::slotIdentitiesChanged( QCString appId, QCString objId )
+{
+ // From standalone kmail to standalone korganizer, the appId will differ
+ // From kontact the appId will match, so we need to test the objId
+ if ( kapp->dcopClient()->appId() != appId || DCOPObject::objId() != objId ) {
+ mConfig->reparseConfiguration();
+ Q_ASSERT( !hasPendingChanges() );
+ readConfig( mConfig );
+ }
+}
+
+#include "identitymanager.moc"