00001
00002
00003
00004
00005 #ifdef HAVE_CONFIG_H
00006 #include <config.h>
00007 #endif
00008
00009 #include "identity.h"
00010
00011 #include <libkdepim/kfileio.h>
00012 #include <libkdepim/collectingprocess.h>
00013
00014 #include <kdebug.h>
00015 #include <klocale.h>
00016 #include <kmessagebox.h>
00017 #include <kconfig.h>
00018 #include <kurl.h>
00019
00020 #include <qfileinfo.h>
00021
00022 #include <sys/types.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <errno.h>
00026 #include <assert.h>
00027
00028 using namespace KPIM;
00029
00030
00031 Signature::Signature()
00032 : mType( Disabled )
00033 {
00034
00035 }
00036
00037 Signature::Signature( const QString & text )
00038 : mText( text ),
00039 mType( Inlined )
00040 {
00041
00042 }
00043
00044 Signature::Signature( const QString & url, bool isExecutable )
00045 : mUrl( url ),
00046 mType( isExecutable ? FromCommand : FromFile )
00047 {
00048 }
00049
00050 bool Signature::operator==( const Signature & other ) const {
00051 if ( mType != other.mType ) return false;
00052 switch ( mType ) {
00053 case Inlined: return mText == other.mText;
00054 case FromFile:
00055 case FromCommand: return mUrl == other.mUrl;
00056 default:
00057 case Disabled: return true;
00058 }
00059 }
00060
00061 QString Signature::rawText( bool * ok ) const
00062 {
00063 switch ( mType ) {
00064 case Disabled:
00065 if ( ok ) *ok = true;
00066 return QString::null;
00067 case Inlined:
00068 if ( ok ) *ok = true;
00069 return mText;
00070 case FromFile:
00071 return textFromFile( ok );
00072 case FromCommand:
00073 return textFromCommand( ok );
00074 };
00075 kdFatal( 5006 ) << "Signature::type() returned unknown value!" << endl;
00076 return QString::null;
00077 }
00078
00079 QString Signature::textFromCommand( bool * ok ) const
00080 {
00081 assert( mType == FromCommand );
00082
00083
00084 if ( mUrl.isEmpty() ) {
00085 if ( ok ) *ok = true;
00086 return QString::null;
00087 }
00088
00089
00090 CollectingProcess proc;
00091 proc.setUseShell(true);
00092 proc << mUrl;
00093
00094
00095 int rc = 0;
00096 if ( !proc.start( KProcess::Block, KProcess::Stdout ) )
00097 rc = -1;
00098 else
00099 rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ;
00100
00101
00102 if ( rc != 0 ) {
00103 if ( ok ) *ok = false;
00104 QString wmsg = i18n("<qt>Failed to execute signature script<br><b>%1</b>:<br>%2</qt>")
00105 .arg( mUrl ).arg( strerror(rc) );
00106 KMessageBox::error(0, wmsg);
00107 return QString::null;
00108 }
00109
00110
00111 if ( ok ) *ok = true;
00112
00113
00114 QByteArray output = proc.collectedStdout();
00115
00116
00117 return QString::fromLocal8Bit( output.data(), output.size() );
00118 }
00119
00120 QString Signature::textFromFile( bool * ok ) const
00121 {
00122 assert( mType == FromFile );
00123
00124
00125 if ( !KURL(mUrl).isLocalFile() && !(QFileInfo(mUrl).isRelative()
00126 && QFileInfo(mUrl).exists()) ) {
00127 kdDebug( 5006 ) << "Signature::textFromFile: non-local URLs are unsupported" << endl;
00128 if ( ok ) *ok = false;
00129 return QString::null;
00130 }
00131 if ( ok ) *ok = true;
00132
00133 return QString::fromLocal8Bit( kFileToString( mUrl, false ) );
00134 }
00135
00136 QString Signature::withSeparator( bool * ok ) const
00137 {
00138 bool internalOK = false;
00139 QString signature = rawText( &internalOK );
00140 if ( !internalOK ) {
00141 if ( ok ) *ok = false;
00142 return QString::null;
00143 }
00144 if ( ok ) *ok = true;
00145 if ( signature.isEmpty() ) return signature;
00146 if ( signature.startsWith( QString::fromLatin1("-- \n") ) )
00147
00148 return QString::fromLatin1("\n") += signature;
00149 else if ( signature.find( QString::fromLatin1("\n-- \n") ) != -1 )
00150
00151
00152 return signature;
00153 else
00154
00155 return QString::fromLatin1("\n-- \n") + signature;
00156 }
00157
00158
00159 void Signature::setUrl( const QString & url, bool isExecutable )
00160 {
00161 mUrl = url;
00162 mType = isExecutable ? FromCommand : FromFile ;
00163 }
00164
00165
00166 static const char sigTypeKey[] = "Signature Type";
00167 static const char sigTypeInlineValue[] = "inline";
00168 static const char sigTypeFileValue[] = "file";
00169 static const char sigTypeCommandValue[] = "command";
00170 static const char sigTypeDisabledValue[] = "disabled";
00171 static const char sigTextKey[] = "Inline Signature";
00172 static const char sigFileKey[] = "Signature File";
00173 static const char sigCommandKey[] = "Signature Command";
00174
00175 void Signature::readConfig( const KConfigBase * config )
00176 {
00177 QString sigType = config->readEntry( sigTypeKey );
00178 if ( sigType == sigTypeInlineValue ) {
00179 mType = Inlined;
00180 mText = config->readEntry( sigTextKey );
00181 } else if ( sigType == sigTypeFileValue ) {
00182 mType = FromFile;
00183 mUrl = config->readPathEntry( sigFileKey );
00184 } else if ( sigType == sigTypeCommandValue ) {
00185 mType = FromCommand;
00186 mUrl = config->readPathEntry( sigCommandKey );
00187 } else {
00188 mType = Disabled;
00189 }
00190 }
00191
00192 void Signature::writeConfig( KConfigBase * config ) const
00193 {
00194 switch ( mType ) {
00195 case Inlined:
00196 config->writeEntry( sigTypeKey, sigTypeInlineValue );
00197 config->writeEntry( sigTextKey, mText );
00198 break;
00199 case FromFile:
00200 config->writeEntry( sigTypeKey, sigTypeFileValue );
00201 config->writePathEntry( sigFileKey, mUrl );
00202 break;
00203 case FromCommand:
00204 config->writeEntry( sigTypeKey, sigTypeCommandValue );
00205 config->writePathEntry( sigCommandKey, mUrl );
00206 break;
00207 case Disabled:
00208 config->writeEntry( sigTypeKey, sigTypeDisabledValue );
00209 default: ;
00210 }
00211 }
00212
00213 QDataStream & KPIM::operator<<( QDataStream & stream, const KPIM::Signature & sig ) {
00214 return stream << static_cast<Q_UINT8>(sig.mType)
00215 << sig.mUrl
00216 << sig.mText;
00217 }
00218
00219 QDataStream & KPIM::operator>>( QDataStream & stream, KPIM::Signature & sig ) {
00220 Q_UINT8 s;
00221 stream >> s
00222 >> sig.mUrl
00223 >> sig.mText;
00224 sig.mType = static_cast<Signature::Type>(s);
00225 return stream;
00226 }
00227
00228
00229 static Identity* identityNull = 0;
00230 const Identity& Identity::null()
00231 {
00232 if ( !identityNull )
00233 identityNull = new Identity;
00234 return *identityNull;
00235 }
00236
00237 bool Identity::isNull() const {
00238 return mIdentity.isEmpty() && mFullName.isEmpty() && mEmailAddr.isEmpty() &&
00239 mOrganization.isEmpty() && mReplyToAddr.isEmpty() && mBcc.isEmpty() &&
00240 mVCardFile.isEmpty() &&
00241 mFcc.isEmpty() && mDrafts.isEmpty() &&
00242 mPGPEncryptionKey.isEmpty() && mPGPSigningKey.isEmpty() &&
00243 mSMIMEEncryptionKey.isEmpty() && mSMIMESigningKey.isEmpty() &&
00244 mTransport.isEmpty() && mDictionary.isEmpty() &&
00245 mPreferredCryptoMessageFormat == Kleo::AutoFormat &&
00246 mSignature.type() == Signature::Disabled &&
00247 mXFace.isEmpty();
00248 }
00249
00250 bool Identity::operator==( const Identity & other ) const {
00251 bool same = mUoid == other.mUoid &&
00252 mIdentity == other.mIdentity && mFullName == other.mFullName &&
00253 mEmailAddr == other.mEmailAddr && mOrganization == other.mOrganization &&
00254 mReplyToAddr == other.mReplyToAddr && mBcc == other.mBcc &&
00255 mVCardFile == other.mVCardFile &&
00256 mFcc == other.mFcc &&
00257 mPGPEncryptionKey == other.mPGPEncryptionKey &&
00258 mPGPSigningKey == other.mPGPSigningKey &&
00259 mSMIMEEncryptionKey == other.mSMIMEEncryptionKey &&
00260 mSMIMESigningKey == other.mSMIMESigningKey &&
00261 mPreferredCryptoMessageFormat == other.mPreferredCryptoMessageFormat &&
00262 mDrafts == other.mDrafts && mTransport == other.mTransport &&
00263 mDictionary == other.mDictionary && mSignature == other.mSignature &&
00264 mXFace == other.mXFace && mXFaceEnabled == other.mXFaceEnabled;
00265
00266 #if 0
00267 if ( same )
00268 return true;
00269 if ( mUoid != other.mUoid ) kdDebug() << "mUoid differs : " << mUoid << " != " << other.mUoid << endl;
00270 if ( mIdentity != other.mIdentity ) kdDebug() << "mIdentity differs : " << mIdentity << " != " << other.mIdentity << endl;
00271 if ( mFullName != other.mFullName ) kdDebug() << "mFullName differs : " << mFullName << " != " << other.mFullName << endl;
00272 if ( mEmailAddr != other.mEmailAddr ) kdDebug() << "mEmailAddr differs : " << mEmailAddr << " != " << other.mEmailAddr << endl;
00273 if ( mOrganization != other.mOrganization ) kdDebug() << "mOrganization differs : " << mOrganization << " != " << other.mOrganization << endl;
00274 if ( mReplyToAddr != other.mReplyToAddr ) kdDebug() << "mReplyToAddr differs : " << mReplyToAddr << " != " << other.mReplyToAddr << endl;
00275 if ( mBcc != other.mBcc ) kdDebug() << "mBcc differs : " << mBcc << " != " << other.mBcc << endl;
00276 if ( mVCardFile != other.mVCardFile ) kdDebug() << "mVCardFile differs : " << mVCardFile << " != " << other.mVCardFile << endl;
00277 if ( mFcc != other.mFcc ) kdDebug() << "mFcc differs : " << mFcc << " != " << other.mFcc << endl;
00278 if ( mPGPEncryptionKey != other.mPGPEncryptionKey ) kdDebug() << "mPGPEncryptionKey differs : " << mPGPEncryptionKey << " != " << other.mPGPEncryptionKey << endl;
00279 if ( mPGPSigningKey != other.mPGPSigningKey ) kdDebug() << "mPGPSigningKey differs : " << mPGPSigningKey << " != " << other.mPGPSigningKey << endl;
00280 if ( mSMIMEEncryptionKey != other.mSMIMEEncryptionKey ) kdDebug() << "mSMIMEEncryptionKey differs : '" << mSMIMEEncryptionKey << "' != '" << other.mSMIMEEncryptionKey << "'" << endl;
00281 if ( mSMIMESigningKey != other.mSMIMESigningKey ) kdDebug() << "mSMIMESigningKey differs : " << mSMIMESigningKey << " != " << other.mSMIMESigningKey << endl;
00282 if ( mPreferredCryptoMessageFormat != other.mPreferredCryptoMessageFormat ) kdDebug() << "mPreferredCryptoMessageFormat differs : " << mPreferredCryptoMessageFormat << " != " << other.mPreferredCryptoMessageFormat << endl;
00283 if ( mDrafts != other.mDrafts ) kdDebug() << "mDrafts differs : " << mDrafts << " != " << other.mDrafts << endl;
00284 if ( mTransport != other.mTransport ) kdDebug() << "mTransport differs : " << mTransport << " != " << other.mTransport << endl;
00285 if ( mDictionary != other.mDictionary ) kdDebug() << "mDictionary differs : " << mDictionary << " != " << other.mDictionary << endl;
00286 if ( ! ( mSignature == other.mSignature ) ) kdDebug() << "mSignature differs" << endl;
00287 #endif
00288 return same;
00289 }
00290
00291 Identity::Identity( const QString & id, const QString & fullName,
00292 const QString & emailAddr, const QString & organization,
00293 const QString & replyToAddr )
00294 : mUoid( 0 ), mIdentity( id ), mFullName( fullName ),
00295 mEmailAddr( emailAddr ), mOrganization( organization ),
00296 mReplyToAddr( replyToAddr ),
00297
00298
00299 mBcc( "" ), mVCardFile( "" ), mPGPEncryptionKey( "" ), mPGPSigningKey( "" ),
00300 mSMIMEEncryptionKey( "" ), mSMIMESigningKey( "" ), mFcc( "" ), mDrafts( "" ), mTransport( "" ),
00301 mDictionary( "" ),
00302 mXFace( "" ), mXFaceEnabled( false ),
00303 mIsDefault( false ),
00304 mPreferredCryptoMessageFormat( Kleo::AutoFormat )
00305 {
00306 }
00307
00308 Identity::~Identity()
00309 {
00310 }
00311
00312
00313 void Identity::readConfig( const KConfigBase * config )
00314 {
00315 mUoid = config->readUnsignedNumEntry("uoid",0);
00316
00317 mIdentity = config->readEntry("Identity");
00318 mFullName = config->readEntry("Name");
00319 mEmailAddr = config->readEntry("Email Address");
00320 mVCardFile = config->readPathEntry("VCardFile");
00321 mOrganization = config->readEntry("Organization");
00322 mPGPSigningKey = config->readEntry("PGP Signing Key").latin1();
00323 mPGPEncryptionKey = config->readEntry("PGP Encryption Key").latin1();
00324 mSMIMESigningKey = config->readEntry("SMIME Signing Key").latin1();
00325 mSMIMEEncryptionKey = config->readEntry("SMIME Encryption Key").latin1();
00326 mPreferredCryptoMessageFormat = Kleo::stringToCryptoMessageFormat( config->readEntry("Preferred Crypto Message Format", "none" ) );
00327 mReplyToAddr = config->readEntry("Reply-To Address");
00328 mBcc = config->readEntry("Bcc");
00329 mFcc = config->readEntry("Fcc", "sent-mail");
00330 if( mFcc.isEmpty() )
00331 mFcc = "sent-mail";
00332 mDrafts = config->readEntry("Drafts", "drafts");
00333 if( mDrafts.isEmpty() )
00334 mDrafts = "drafts";
00335 mTransport = config->readEntry("Transport");
00336 mDictionary = config->readEntry( "Dictionary" );
00337 mXFace = config->readEntry( "X-Face" );
00338 mXFaceEnabled = config->readBoolEntry( "X-FaceEnabled", false );
00339
00340 mSignature.readConfig( config );
00341 kdDebug(5006) << "Identity::readConfig(): UOID = " << mUoid
00342 << " for identity named \"" << mIdentity << "\"" << endl;
00343 }
00344
00345
00346 void Identity::writeConfig( KConfigBase * config ) const
00347 {
00348 config->writeEntry("uoid", mUoid);
00349
00350 config->writeEntry("Identity", mIdentity);
00351 config->writeEntry("Name", mFullName);
00352 config->writeEntry("Organization", mOrganization);
00353 config->writeEntry("PGP Signing Key", mPGPSigningKey.data());
00354 config->writeEntry("PGP Encryption Key", mPGPEncryptionKey.data());
00355 config->writeEntry("SMIME Signing Key", mSMIMESigningKey.data());
00356 config->writeEntry("SMIME Encryption Key", mSMIMEEncryptionKey.data());
00357 config->writeEntry("Preferred Crypto Message Format", Kleo::cryptoMessageFormatToString( mPreferredCryptoMessageFormat ) );
00358 config->writeEntry("Email Address", mEmailAddr);
00359 config->writeEntry("Reply-To Address", mReplyToAddr);
00360 config->writeEntry("Bcc", mBcc);
00361 config->writePathEntry("VCardFile", mVCardFile);
00362 config->writeEntry("Transport", mTransport);
00363 config->writeEntry("Fcc", mFcc);
00364 config->writeEntry("Drafts", mDrafts);
00365 config->writeEntry( "Dictionary", mDictionary );
00366 config->writeEntry( "X-Face", mXFace );
00367 config->writeEntry( "X-FaceEnabled", mXFaceEnabled );
00368
00369 mSignature.writeConfig( config );
00370 }
00371
00372 QDataStream & KPIM::operator<<( QDataStream & stream, const KPIM::Identity & i ) {
00373 return stream << static_cast<Q_UINT32>(i.uoid())
00374 << i.identityName()
00375 << i.fullName()
00376 << i.organization()
00377 << i.pgpSigningKey()
00378 << i.pgpEncryptionKey()
00379 << i.smimeSigningKey()
00380 << i.smimeEncryptionKey()
00381 << i.emailAddr()
00382 << i.replyToAddr()
00383 << i.bcc()
00384 << i.vCardFile()
00385 << i.transport()
00386 << i.fcc()
00387 << i.drafts()
00388 << i.mSignature
00389 << i.dictionary()
00390 << i.xface()
00391 << QString( Kleo::cryptoMessageFormatToString( i.mPreferredCryptoMessageFormat ) );
00392 }
00393
00394 QDataStream & KPIM::operator>>( QDataStream & stream, KPIM::Identity & i ) {
00395 Q_UINT32 uoid;
00396 QString format;
00397 stream >> uoid
00398 >> i.mIdentity
00399 >> i.mFullName
00400 >> i.mOrganization
00401 >> i.mPGPSigningKey
00402 >> i.mPGPEncryptionKey
00403 >> i.mSMIMESigningKey
00404 >> i.mSMIMEEncryptionKey
00405 >> i.mEmailAddr
00406 >> i.mReplyToAddr
00407 >> i.mBcc
00408 >> i.mVCardFile
00409 >> i.mTransport
00410 >> i.mFcc
00411 >> i.mDrafts
00412 >> i.mSignature
00413 >> i.mDictionary
00414 >> i.mXFace
00415 >> format;
00416 i.mUoid = uoid;
00417 i.mPreferredCryptoMessageFormat = Kleo::stringToCryptoMessageFormat( format.latin1() );
00418
00419 return stream;
00420 }
00421
00422
00423 bool Identity::mailingAllowed() const
00424 {
00425 return !mEmailAddr.isEmpty();
00426 }
00427
00428
00429 void Identity::setIsDefault( bool flag ) {
00430 mIsDefault = flag;
00431 }
00432
00433 void Identity::setIdentityName( const QString & name ) {
00434 mIdentity = name;
00435 }
00436
00437 void Identity::setFullName(const QString &str)
00438 {
00439 mFullName = str;
00440 }
00441
00442
00443
00444 void Identity::setOrganization(const QString &str)
00445 {
00446 mOrganization = str;
00447 }
00448
00449 void Identity::setPGPSigningKey(const QCString &str)
00450 {
00451 mPGPSigningKey = str;
00452 if ( mPGPSigningKey.isNull() )
00453 mPGPSigningKey = "";
00454 }
00455
00456 void Identity::setPGPEncryptionKey(const QCString &str)
00457 {
00458 mPGPEncryptionKey = str;
00459 if ( mPGPEncryptionKey.isNull() )
00460 mPGPEncryptionKey = "";
00461 }
00462
00463 void Identity::setSMIMESigningKey(const QCString &str)
00464 {
00465 mSMIMESigningKey = str;
00466 if ( mSMIMESigningKey.isNull() )
00467 mSMIMESigningKey = "";
00468 }
00469
00470 void Identity::setSMIMEEncryptionKey(const QCString &str)
00471 {
00472 mSMIMEEncryptionKey = str;
00473 if ( mSMIMEEncryptionKey.isNull() )
00474 mSMIMEEncryptionKey = "";
00475 }
00476
00477
00478 void Identity::setEmailAddr(const QString &str)
00479 {
00480 mEmailAddr = str;
00481 }
00482
00483
00484
00485 void Identity::setVCardFile(const QString &str)
00486 {
00487 mVCardFile = str;
00488 }
00489
00490
00491
00492 QString Identity::fullEmailAddr(void) const
00493 {
00494 if (mFullName.isEmpty()) return mEmailAddr;
00495
00496 const QString specials("()<>@,.;:[]");
00497
00498 QString result;
00499
00500
00501 bool needsQuotes=false;
00502 for (unsigned int i=0; i < mFullName.length(); i++) {
00503 if ( specials.contains( mFullName[i] ) )
00504 needsQuotes = true;
00505 else if ( mFullName[i] == '\\' || mFullName[i] == '"' ) {
00506 needsQuotes = true;
00507 result += '\\';
00508 }
00509 result += mFullName[i];
00510 }
00511
00512 if (needsQuotes) {
00513 result.insert(0,'"');
00514 result += '"';
00515 }
00516
00517 result += " <" + mEmailAddr + '>';
00518
00519 return result;
00520 }
00521
00522
00523 void Identity::setReplyToAddr(const QString& str)
00524 {
00525 mReplyToAddr = str;
00526 }
00527
00528
00529
00530 void Identity::setSignatureFile(const QString &str)
00531 {
00532 mSignature.setUrl( str, signatureIsCommand() );
00533 }
00534
00535
00536
00537 void Identity::setSignatureInlineText(const QString &str )
00538 {
00539 mSignature.setText( str );
00540 }
00541
00542
00543
00544 void Identity::setTransport(const QString &str)
00545 {
00546 mTransport = str;
00547 if ( mTransport.isNull() )
00548 mTransport = "";
00549 }
00550
00551
00552 void Identity::setFcc(const QString &str)
00553 {
00554 mFcc = str;
00555 if ( mFcc.isNull() )
00556 mFcc = "";
00557 }
00558
00559
00560 void Identity::setDrafts(const QString &str)
00561 {
00562 mDrafts = str;
00563 if ( mDrafts.isNull() )
00564 mDrafts = "";
00565 }
00566
00567
00568
00569 void Identity::setDictionary( const QString &str )
00570 {
00571 mDictionary = str;
00572 if ( mDictionary.isNull() )
00573 mDictionary = "";
00574 }
00575
00576
00577
00578 void Identity::setXFace( const QString &str )
00579 {
00580 mXFace = str;
00581 mXFace.remove( " " );
00582 mXFace.remove( "\n" );
00583 mXFace.remove( "\r" );
00584 }
00585
00586
00587
00588 void Identity::setXFaceEnabled( const bool on )
00589 {
00590 mXFaceEnabled = on;
00591 }
00592
00593
00594
00595 QString Identity::signatureText( bool * ok ) const
00596 {
00597 bool internalOK = false;
00598 QString signatureText = mSignature.withSeparator( &internalOK );
00599 if ( internalOK ) {
00600 if ( ok ) *ok=true;
00601 return signatureText;
00602 }
00603
00604
00605
00606
00607 if ( ok ) *ok = false;
00608 return QString::null;
00609
00610 #if 0 // ### FIXME: error handling
00611 if (mSignatureFile.endsWith("|"))
00612 {
00613 }
00614 else
00615 {
00616 }
00617 #endif
00618
00619 return QString::null;
00620 }