diff options
Diffstat (limited to 'libkpimidentities')
-rw-r--r-- | libkpimidentities/Makefile.am | 18 | ||||
-rw-r--r-- | libkpimidentities/identity.cpp | 636 | ||||
-rw-r--r-- | libkpimidentities/identity.h | 319 | ||||
-rw-r--r-- | libkpimidentities/identitycombo.cpp | 129 | ||||
-rw-r--r-- | libkpimidentities/identitycombo.h | 99 | ||||
-rw-r--r-- | libkpimidentities/identitymanager.cpp | 518 | ||||
-rw-r--r-- | libkpimidentities/identitymanager.h | 242 |
7 files changed, 1961 insertions, 0 deletions
diff --git a/libkpimidentities/Makefile.am b/libkpimidentities/Makefile.am new file mode 100644 index 000000000..663e4c8e1 --- /dev/null +++ b/libkpimidentities/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/certmanager/lib $(all_includes) + +lib_LTLIBRARIES = libkpimidentities.la +libkpimidentities_la_SOURCES = \ + identitymanager.cpp identity.cpp identitymanager.skel \ + identitycombo.cpp +libkpimidentities_la_LIBADD = ../certmanager/lib/libkleopatra.la \ + ../libkdepim/libkdepim.la ../libemailfunctions/libemailfunctions.la +libkpimidentities_la_LDFLAGS = $(all_libraries) -no-undefined \ + -version-info 1:0:0 + +identitymanager_DCOPIDLNG = true + +METASOURCES = AUTO + +include $(top_srcdir)/admin/Doxyfile.am + +# No messages target. Those files are part of libkdepim.pot. diff --git a/libkpimidentities/identity.cpp b/libkpimidentities/identity.cpp new file mode 100644 index 000000000..204e997e7 --- /dev/null +++ b/libkpimidentities/identity.cpp @@ -0,0 +1,636 @@ +// -*- mode: C++; c-file-style: "gnu" -*- +// kmidentity.cpp +// License: GPL + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "identity.h" + +#include <libkdepim/kfileio.h> +#include <libkdepim/collectingprocess.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <kurl.h> + +#include <qfileinfo.h> + +#include <sys/types.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <assert.h> + +using namespace KPIM; + + +Signature::Signature() + : mType( Disabled ) +{ + +} + +Signature::Signature( const QString & text ) + : mText( text ), + mType( Inlined ) +{ + +} + +Signature::Signature( const QString & url, bool isExecutable ) + : mUrl( url ), + mType( isExecutable ? FromCommand : FromFile ) +{ +} + +bool Signature::operator==( const Signature & other ) const { + if ( mType != other.mType ) return false; + switch ( mType ) { + case Inlined: return mText == other.mText; + case FromFile: + case FromCommand: return mUrl == other.mUrl; + default: + case Disabled: return true; + } +} + +QString Signature::rawText( bool * ok ) const +{ + switch ( mType ) { + case Disabled: + if ( ok ) *ok = true; + return QString::null; + case Inlined: + if ( ok ) *ok = true; + return mText; + case FromFile: + return textFromFile( ok ); + case FromCommand: + return textFromCommand( ok ); + }; + kdFatal( 5006 ) << "Signature::type() returned unknown value!" << endl; + return QString::null; // make compiler happy +} + +QString Signature::textFromCommand( bool * ok ) const +{ + assert( mType == FromCommand ); + + // handle pathological cases: + if ( mUrl.isEmpty() ) { + if ( ok ) *ok = true; + return QString::null; + } + + // create a shell process: + CollectingProcess proc; + proc.setUseShell(true); + proc << mUrl; + + // run the process: + int rc = 0; + if ( !proc.start( KProcess::Block, KProcess::Stdout ) ) + rc = -1; + else + rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ; + + // handle errors, if any: + if ( rc != 0 ) { + if ( ok ) *ok = false; + QString wmsg = i18n("<qt>Failed to execute signature script<br><b>%1</b>:<br>%2</qt>") + .arg( mUrl ).arg( strerror(rc) ); + KMessageBox::error(0, wmsg); + return QString::null; + } + + // no errors: + if ( ok ) *ok = true; + + // get output: + QByteArray output = proc.collectedStdout(); + + // ### hmm, should we allow other encodings, too? + return QString::fromLocal8Bit( output.data(), output.size() ); +} + +QString Signature::textFromFile( bool * ok ) const +{ + assert( mType == FromFile ); + + // ### FIXME: Use KIO::NetAccess to download non-local files! + if ( !KURL(mUrl).isLocalFile() && !(QFileInfo(mUrl).isRelative() + && QFileInfo(mUrl).exists()) ) { + kdDebug( 5006 ) << "Signature::textFromFile: non-local URLs are unsupported" << endl; + if ( ok ) *ok = false; + return QString::null; + } + if ( ok ) *ok = true; + // ### hmm, should we allow other encodings, too? + return QString::fromLocal8Bit( kFileToString( mUrl, false ) ); +} + +QString Signature::withSeparator( bool * ok ) const +{ + bool internalOK = false; + QString signature = rawText( &internalOK ); + if ( !internalOK ) { + if ( ok ) *ok = false; + return QString::null; + } + if ( ok ) *ok = true; + if ( signature.isEmpty() ) return signature; // don't add a separator in this case + if ( signature.startsWith( QString::fromLatin1("-- \n") ) ) + // already have signature separator at start of sig: + return QString::fromLatin1("\n") += signature; + else if ( signature.find( QString::fromLatin1("\n-- \n") ) != -1 ) + // already have signature separator inside sig; don't prepend '\n' + // to improve abusing signatures as templates: + return signature; + else + // need to prepend one: + return QString::fromLatin1("\n-- \n") + signature; +} + + +void Signature::setUrl( const QString & url, bool isExecutable ) +{ + mUrl = url; + mType = isExecutable ? FromCommand : FromFile ; +} + +// config keys and values: +static const char sigTypeKey[] = "Signature Type"; +static const char sigTypeInlineValue[] = "inline"; +static const char sigTypeFileValue[] = "file"; +static const char sigTypeCommandValue[] = "command"; +static const char sigTypeDisabledValue[] = "disabled"; +static const char sigTextKey[] = "Inline Signature"; +static const char sigFileKey[] = "Signature File"; +static const char sigCommandKey[] = "Signature Command"; + +void Signature::readConfig( const KConfigBase * config ) +{ + QString sigType = config->readEntry( sigTypeKey ); + if ( sigType == sigTypeInlineValue ) { + mType = Inlined; + } else if ( sigType == sigTypeFileValue ) { + mType = FromFile; + mUrl = config->readPathEntry( sigFileKey ); + } else if ( sigType == sigTypeCommandValue ) { + mType = FromCommand; + mUrl = config->readPathEntry( sigCommandKey ); + } else { + mType = Disabled; + } + mText = config->readEntry( sigTextKey ); +} + +void Signature::writeConfig( KConfigBase * config ) const +{ + switch ( mType ) { + case Inlined: + config->writeEntry( sigTypeKey, sigTypeInlineValue ); + break; + case FromFile: + config->writeEntry( sigTypeKey, sigTypeFileValue ); + config->writePathEntry( sigFileKey, mUrl ); + break; + case FromCommand: + config->writeEntry( sigTypeKey, sigTypeCommandValue ); + config->writePathEntry( sigCommandKey, mUrl ); + break; + case Disabled: + config->writeEntry( sigTypeKey, sigTypeDisabledValue ); + default: ; + } + config->writeEntry( sigTextKey, mText ); +} + +QDataStream & KPIM::operator<<( QDataStream & stream, const KPIM::Signature & sig ) { + return stream << static_cast<Q_UINT8>(sig.mType) + << sig.mUrl + << sig.mText; +} + +QDataStream & KPIM::operator>>( QDataStream & stream, KPIM::Signature & sig ) { + Q_UINT8 s; + stream >> s + >> sig.mUrl + >> sig.mText; + sig.mType = static_cast<Signature::Type>(s); + return stream; +} + +// ### should use a kstaticdeleter? +static Identity* identityNull = 0; +const Identity& Identity::null() +{ + if ( !identityNull ) + identityNull = new Identity; + return *identityNull; +} + +bool Identity::isNull() const { + return mIdentity.isEmpty() && mFullName.isEmpty() && mEmailAddr.isEmpty() && + mOrganization.isEmpty() && mReplyToAddr.isEmpty() && mBcc.isEmpty() && + mVCardFile.isEmpty() && + mFcc.isEmpty() && mDrafts.isEmpty() && mTemplates.isEmpty() && + mPGPEncryptionKey.isEmpty() && mPGPSigningKey.isEmpty() && + mSMIMEEncryptionKey.isEmpty() && mSMIMESigningKey.isEmpty() && + mTransport.isEmpty() && mDictionary.isEmpty() && + mPreferredCryptoMessageFormat == Kleo::AutoFormat && + mSignature.type() == Signature::Disabled && + mXFace.isEmpty(); +} + +bool Identity::operator==( const Identity & other ) const { + bool same = mUoid == other.mUoid && + mIdentity == other.mIdentity && mFullName == other.mFullName && + mEmailAddr == other.mEmailAddr && mOrganization == other.mOrganization && + mReplyToAddr == other.mReplyToAddr && mBcc == other.mBcc && + mVCardFile == other.mVCardFile && + mFcc == other.mFcc && + mPGPEncryptionKey == other.mPGPEncryptionKey && + mPGPSigningKey == other.mPGPSigningKey && + mSMIMEEncryptionKey == other.mSMIMEEncryptionKey && + mSMIMESigningKey == other.mSMIMESigningKey && + mPreferredCryptoMessageFormat == other.mPreferredCryptoMessageFormat && + mDrafts == other.mDrafts && mTemplates == other.mTemplates && + mTransport == other.mTransport && + mDictionary == other.mDictionary && mSignature == other.mSignature && + mXFace == other.mXFace && mXFaceEnabled == other.mXFaceEnabled; + +#if 0 + if ( same ) + return true; + if ( mUoid != other.mUoid ) kdDebug() << "mUoid differs : " << mUoid << " != " << other.mUoid << endl; + if ( mIdentity != other.mIdentity ) kdDebug() << "mIdentity differs : " << mIdentity << " != " << other.mIdentity << endl; + if ( mFullName != other.mFullName ) kdDebug() << "mFullName differs : " << mFullName << " != " << other.mFullName << endl; + if ( mEmailAddr != other.mEmailAddr ) kdDebug() << "mEmailAddr differs : " << mEmailAddr << " != " << other.mEmailAddr << endl; + if ( mOrganization != other.mOrganization ) kdDebug() << "mOrganization differs : " << mOrganization << " != " << other.mOrganization << endl; + if ( mReplyToAddr != other.mReplyToAddr ) kdDebug() << "mReplyToAddr differs : " << mReplyToAddr << " != " << other.mReplyToAddr << endl; + if ( mBcc != other.mBcc ) kdDebug() << "mBcc differs : " << mBcc << " != " << other.mBcc << endl; + if ( mVCardFile != other.mVCardFile ) kdDebug() << "mVCardFile differs : " << mVCardFile << " != " << other.mVCardFile << endl; + if ( mFcc != other.mFcc ) kdDebug() << "mFcc differs : " << mFcc << " != " << other.mFcc << endl; + if ( mPGPEncryptionKey != other.mPGPEncryptionKey ) kdDebug() << "mPGPEncryptionKey differs : " << mPGPEncryptionKey << " != " << other.mPGPEncryptionKey << endl; + if ( mPGPSigningKey != other.mPGPSigningKey ) kdDebug() << "mPGPSigningKey differs : " << mPGPSigningKey << " != " << other.mPGPSigningKey << endl; + if ( mSMIMEEncryptionKey != other.mSMIMEEncryptionKey ) kdDebug() << "mSMIMEEncryptionKey differs : '" << mSMIMEEncryptionKey << "' != '" << other.mSMIMEEncryptionKey << "'" << endl; + if ( mSMIMESigningKey != other.mSMIMESigningKey ) kdDebug() << "mSMIMESigningKey differs : " << mSMIMESigningKey << " != " << other.mSMIMESigningKey << endl; + if ( mPreferredCryptoMessageFormat != other.mPreferredCryptoMessageFormat ) kdDebug() << "mPreferredCryptoMessageFormat differs : " << mPreferredCryptoMessageFormat << " != " << other.mPreferredCryptoMessageFormat << endl; + if ( mDrafts != other.mDrafts ) kdDebug() << "mDrafts differs : " << mDrafts << " != " << other.mDrafts << endl; + if ( mTemplates != other.mTemplates ) kdDebug() << "mTemplates differs : " << mTemplates << " != " << other.mTemplates << endl; + if ( mTransport != other.mTransport ) kdDebug() << "mTransport differs : " << mTransport << " != " << other.mTransport << endl; + if ( mDictionary != other.mDictionary ) kdDebug() << "mDictionary differs : " << mDictionary << " != " << other.mDictionary << endl; + if ( ! ( mSignature == other.mSignature ) ) kdDebug() << "mSignature differs" << endl; +#endif + return same; +} + +Identity::Identity( const QString & id, const QString & fullName, + const QString & emailAddr, const QString & organization, + const QString & replyToAddr ) + : mUoid( 0 ), mIdentity( id ), mFullName( fullName ), + mEmailAddr( emailAddr ), mOrganization( organization ), + mReplyToAddr( replyToAddr ), + // Using "" instead of null to make operator==() not fail + // (readConfig returns "") + mBcc( "" ), mVCardFile( "" ), mPGPEncryptionKey( "" ), mPGPSigningKey( "" ), + mSMIMEEncryptionKey( "" ), mSMIMESigningKey( "" ), mFcc( "" ), + mDrafts( "" ), mTemplates( "" ), mTransport( "" ), + mDictionary( "" ), + mXFace( "" ), mXFaceEnabled( false ), + mIsDefault( false ), + mPreferredCryptoMessageFormat( Kleo::AutoFormat ) +{ +} + +Identity::~Identity() +{ +} + + +void Identity::readConfig( const KConfigBase * config ) +{ + mUoid = config->readUnsignedNumEntry("uoid",0); + + mIdentity = config->readEntry("Identity"); + mFullName = config->readEntry("Name"); + mEmailAddr = config->readEntry("Email Address"); + mVCardFile = config->readPathEntry("VCardFile"); + mOrganization = config->readEntry("Organization"); + mPGPSigningKey = config->readEntry("PGP Signing Key").latin1(); + mPGPEncryptionKey = config->readEntry("PGP Encryption Key").latin1(); + mSMIMESigningKey = config->readEntry("SMIME Signing Key").latin1(); + mSMIMEEncryptionKey = config->readEntry("SMIME Encryption Key").latin1(); + mPreferredCryptoMessageFormat = Kleo::stringToCryptoMessageFormat( config->readEntry("Preferred Crypto Message Format", "none" ) ); + mReplyToAddr = config->readEntry( "Reply-To Address" ); + mBcc = config->readEntry( "Bcc" ); + mFcc = config->readEntry( "Fcc", "sent-mail" ); + if( mFcc.isEmpty() ) + mFcc = "sent-mail"; + mDrafts = config->readEntry( "Drafts", "drafts" ); + if( mDrafts.isEmpty() ) + mDrafts = "drafts"; + mTemplates = config->readEntry( "Templates", "templates" ); + if( mTemplates.isEmpty() ) + mTemplates = "templates"; + mTransport = config->readEntry( "Transport" ); + mDictionary = config->readEntry( "Dictionary" ); + mXFace = config->readEntry( "X-Face" ); + mXFaceEnabled = config->readBoolEntry( "X-FaceEnabled", false ); + + mSignature.readConfig( config ); + kdDebug(5006) << "Identity::readConfig(): UOID = " << mUoid + << " for identity named \"" << mIdentity << "\"" << endl; +} + + +void Identity::writeConfig( KConfigBase * config ) const +{ + config->writeEntry("uoid", mUoid); + + config->writeEntry("Identity", mIdentity); + config->writeEntry("Name", mFullName); + config->writeEntry("Organization", mOrganization); + config->writeEntry("PGP Signing Key", mPGPSigningKey.data()); + config->writeEntry("PGP Encryption Key", mPGPEncryptionKey.data()); + config->writeEntry("SMIME Signing Key", mSMIMESigningKey.data()); + config->writeEntry("SMIME Encryption Key", mSMIMEEncryptionKey.data()); + config->writeEntry("Preferred Crypto Message Format", Kleo::cryptoMessageFormatToString( mPreferredCryptoMessageFormat ) ); + config->writeEntry("Email Address", mEmailAddr); + config->writeEntry("Reply-To Address", mReplyToAddr); + config->writeEntry("Bcc", mBcc); + config->writePathEntry("VCardFile", mVCardFile); + config->writeEntry("Transport", mTransport); + config->writeEntry("Fcc", mFcc); + config->writeEntry("Drafts", mDrafts); + config->writeEntry("Templates", mTemplates); + config->writeEntry( "Dictionary", mDictionary ); + config->writeEntry( "X-Face", mXFace ); + config->writeEntry( "X-FaceEnabled", mXFaceEnabled ); + + mSignature.writeConfig( config ); +} + +QDataStream & KPIM::operator<<( QDataStream & stream, const KPIM::Identity & i ) { + return stream << static_cast<Q_UINT32>(i.uoid()) + << i.identityName() + << i.fullName() + << i.organization() + << i.pgpSigningKey() + << i.pgpEncryptionKey() + << i.smimeSigningKey() + << i.smimeEncryptionKey() + << i.emailAddr() + << i.replyToAddr() + << i.bcc() + << i.vCardFile() + << i.transport() + << i.fcc() + << i.drafts() + << i.templates() + << i.mSignature + << i.dictionary() + << i.xface() + << QString( Kleo::cryptoMessageFormatToString( i.mPreferredCryptoMessageFormat ) ); +} + +QDataStream & KPIM::operator>>( QDataStream & stream, KPIM::Identity & i ) { + Q_UINT32 uoid; + QString format; + stream >> uoid + >> i.mIdentity + >> i.mFullName + >> i.mOrganization + >> i.mPGPSigningKey + >> i.mPGPEncryptionKey + >> i.mSMIMESigningKey + >> i.mSMIMEEncryptionKey + >> i.mEmailAddr + >> i.mReplyToAddr + >> i.mBcc + >> i.mVCardFile + >> i.mTransport + >> i.mFcc + >> i.mDrafts + >> i.mTemplates + >> i.mSignature + >> i.mDictionary + >> i.mXFace + >> format; + i.mUoid = uoid; + i.mPreferredCryptoMessageFormat = Kleo::stringToCryptoMessageFormat( format.latin1() ); + + return stream; +} + +//----------------------------------------------------------------------------- +bool Identity::mailingAllowed() const +{ + return !mEmailAddr.isEmpty(); +} + + +void Identity::setIsDefault( bool flag ) { + mIsDefault = flag; +} + +void Identity::setIdentityName( const QString & name ) { + mIdentity = name; +} + +void Identity::setFullName(const QString &str) +{ + mFullName = str; +} + + +//----------------------------------------------------------------------------- +void Identity::setOrganization(const QString &str) +{ + mOrganization = str; +} + +void Identity::setPGPSigningKey(const QCString &str) +{ + mPGPSigningKey = str; + if ( mPGPSigningKey.isNull() ) + mPGPSigningKey = ""; +} + +void Identity::setPGPEncryptionKey(const QCString &str) +{ + mPGPEncryptionKey = str; + if ( mPGPEncryptionKey.isNull() ) + mPGPEncryptionKey = ""; +} + +void Identity::setSMIMESigningKey(const QCString &str) +{ + mSMIMESigningKey = str; + if ( mSMIMESigningKey.isNull() ) + mSMIMESigningKey = ""; +} + +void Identity::setSMIMEEncryptionKey(const QCString &str) +{ + mSMIMEEncryptionKey = str; + if ( mSMIMEEncryptionKey.isNull() ) + mSMIMEEncryptionKey = ""; +} + +//----------------------------------------------------------------------------- +void Identity::setEmailAddr(const QString &str) +{ + mEmailAddr = str; +} + + +//----------------------------------------------------------------------------- +void Identity::setVCardFile(const QString &str) +{ + mVCardFile = str; +} + + +//----------------------------------------------------------------------------- +QString Identity::fullEmailAddr(void) const +{ + if (mFullName.isEmpty()) return mEmailAddr; + + const QString specials("()<>@,.;:[]"); + + QString result; + + // add DQUOTE's if necessary: + bool needsQuotes=false; + for (unsigned int i=0; i < mFullName.length(); i++) { + if ( specials.contains( mFullName[i] ) ) + needsQuotes = true; + else if ( mFullName[i] == '\\' || mFullName[i] == '"' ) { + needsQuotes = true; + result += '\\'; + } + result += mFullName[i]; + } + + if (needsQuotes) { + result.insert(0,'"'); + result += '"'; + } + + result += " <" + mEmailAddr + '>'; + + return result; +} + +//----------------------------------------------------------------------------- +void Identity::setReplyToAddr(const QString& str) +{ + mReplyToAddr = str; +} + + +//----------------------------------------------------------------------------- +void Identity::setSignatureFile(const QString &str) +{ + mSignature.setUrl( str, signatureIsCommand() ); +} + + +//----------------------------------------------------------------------------- +void Identity::setSignatureInlineText(const QString &str ) +{ + mSignature.setText( str ); +} + + +//----------------------------------------------------------------------------- +void Identity::setTransport( const QString &str ) +{ + mTransport = str; + if ( mTransport.isNull() ) + mTransport = ""; +} + +//----------------------------------------------------------------------------- +void Identity::setFcc( const QString &str ) +{ + mFcc = str; + if ( mFcc.isNull() ) + mFcc = ""; +} + +//----------------------------------------------------------------------------- +void Identity::setDrafts( const QString &str ) +{ + mDrafts = str; + if ( mDrafts.isNull() ) + mDrafts = ""; +} + +//----------------------------------------------------------------------------- +void Identity::setTemplates( const QString &str ) +{ + mTemplates = str; + if ( mTemplates.isNull() ) + mTemplates = ""; +} + +//----------------------------------------------------------------------------- +void Identity::setDictionary( const QString &str ) +{ + mDictionary = str; + if ( mDictionary.isNull() ) + mDictionary = ""; +} + + +//----------------------------------------------------------------------------- +void Identity::setXFace( const QString &str ) +{ + mXFace = str; + mXFace.remove( " " ); + mXFace.remove( "\n" ); + mXFace.remove( "\r" ); +} + + +//----------------------------------------------------------------------------- +void Identity::setXFaceEnabled( const bool on ) +{ + mXFaceEnabled = on; +} + + +//----------------------------------------------------------------------------- +QString Identity::signatureText( bool * ok ) const +{ + bool internalOK = false; + QString signatureText = mSignature.withSeparator( &internalOK ); + if ( internalOK ) { + if ( ok ) *ok=true; + return signatureText; + } + + // OK, here comes the funny part. The call to + // Signature::withSeparator() failed, so we should probably fix the + // cause: + if ( ok ) *ok = false; + return QString::null; + +#if 0 // ### FIXME: error handling + if (mSignatureFile.endsWith("|")) + { + } + else + { + } +#endif + + return QString::null; +} diff --git a/libkpimidentities/identity.h b/libkpimidentities/identity.h new file mode 100644 index 000000000..6b06e9a9d --- /dev/null +++ b/libkpimidentities/identity.h @@ -0,0 +1,319 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + * User identity information + * + * Author: Stefan Taferner <taferner@kde.org> + * This code is under GPL + */ +#ifndef kpim_identity_h +#define kpim_identity_h + +#include <kleo/enum.h> + +#include <kdepimmacros.h> + +#include <qstring.h> +#include <qcstring.h> +#include <qstringlist.h> + +class KProcess; +namespace KPIM { + class Identity; + class Signature; +} +class KConfigBase; +class IdentityList; +class QDataStream; + +namespace KPIM { + +/** + * @short abstraction of a signature (aka "footer"). + * @author Marc Mutz <mutz@kde.org> + */ +class KDE_EXPORT Signature { + friend class Identity; + + friend QDataStream & KPIM::operator<<( QDataStream & stream, const Signature & sig ); + friend QDataStream & KPIM::operator>>( QDataStream & stream, Signature & sig ); + +public: + /** Type of signature (ie. way to obtain the signature text) */ + enum Type { Disabled = 0, Inlined = 1, FromFile = 2, FromCommand = 3 }; + + /** Used for comparison */ + bool operator==( const Signature & other ) const; + + /** Constructor for disabled signature */ + Signature(); + /** Constructor for inline text */ + Signature( const QString & text ); + /** Constructor for text from a file or from output of a command */ + Signature( const QString & url, bool isExecutable ); + + /** @return the raw signature text as entered resp. read from file. */ + QString rawText( bool * ok=0 ) const; + + /** @return the signature text with a "-- " separator added, if + necessary. */ + QString withSeparator( bool * ok=0 ) const; + + /** Set the signature text and mark this signature as being of + "inline text" type. */ + void setText( const QString & text ) { mText = text; } + QString text() const { return mText; } + + /** Set the signature URL and mark this signature as being of + "from file" resp. "from output of command" type. */ + void setUrl( const QString & url, bool isExecutable=false ); + QString url() const { return mUrl; } + + /// @return the type of signature (ie. way to obtain the signature text) + Type type() const { return mType; } + void setType( Type type ) { mType = type; } + +protected: + void writeConfig( KConfigBase * config ) const; + void readConfig( const KConfigBase * config ); + +private: + QString textFromFile( bool * ok ) const; + QString textFromCommand( bool * ok ) const; + +private: + QString mUrl; + QString mText; + Type mType; +}; + +/** User identity information */ +class KDE_EXPORT Identity +{ + // only the identity manager should be able to construct and + // destruct us, but then we get into problems with using + // QValueList<Identity> and especially qHeapSort(). + friend class IdentityManager; + + friend QDataStream & operator<<( QDataStream & stream, const KPIM::Identity & ident ); + friend QDataStream & operator>>( QDataStream & stream, KPIM::Identity & ident ); + +public: + typedef QValueList<Identity> List; + + /** used for comparison */ + bool operator==( const Identity & other ) const; + + bool operator!=( const Identity & other ) const { + return !operator==( other ); + } + + /** used for sorting */ + bool operator<( const Identity & other ) const { + if ( isDefault() ) return true; + if ( other.isDefault() ) return false; + return identityName() < other.identityName(); + } + bool operator>( const Identity & other ) const { + if ( isDefault() ) return false; + if ( other.isDefault() ) return true; + return identityName() > other.identityName(); + } + bool operator<=( const Identity & other ) const { + return !operator>( other ); + } + bool operator>=( const Identity & other ) const { + return !operator<( other ); + } + + /** Constructor */ + explicit Identity( const QString & id=QString::null, + const QString & realName=QString::null, + const QString & emailAddr=QString::null, + const QString & organization=QString::null, + const QString & replyToAddress=QString::null ); + + /** Destructor */ + ~Identity(); + +protected: + /** Read configuration from config. Group must be preset (or use + KConfigGroup). Called from IdentityManager. */ + void readConfig( const KConfigBase * ); + + /** Write configuration to config. Group must be preset (or use + KConfigGroup). Called from IdentityManager. */ + void writeConfig( KConfigBase * ) const; + +public: + /** Tests if there are enough values set to allow mailing */ + bool mailingAllowed() const; + + /** Identity/nickname for this collection */ + QString identityName() const { return mIdentity; } + void setIdentityName( const QString & name ); + + /** @return whether this identity is the default identity */ + bool isDefault() const { return mIsDefault; } + + /// Unique Object Identifier for this identity + uint uoid() const { return mUoid; } + +protected: + /** Set whether this identity is the default identity. Since this + affects all other identites, too (most notably, the old default + identity), only the IdentityManager can change this. + You should use + <pre> + kmkernel->identityManager()->setAsDefault( name_of_default ) + </pre> + instead. + **/ + void setIsDefault( bool flag ); + + void setUoid( uint aUoid ) { mUoid = aUoid; } + +public: + /** Full name of the user */ + QString fullName() const { return mFullName; } + void setFullName(const QString&); + + /** The user's organization (optional) */ + QString organization() const { return mOrganization; } + void setOrganization(const QString&); + + KDE_DEPRECATED QCString pgpIdentity() const { return pgpEncryptionKey(); } + KDE_DEPRECATED void setPgpIdentity( const QCString & key ) { + setPGPEncryptionKey( key ); + setPGPSigningKey( key ); + } + + /** The user's OpenPGP encryption key */ + QCString pgpEncryptionKey() const { return mPGPEncryptionKey; } + void setPGPEncryptionKey( const QCString & key ); + + /** The user's OpenPGP signing key */ + QCString pgpSigningKey() const { return mPGPSigningKey; } + void setPGPSigningKey( const QCString & key ); + + /** The user's S/MIME encryption key */ + QCString smimeEncryptionKey() const { return mSMIMEEncryptionKey; } + void setSMIMEEncryptionKey( const QCString & key ); + + /** The user's S/MIME signing key */ + QCString smimeSigningKey() const { return mSMIMESigningKey; } + void setSMIMESigningKey( const QCString & key ); + + Kleo::CryptoMessageFormat preferredCryptoMessageFormat() const { return mPreferredCryptoMessageFormat; } + void setPreferredCryptoMessageFormat( Kleo::CryptoMessageFormat format ) { mPreferredCryptoMessageFormat = format; } + + /** email address (without the user name - only name\@host) */ + QString emailAddr() const { return mEmailAddr; } + void setEmailAddr(const QString&); + + /** vCard to attach to outgoing emails */ + QString vCardFile() const { return mVCardFile; } + void setVCardFile(const QString&); + + /** email address in the format "username <name@host>" suitable + for the "From:" field of email messages. */ + QString fullEmailAddr() const; + + /** email address for the ReplyTo: field */ + QString replyToAddr() const { return mReplyToAddr; } + void setReplyToAddr(const QString&); + + /** email addresses for the BCC: field */ + QString bcc() const { return mBcc; } + void setBcc(const QString& aBcc) { mBcc = aBcc; } + + void setSignature( const Signature & sig ) { mSignature = sig; } + Signature & signature() /* _not_ const! */ { return mSignature; } + const Signature & signature() const { return mSignature; } + +protected: + /** @return true if the signature is read from the output of a command */ + bool signatureIsCommand() const { return mSignature.type() == Signature::FromCommand; } + /** @return true if the signature is read from a text file */ + bool signatureIsPlainFile() const { return mSignature.type() == Signature::FromFile; } + /** @return true if the signature was specified directly */ + bool signatureIsInline() const { return mSignature.type() == Signature::Inlined; } + + /** name of the signature file (with path) */ + QString signatureFile() const { return mSignature.url(); } + void setSignatureFile(const QString&); + + /** inline signature */ + QString signatureInlineText() const { return mSignature.text();} + void setSignatureInlineText(const QString&); + + /** Inline or signature from a file */ + bool useSignatureFile() const { return signatureIsPlainFile() || signatureIsCommand(); } + +public: + /** Returns the signature. This method also takes care of special + signature files that are shell scripts and handles them + correct. So use this method to rectreive the contents of the + signature file. If @p prompt is false, no errors will be displayed + (useful for retries). */ + QString signatureText( bool * ok=0) const; + + /** The transport that is set for this identity. Used to link a + transport with an identity. */ + QString transport() const { return mTransport; } + void setTransport(const QString&); + + /** The folder where sent messages from this identity will be + stored by default. */ + QString fcc() const { return mFcc; } + void setFcc(const QString&); + + /** The folder where draft messages from this identity will be + stored by default. */ + QString drafts() const { return mDrafts; } + void setDrafts(const QString&); + + /** The folder where template messages from this identity will be + stored by default. */ + QString templates() const { return mTemplates; } + void setTemplates( const QString& ); + + /** dictionary which should be used for spell checking */ + QString dictionary() const { return mDictionary; } + void setDictionary( const QString& ); + + /** a X-Face header for this identity */ + QString xface() const { return mXFace; } + void setXFace( const QString& ); + bool isXFaceEnabled() const { return mXFaceEnabled; } + void setXFaceEnabled( const bool ); + + static const Identity& null(); + bool isNull() const; +protected: + // if you add new members, make sure they have an operator= (or the + // compiler can synthesize one) and amend Identity::operator==, + // isNull(), readConfig() and writeConfig() as well as operator<< + // and operator>> accordingly: + uint mUoid; + QString mIdentity, mFullName, mEmailAddr, mOrganization; + QString mReplyToAddr; + QString mBcc; + QString mVCardFile; + QCString mPGPEncryptionKey, mPGPSigningKey, mSMIMEEncryptionKey, mSMIMESigningKey; + QString mFcc, mDrafts, mTemplates, mTransport; + QString mDictionary; + QString mXFace; + bool mXFaceEnabled; + Signature mSignature; + bool mIsDefault; + Kleo::CryptoMessageFormat mPreferredCryptoMessageFormat; +}; + +KDE_EXPORT QDataStream & operator<<( QDataStream & stream, const KPIM::Signature & sig ); +KDE_EXPORT QDataStream & operator>>( QDataStream & stream, KPIM::Signature & sig ); + +KDE_EXPORT QDataStream & operator<<( QDataStream & stream, const KPIM::Identity & ident ); +KDE_EXPORT QDataStream & operator>>( QDataStream & stream, KPIM::Identity & ident ); + +} // namespace KPIM + +#endif /*kpim_identity_h*/ diff --git a/libkpimidentities/identitycombo.cpp b/libkpimidentities/identitycombo.cpp new file mode 100644 index 000000000..a7b9cd3ab --- /dev/null +++ b/libkpimidentities/identitycombo.cpp @@ -0,0 +1,129 @@ +/* -*- c++ -*- + identitycombo.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2002 Marc Mutz <mutz@kde.org> + + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "identitycombo.h" +#include "identity.h" +#include "identitymanager.h" + +#include <klocale.h> + +#include <assert.h> + +using namespace KPIM; + +IdentityCombo::IdentityCombo( IdentityManager* manager, QWidget * parent, const char * name ) + : QComboBox( false, parent, name ), mIdentityManager( manager ) +{ + reloadCombo(); + reloadUoidList(); + connect( this, SIGNAL(activated(int)), SLOT(slotEmitChanged(int)) ); + connect( manager, SIGNAL(changed()), + SLOT(slotIdentityManagerChanged()) ); +} + +QString IdentityCombo::currentIdentityName() const { + return mIdentityManager->identities()[ currentItem() ]; +} + +uint IdentityCombo::currentIdentity() const { + return mUoidList[ currentItem() ]; +} + +void IdentityCombo::setCurrentIdentity( const Identity & identity ) { + setCurrentIdentity( identity.uoid() ); +} + +void IdentityCombo::setCurrentIdentity( const QString & name ) { + int idx = mIdentityManager->identities().findIndex( name ); + if ( idx < 0 ) return; + if ( idx == currentItem() ) return; + + blockSignals( true ); // just in case Qt gets fixed to emit activated() here + setCurrentItem( idx ); + blockSignals( false ); + + slotEmitChanged( idx ); +} + +void IdentityCombo::setCurrentIdentity( uint uoid ) { + int idx = mUoidList.findIndex( uoid ); + if ( idx < 0 ) return; + if ( idx == currentItem() ) return; + + blockSignals( true ); // just in case Qt gets fixed to emit activated() here + setCurrentItem( idx ); + blockSignals( false ); + + slotEmitChanged( idx ); +} + +void IdentityCombo::reloadCombo() { + QStringList identities = mIdentityManager->identities(); + // the IM should prevent this from happening: + assert( !identities.isEmpty() ); + identities.first() = i18n("%1 (Default)").arg( identities.first() ); + clear(); + insertStringList( identities ); +} + +void IdentityCombo::reloadUoidList() { + mUoidList.clear(); + IdentityManager::ConstIterator it; + for ( it = mIdentityManager->begin() ; it != mIdentityManager->end() ; ++it ) + mUoidList << (*it).uoid(); +} + +void IdentityCombo::slotIdentityManagerChanged() { + uint oldIdentity = mUoidList[ currentItem() ]; + + reloadUoidList(); + int idx = mUoidList.findIndex( oldIdentity ); + + blockSignals( true ); + reloadCombo(); + setCurrentItem( idx < 0 ? 0 : idx ); + blockSignals( false ); + + if ( idx < 0 ) + // apparently our oldIdentity got deleted: + slotEmitChanged( currentItem() ); +} + +void IdentityCombo::slotEmitChanged( int idx ) { + emit identityChanged( mIdentityManager->identities()[idx] ); + emit identityChanged( mUoidList[idx] ); +} + +#include "identitycombo.moc" diff --git a/libkpimidentities/identitycombo.h b/libkpimidentities/identitycombo.h new file mode 100644 index 000000000..193b81d04 --- /dev/null +++ b/libkpimidentities/identitycombo.h @@ -0,0 +1,99 @@ +/* -*- c++ -*- + identitycombo.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2002 Marc Mutz <mutz@kde.org> + + 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. +*/ + +#ifndef _KPIM_IDENTITYCOMBO_H_ +#define _KPIM_IDENTITYCOMBO_H_ + +#include <qcombobox.h> +#include <qvaluelist.h> +#include <kdepimmacros.h> + +class QString; + +namespace KPIM { + +class IdentityManager; +class Identity; + +/** + * @short A combo box that always shows the up-to-date identity list. + * @author Marc Mutz <mutz@kde.org> + **/ + +class KDE_EXPORT IdentityCombo : public QComboBox { + Q_OBJECT +public: + IdentityCombo( IdentityManager* manager, QWidget * parent=0, const char * name=0 ); + + QString currentIdentityName() const; + uint currentIdentity() const; + void setCurrentIdentity( const QString & identityName ); + void setCurrentIdentity( const Identity & identity ); + void setCurrentIdentity( uint uoid ); + +signals: + /** @deprecated + * @em Really emitted whenever the current identity changes. Either + * by user intervention or on setCurrentIdentity() or if the + * current identity disappears. + **/ + void identityChanged( const QString & identityName ); + + /** @em Really emitted whenever the current identity changes. Either + * by user intervention or on setCurrentIdentity() or if the + * current identity disappears. + * + * You might also want to listen to IdentityManager::changed, + * IdentityManager::deleted and IdentityManager::added. + **/ + void identityChanged( uint uoid ); + +public slots: + /** Connected to IdentityManager::changed(). Reloads the list + * of identities. + **/ + void slotIdentityManagerChanged(); + +protected slots: + void slotEmitChanged(int); + +protected: + void reloadCombo(); + void reloadUoidList(); + +protected: + QValueList<uint> mUoidList; + IdentityManager* mIdentityManager; +}; + +} // namespace + +#endif // _KPIM_IDENTITYCOMBO_H_ 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 <mutz@kde.org> + + 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" diff --git a/libkpimidentities/identitymanager.h b/libkpimidentities/identitymanager.h new file mode 100644 index 000000000..b07ba7434 --- /dev/null +++ b/libkpimidentities/identitymanager.h @@ -0,0 +1,242 @@ +/* -*- c++ -*- + identitymanager.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2002 Marc Mutz <mutz@kde.org> + + 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. +*/ +#ifndef _KPIM_IDENTITYMANAGER_H_ +#define _KPIM_IDENTITYMANAGER_H_ + +#include <libkdepim/configmanager.h> + +#include <qvaluelist.h> +#include <dcopobject.h> +#include <kdepimmacros.h> + +class KConfigBase; +class KConfig; +class KMKernel; +class QStringList; +class KMIdentity; + +namespace KPIM { + +class Identity; +/** + * @short Manages the list of identities. + * @author Marc Mutz <mutz@kde.org> + **/ +#define IdentityManager KDE_EXPORT IdentityManager +class IdentityManager : public ConfigManager, public DCOPObject +#undef IdentityManager +{ + Q_OBJECT + K_DCOP + +public: + /** + * Create an identity manager, which loads the emailidentities file + * to create identities. + * @param readonly if true, no changes can be made to the identity manager + * This means in particular that if there is no identity configured, + * the default identity created here will not be saved. + */ + IdentityManager( bool readonly = false, QObject * parent=0, const char * name=0 ); + virtual ~IdentityManager(); + +public: + typedef QValueList<Identity>::Iterator Iterator; + typedef QValueList<Identity>::ConstIterator ConstIterator; + + /** Commit changes to disk and emit changed() if necessary. */ + void commit(); + /** Re-read the config from disk and forget changes. */ + void rollback(); + + /** Check whether there are any unsaved changes. */ + bool hasPendingChanges() const; + + /** @return the list of identities */ + QStringList identities() const; + + /** Convenience method. + + @return the list of (shadow) identities, ie. the ones currently + under configuration. + */ + QStringList shadowIdentities() const; + + /** Sort the identities by name (the default is always first). This + operates on the @em shadow list, so you need to @ref commit for + the changes to take effect. + **/ + void sort(); + + /** @return an identity whose address matches any in @p addresses + or @ref Identity::null if no such identity exists. + **/ + const Identity & identityForAddress( const QString & addresses ) const; + + /** @return true if @p addressList contains any of our addresses, + false otherwise. + @see #identityForAddress + **/ + bool thatIsMe( const QString & addressList ) const; + + /** @deprecated + @return the identity named @p identityName or @ref + Identity::null if not found. + **/ + const Identity & identityForName( const QString & identityName ) const; + + /** @return the identity with Unique Object Identifier (UOID) @p + uoid or @ref Identity::null if not found. + **/ + const Identity & identityForUoid( uint uoid ) const; + + /** @deprecated + Convenience method. + + @return the identity named @p identityName or the default + identity if not found. + **/ + const Identity & identityForNameOrDefault( const QString & identityName ) const; + + /** Convenience menthod. + + @return the identity with Unique Object Identifier (UOID) @p + uoid or the default identity if not found. + **/ + const Identity & identityForUoidOrDefault( uint uoid ) const; + + /** @return the default identity */ + const Identity & defaultIdentity() const; + + /** @deprecated + Sets the identity named @p identityName to be the new default + identity. As usual, use @ref commit to make this permanent. + + @return false if an identity named @p identityName was not found + **/ + bool setAsDefault( const QString & identityName ); + + /** Sets the identity with Unique Object Identifier (UOID) @p uoid + to be new the default identity. As usual, use @ref commit to + make this permanent. + + @return false if an identity with UOID @p uoid was not found + **/ + bool setAsDefault( uint uoid ); + + /** @return the identity named @p identityName. This method returns a + reference to the identity that can be modified. To let others + see this change, use @ref commit. + **/ + Identity & modifyIdentityForName( const QString & identityName ); + + /** @return the identity with Unique Object Identifier (UOID) @p uoid. + This method returns a reference to the identity that can + be modified. To let others see this change, use @ref commit. + **/ + Identity & modifyIdentityForUoid( uint uoid ); + + /** Removes the identity with name @p identityName */ + bool removeIdentity( const QString & identityName ); + + ConstIterator begin() const; + ConstIterator end() const; + /// Iterator used by the configuration dialog, which works on a separate list + /// of identities, for modification. Changes are made effective by commit(). + Iterator modifyBegin(); + Iterator modifyEnd(); + + Identity & newFromScratch( const QString & name ); + Identity & newFromControlCenter( const QString & name ); + Identity & newFromExisting( const Identity & other, + const QString & name=QString::null ); + + /** Returns the list of all email addresses (only name@host) from all identities */ + QStringList allEmails() const; + +signals: + /** Emitted whenever the identity with Unique Object Identifier + (UOID) @p uoid changed. Useful for more fine-grained change + notifications than what is possible with the standard @ref + changed() signal. */ + void changed( uint uoid ); + /** Emitted whenever the identity @p ident changed. Useful for more + fine-grained change notifications than what is possible with the + standard @ref changed() signal. */ + void changed( const KPIM::Identity & ident ); + /** Emitted on @ref commit() for each deleted identity. At the time + this signal is emitted, the identity does still exist and can be + retrieved by @ref identityForUoid() if needed */ + void deleted( uint uoid ); + /** Emitted on @ref commit() for each new identity */ + void added( const KPIM::Identity & ident ); + +protected: + /** + * This is called when no identity has been defined, so we need to create a default one + * The parameters are filled with some default values from KUser, + * but reimplementations of this method can give them another value. + */ + virtual void createDefaultIdentity( QString& /*fullName*/, QString& /*emailAddress*/ ) {} + +protected slots: + void slotRollback() { rollback(); }; + +protected: + /** The list that will be seen by everyone */ + QValueList<Identity> mIdentities; + /** The list that will be seen by the config dialog */ + QValueList<Identity> mShadowIdentities; + +//k_dcop_signals: +// void identitiesChanged( QCString appId, QCString objId ); + +k_dcop: + // Connected to the DCOP signal + void slotIdentitiesChanged( QCString appId, QCString objId ); + +private: + void writeConfig() const; + void readConfig(KConfigBase* config); + QStringList groupList(KConfigBase* config) const; + void createDefaultIdentity(); + + // returns a new Unique Object Identifier + int newUoid(); + +private: + KConfig* mConfig; + bool mReadOnly; +}; + +} // namespace + +#endif // _KMAIL_IDENTITYMANAGER_H_ |