kmail Library API Documentation

identitymanager.cpp

00001 /*  -*- mode: C++; c-file-style: "gnu" -*-
00002     identitymanager.cpp
00003 
00004     This file is part of KMail, the KDE mail client.
00005     Copyright (c) 2002 Marc Mutz <mutz@kde.org>
00006 
00007     KMail is free software; you can redistribute it and/or modify it
00008     under the terms of the GNU General Public License, version 2, as
00009     published by the Free Software Foundation.
00010 
00011     KMail is distributed in the hope that it will be useful, but
00012     WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020     In addition, as a special exception, the copyright holders give
00021     permission to link the code of this program with any edition of
00022     the Qt library by Trolltech AS, Norway (or with modified versions
00023     of Qt that use the same license as Qt), and distribute linked
00024     combinations including the two.  You must obey the GNU General
00025     Public License in all respects for all of the code used other than
00026     Qt.  If you modify this file, you may extend this exception to
00027     your version of the file, but you are not obligated to do so.  If
00028     you do not wish to do so, delete this exception statement from
00029     your version.
00030 */
00031 
00032 // config keys:
00033 static const char configKeyDefaultIdentity[] = "Default Identity";
00034 
00035 #ifdef HAVE_CONFIG_H
00036 #include <config.h>
00037 #endif
00038 
00039 #include "identitymanager.h"
00040 
00041 #include "kmidentity.h" // for IdentityList::{export,import}Data
00042 #ifndef KMAIL_TESTING
00043 #include "kmkernel.h"
00044 #endif
00045 #include "kmmessage.h" // for static KMMessage helper functions
00046 
00047 #include <kemailsettings.h> // for IdentityEntry::fromControlCenter()
00048 #include <kapplication.h>
00049 #include <klocale.h>
00050 #include <kdebug.h>
00051 #include <kconfig.h>
00052 #if KDE_IS_VERSION( 3, 1, 92 )
00053 #include <kuser.h>
00054 #else
00055 #include <pwd.h> // for struct pw;
00056 #include <unistd.h> // for getuid
00057 #endif
00058 
00059 #include <qregexp.h>
00060 
00061 #include <assert.h>
00062 
00063 IdentityManager::IdentityManager( QObject * parent, const char * name )
00064   : ConfigManager( parent, name )
00065 {
00066   readConfig();
00067   mShadowIdentities = mIdentities;
00068   // we need at least a default identity:
00069   if ( mIdentities.isEmpty() ) {
00070     kdDebug( 5006 ) << "IdentityManager: No identity found. Creating default." << endl;
00071     createDefaultIdentity();
00072     commit();
00073   }
00074 }
00075 
00076 IdentityManager::~IdentityManager()
00077 {
00078   kdWarning( hasPendingChanges(), 5006 )
00079     << "IdentityManager: There were uncommitted changes!" << endl;
00080 }
00081 
00082 void IdentityManager::commit()
00083 {
00084   // early out:
00085   if ( !hasPendingChanges() ) return;
00086 
00087   QValueList<uint> seenUOIDs;
00088   for ( QValueList<KMIdentity>::ConstIterator it = mIdentities.begin() ;
00089     it != mIdentities.end() ; ++it )
00090     seenUOIDs << (*it).uoid();
00091 
00092   // find added and changed identities:
00093   for ( QValueList<KMIdentity>::ConstIterator it = mShadowIdentities.begin() ;
00094     it != mShadowIdentities.end() ; ++it ) {
00095     QValueList<uint>::Iterator uoid = seenUOIDs.find( (*it).uoid() );
00096     if ( uoid != seenUOIDs.end() ) {
00097       const KMIdentity & orig = identityForUoid( *uoid );
00098       if ( *it != orig ) {
00099     // changed identity
00100     kdDebug( 5006 ) << "emitting changed() for identity " << *uoid << endl;
00101     emit changed( *it );
00102     emit changed( *uoid );
00103       }
00104       seenUOIDs.remove( uoid );
00105     } else {
00106       // new identity
00107       kdDebug( 5006 ) << "emitting added() for identity " << (*it).uoid() << endl;
00108       emit added( *it );
00109     }
00110   }
00111 
00112   // what's left are deleted identities:
00113   for ( QValueList<uint>::ConstIterator it = seenUOIDs.begin() ;
00114     it != seenUOIDs.end() ; ++it ) {
00115     kdDebug( 5006 ) << "emitting deleted() for identity " << (*it) << endl;
00116     emit deleted( *it );
00117   }
00118 
00119   mIdentities = mShadowIdentities;
00120   writeConfig();
00121   emit ConfigManager::changed();
00122 }
00123 
00124 void IdentityManager::rollback()
00125 {
00126   mShadowIdentities = mIdentities;
00127 }
00128 
00129 bool IdentityManager::hasPendingChanges() const
00130 {
00131   return mIdentities != mShadowIdentities;
00132 }
00133 
00134 QStringList IdentityManager::identities() const
00135 {
00136   QStringList result;
00137   for ( ConstIterator it = mIdentities.begin() ;
00138     it != mIdentities.end() ; ++it )
00139     result << (*it).identityName();
00140   return result;
00141 }
00142 
00143 QStringList IdentityManager::shadowIdentities() const
00144 {
00145   QStringList result;
00146   for ( ConstIterator it = mShadowIdentities.begin() ;
00147     it != mShadowIdentities.end() ; ++it )
00148     result << (*it).identityName();
00149   return result;
00150 }
00151 
00152 // hmm, anyone can explain why I need to explicitly instantate qHeapSort?
00153 //template void qHeapSort( QValueList<KMIdentity> & );
00154 
00155 void IdentityManager::sort() {
00156   qHeapSort( mShadowIdentities );
00157 }
00158 
00159 void IdentityManager::writeConfig() const {
00160   QStringList identities = groupList();
00161   KConfig * config = KMKernel::config();
00162   for ( QStringList::Iterator group = identities.begin() ;
00163     group != identities.end() ; ++group )
00164     config->deleteGroup( *group );
00165   int i = 0;
00166   for ( ConstIterator it = mIdentities.begin() ;
00167     it != mIdentities.end() ; ++it, ++i ) {
00168     KConfigGroup cg( config, QString::fromLatin1("Identity #%1").arg(i) );
00169     (*it).writeConfig( &cg );
00170     if ( (*it).isDefault() ) {
00171       // remember which one is default:
00172       KConfigGroup general( config, "General" );
00173       general.writeEntry( configKeyDefaultIdentity, (*it).uoid() );
00174     }
00175   }
00176 #ifndef KMAIL_TESTING
00177   kmkernel->slotRequestConfigSync();
00178 #else
00179   config->sync();
00180 #endif
00181 }
00182 
00183 void IdentityManager::readConfig() {
00184   mIdentities.clear();
00185 
00186   QStringList identities = groupList();
00187   if ( identities.isEmpty() ) return; // nothing to be done...
00188 
00189   KConfigGroup general( KMKernel::config(), "General" );
00190   uint defaultIdentity = general.readUnsignedNumEntry( configKeyDefaultIdentity );
00191   bool haveDefault = false;
00192 
00193   for ( QStringList::Iterator group = identities.begin() ;
00194     group != identities.end() ; ++group ) {
00195     KConfigGroup config( KMKernel::config(), *group );
00196     mIdentities << KMIdentity();
00197     mIdentities.last().readConfig( &config );
00198     if ( !haveDefault && mIdentities.last().uoid() == defaultIdentity ) {
00199       haveDefault = true;
00200       mIdentities.last().setIsDefault( true );
00201     }
00202   }
00203   if ( !haveDefault ) {
00204     kdWarning( 5006 ) << "IdentityManager: There was no default identity. Marking first one as default." << endl;
00205     mIdentities.first().setIsDefault( true );
00206   }
00207   qHeapSort( mIdentities );
00208 }
00209 
00210 QStringList IdentityManager::groupList() const {
00211   return KMKernel::config()->groupList().grep( QRegExp("^Identity #\\d+$") );
00212 }
00213 
00214 IdentityManager::ConstIterator IdentityManager::begin() const {
00215   return mIdentities.begin();
00216 }
00217 
00218 IdentityManager::ConstIterator IdentityManager::end() const {
00219   return mIdentities.end();
00220 }
00221 
00222 IdentityManager::Iterator IdentityManager::begin() {
00223   return mShadowIdentities.begin();
00224 }
00225 
00226 IdentityManager::Iterator IdentityManager::end() {
00227   return mShadowIdentities.end();
00228 }
00229 
00230 const KMIdentity & IdentityManager::identityForName( const QString & name ) const
00231 {
00232   kdWarning( 5006 )
00233     << "deprecated method IdentityManager::identityForName() called!" << endl;
00234   for ( ConstIterator it = begin() ; it != end() ; ++it )
00235     if ( (*it).identityName() == name ) return (*it);
00236   return KMIdentity::null;
00237 }
00238 
00239 const KMIdentity & IdentityManager::identityForUoid( uint uoid ) const {
00240   for ( ConstIterator it = begin() ; it != end() ; ++it )
00241     if ( (*it).uoid() == uoid ) return (*it);
00242   return KMIdentity::null;
00243 }
00244 
00245 const KMIdentity & IdentityManager::identityForNameOrDefault( const QString & name ) const
00246 {
00247   const KMIdentity & ident = identityForName( name );
00248   if ( ident.isNull() )
00249     return defaultIdentity();
00250   else
00251     return ident;
00252 }
00253 
00254 const KMIdentity & IdentityManager::identityForUoidOrDefault( uint uoid ) const
00255 {
00256   const KMIdentity & ident = identityForUoid( uoid );
00257   if ( ident.isNull() )
00258     return defaultIdentity();
00259   else
00260     return ident;
00261 }
00262 
00263 const KMIdentity & IdentityManager::identityForAddress( const QString & addresses ) const
00264 {
00265   QStringList addressList = KMMessage::splitEmailAddrList( addresses );
00266   for ( ConstIterator it = begin() ; it != end() ; ++it ) {
00267     for( QStringList::ConstIterator addrIt = addressList.begin();
00268          addrIt != addressList.end(); ++addrIt ) {
00269       // I use QString::utf8() instead of QString::latin1() because I want
00270       // a QCString and not a char*. It doesn't matter because emailAddr()
00271       // returns a 7-bit string.
00272       if( (*it).emailAddr().utf8().lower() ==
00273           KMMessage::getEmailAddr( *addrIt ).lower() )
00274         return (*it);
00275     }
00276   }
00277   return KMIdentity::null;
00278 }
00279 
00280 bool IdentityManager::thatIsMe( const QString & addressList ) const {
00281   return !identityForAddress( addressList ).isNull();
00282 }
00283 
00284 KMIdentity & IdentityManager::identityForName( const QString & name )
00285 {
00286   for ( Iterator it = begin() ; it != end() ; ++it )
00287     if ( (*it).identityName() == name ) return (*it);
00288   kdWarning( 5006 ) << "IdentityManager::identityForName() used as newFromScratch() replacement!"
00289             << "\n  name == \"" << name << "\"" << endl;
00290   return newFromScratch( name );
00291 }
00292 
00293 KMIdentity & IdentityManager::identityForUoid( uint uoid )
00294 {
00295   for ( Iterator it = begin() ; it != end() ; ++it )
00296     if ( (*it).uoid() == uoid ) return (*it);
00297   kdWarning( 5006 ) << "IdentityManager::identityForUoid() used as newFromScratch() replacement!"
00298             << "\n  uoid == \"" << uoid << "\"" << endl;
00299   return newFromScratch( i18n("Unnamed") );
00300 }
00301 
00302 const KMIdentity & IdentityManager::defaultIdentity() const {
00303   for ( ConstIterator it = begin() ; it != end() ; ++it )
00304     if ( (*it).isDefault() ) return (*it);
00305   (mIdentities.isEmpty() ? kdFatal( 5006 ) : kdWarning( 5006 ) )
00306     << "IdentityManager: No default identity found!" << endl;
00307   return *begin();
00308 }
00309 
00310 bool IdentityManager::setAsDefault( const QString & name ) {
00311   // First, check if the identity actually exists:
00312   QStringList names = shadowIdentities();
00313   if ( names.find( name ) == names.end() ) return false;
00314   // Then, change the default as requested:
00315   for ( Iterator it = begin() ; it != end() ; ++it )
00316     (*it).setIsDefault( (*it).identityName() == name );
00317   // and re-sort:
00318   sort();
00319   return true;
00320 }
00321 
00322 bool IdentityManager::setAsDefault( uint uoid ) {
00323   // First, check if the identity actually exists:
00324   bool found = false;
00325   for ( ConstIterator it = mShadowIdentities.begin() ;
00326     it != mShadowIdentities.end() ; ++it )
00327     if ( (*it).uoid() == uoid ) {
00328       found = true;
00329       break;
00330     }
00331   if ( !found ) return false;
00332 
00333   // Then, change the default as requested:
00334   for ( Iterator it = begin() ; it != end() ; ++it )
00335     (*it).setIsDefault( (*it).uoid() == uoid );
00336   // and re-sort:
00337   sort();
00338   return true;
00339 }
00340 
00341 bool IdentityManager::removeIdentity( const QString & name ) {
00342   for ( Iterator it = begin() ; it != end() ; ++it )
00343     if ( (*it).identityName() == name ) {
00344       bool removedWasDefault = (*it).isDefault();
00345       mShadowIdentities.remove( it );
00346       if ( removedWasDefault )
00347     mShadowIdentities.first().setIsDefault( true );
00348       return true;
00349     }
00350   return false;
00351 }
00352 
00353 KMIdentity & IdentityManager::newFromScratch( const QString & name ) {
00354   return newFromExisting( KMIdentity( name ) );
00355 }
00356 
00357 KMIdentity & IdentityManager::newFromControlCenter( const QString & name ) {
00358   KEMailSettings es;
00359   es.setProfile( es.defaultProfileName() );
00360 
00361   return newFromExisting( KMIdentity( name,
00362                    es.getSetting( KEMailSettings::RealName ),
00363                    es.getSetting( KEMailSettings::EmailAddress ),
00364                    es.getSetting( KEMailSettings::Organization ),
00365                    es.getSetting( KEMailSettings::ReplyToAddress )
00366                    ) );
00367 }
00368 
00369 KMIdentity & IdentityManager::newFromExisting( const KMIdentity & other,
00370                            const QString & name ) {
00371   mShadowIdentities << other;
00372   KMIdentity & result = mShadowIdentities.last();
00373   result.setIsDefault( false ); // we don't want two default identities!
00374   result.setUoid( newUoid() ); // we don't want two identies w/ same UOID
00375   if ( !name.isNull() )
00376     result.setIdentityName( name );
00377   return result;
00378 }
00379 
00380 void IdentityManager::createDefaultIdentity() {
00381 #if KDE_IS_VERSION( 3, 1, 92 )
00382   KUser user;
00383   QString fullName = user.fullName();
00384 
00385   QString emailAddress = user.loginName();
00386   if ( !emailAddress.isEmpty() ) {
00387     KConfigGroup general( KMKernel::config(), "General" );
00388     QString defaultdomain = general.readEntry( "Default domain" );
00389     if( !defaultdomain.isEmpty() ) {
00390       emailAddress += '@' + defaultdomain;
00391     }
00392     else {
00393       emailAddress = QString::null;
00394     }
00395   }
00396 #else
00397   QString fullName, emailAddress;
00398   if ( const struct passwd * pw = getpwuid( getuid() ) ) {
00399     // extract possible full name from /etc/passwd
00400     fullName = QString::fromLocal8Bit( pw->pw_gecos );
00401     const int i = fullName.find(',');
00402     if ( i > 0 ) fullName.truncate( i );
00403   }
00404 #endif
00405   mShadowIdentities << KMIdentity( i18n("Default"), fullName, emailAddress );
00406   mShadowIdentities.last().setIsDefault( true );
00407   mShadowIdentities.last().setUoid( newUoid() );
00408 }
00409 
00410 int IdentityManager::newUoid()
00411 {
00412   int uoid;
00413 
00414   // determine the UOIDs of all saved identities
00415   QValueList<uint> usedUOIDs;
00416   for ( QValueList<KMIdentity>::ConstIterator it = mIdentities.begin() ;
00417     it != mIdentities.end() ; ++it )
00418     usedUOIDs << (*it).uoid();
00419 
00420   if ( hasPendingChanges() ) {
00421     // add UOIDs of all shadow identities. Yes, we will add a lot of duplicate
00422     // UOIDs, but avoiding duplicate UOIDs isn't worth the effort.
00423     for ( QValueList<KMIdentity>::ConstIterator it = mShadowIdentities.begin() ;
00424           it != mShadowIdentities.end() ; ++it ) {
00425       usedUOIDs << (*it).uoid();
00426     }
00427   }
00428 
00429   usedUOIDs << 0; // no UOID must be 0 because this value always refers to the
00430                   // default identity
00431 
00432   do {
00433     uoid = kapp->random();
00434   } while ( usedUOIDs.find( uoid ) != usedUOIDs.end() );
00435 
00436   return uoid;
00437 }
00438 
00439 #include "identitymanager.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:18 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003