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() && mTemplates.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 && mTemplates == other.mTemplates &&
00263 mTransport == other.mTransport &&
00264 mDictionary == other.mDictionary && mSignature == other.mSignature &&
00265 mXFace == other.mXFace && mXFaceEnabled == other.mXFaceEnabled;
00266
00267 #if 0
00268 if ( same )
00269 return true;
00270 if ( mUoid != other.mUoid ) kdDebug() << "mUoid differs : " << mUoid << " != " << other.mUoid << endl;
00271 if ( mIdentity != other.mIdentity ) kdDebug() << "mIdentity differs : " << mIdentity << " != " << other.mIdentity << endl;
00272 if ( mFullName != other.mFullName ) kdDebug() << "mFullName differs : " << mFullName << " != " << other.mFullName << endl;
00273 if ( mEmailAddr != other.mEmailAddr ) kdDebug() << "mEmailAddr differs : " << mEmailAddr << " != " << other.mEmailAddr << endl;
00274 if ( mOrganization != other.mOrganization ) kdDebug() << "mOrganization differs : " << mOrganization << " != " << other.mOrganization << endl;
00275 if ( mReplyToAddr != other.mReplyToAddr ) kdDebug() << "mReplyToAddr differs : " << mReplyToAddr << " != " << other.mReplyToAddr << endl;
00276 if ( mBcc != other.mBcc ) kdDebug() << "mBcc differs : " << mBcc << " != " << other.mBcc << endl;
00277 if ( mVCardFile != other.mVCardFile ) kdDebug() << "mVCardFile differs : " << mVCardFile << " != " << other.mVCardFile << endl;
00278 if ( mFcc != other.mFcc ) kdDebug() << "mFcc differs : " << mFcc << " != " << other.mFcc << endl;
00279 if ( mPGPEncryptionKey != other.mPGPEncryptionKey ) kdDebug() << "mPGPEncryptionKey differs : " << mPGPEncryptionKey << " != " << other.mPGPEncryptionKey << endl;
00280 if ( mPGPSigningKey != other.mPGPSigningKey ) kdDebug() << "mPGPSigningKey differs : " << mPGPSigningKey << " != " << other.mPGPSigningKey << endl;
00281 if ( mSMIMEEncryptionKey != other.mSMIMEEncryptionKey ) kdDebug() << "mSMIMEEncryptionKey differs : '" << mSMIMEEncryptionKey << "' != '" << other.mSMIMEEncryptionKey << "'" << endl;
00282 if ( mSMIMESigningKey != other.mSMIMESigningKey ) kdDebug() << "mSMIMESigningKey differs : " << mSMIMESigningKey << " != " << other.mSMIMESigningKey << endl;
00283 if ( mPreferredCryptoMessageFormat != other.mPreferredCryptoMessageFormat ) kdDebug() << "mPreferredCryptoMessageFormat differs : " << mPreferredCryptoMessageFormat << " != " << other.mPreferredCryptoMessageFormat << endl;
00284 if ( mDrafts != other.mDrafts ) kdDebug() << "mDrafts differs : " << mDrafts << " != " << other.mDrafts << endl;
00285 if ( mTemplates != other.mTemplates ) kdDebug() << "mTemplates differs : " << mTemplates << " != " << other.mTemplates << endl;
00286 if ( mTransport != other.mTransport ) kdDebug() << "mTransport differs : " << mTransport << " != " << other.mTransport << endl;
00287 if ( mDictionary != other.mDictionary ) kdDebug() << "mDictionary differs : " << mDictionary << " != " << other.mDictionary << endl;
00288 if ( ! ( mSignature == other.mSignature ) ) kdDebug() << "mSignature differs" << endl;
00289 #endif
00290 return same;
00291 }
00292
00293 Identity::Identity( const QString & id, const QString & fullName,
00294 const QString & emailAddr, const QString & organization,
00295 const QString & replyToAddr )
00296 : mUoid( 0 ), mIdentity( id ), mFullName( fullName ),
00297 mEmailAddr( emailAddr ), mOrganization( organization ),
00298 mReplyToAddr( replyToAddr ),
00299
00300
00301 mBcc( "" ), mVCardFile( "" ), mPGPEncryptionKey( "" ), mPGPSigningKey( "" ),
00302 mSMIMEEncryptionKey( "" ), mSMIMESigningKey( "" ), mFcc( "" ),
00303 mDrafts( "" ), mTemplates( "" ), mTransport( "" ),
00304 mDictionary( "" ),
00305 mXFace( "" ), mXFaceEnabled( false ),
00306 mIsDefault( false ),
00307 mPreferredCryptoMessageFormat( Kleo::AutoFormat )
00308 {
00309 }
00310
00311 Identity::~Identity()
00312 {
00313 }
00314
00315
00316 void Identity::readConfig( const KConfigBase * config )
00317 {
00318 mUoid = config->readUnsignedNumEntry("uoid",0);
00319
00320 mIdentity = config->readEntry("Identity");
00321 mFullName = config->readEntry("Name");
00322 mEmailAddr = config->readEntry("Email Address");
00323 mVCardFile = config->readPathEntry("VCardFile");
00324 mOrganization = config->readEntry("Organization");
00325 mPGPSigningKey = config->readEntry("PGP Signing Key").latin1();
00326 mPGPEncryptionKey = config->readEntry("PGP Encryption Key").latin1();
00327 mSMIMESigningKey = config->readEntry("SMIME Signing Key").latin1();
00328 mSMIMEEncryptionKey = config->readEntry("SMIME Encryption Key").latin1();
00329 mPreferredCryptoMessageFormat = Kleo::stringToCryptoMessageFormat( config->readEntry("Preferred Crypto Message Format", "none" ) );
00330 mReplyToAddr = config->readEntry( "Reply-To Address" );
00331 mBcc = config->readEntry( "Bcc" );
00332 mFcc = config->readEntry( "Fcc", "sent-mail" );
00333 if( mFcc.isEmpty() )
00334 mFcc = "sent-mail";
00335 mDrafts = config->readEntry( "Drafts", "drafts" );
00336 if( mDrafts.isEmpty() )
00337 mDrafts = "drafts";
00338 mTemplates = config->readEntry( "Templates", "templates" );
00339 if( mTemplates.isEmpty() )
00340 mTemplates = "templates";
00341 mTransport = config->readEntry( "Transport" );
00342 mDictionary = config->readEntry( "Dictionary" );
00343 mXFace = config->readEntry( "X-Face" );
00344 mXFaceEnabled = config->readBoolEntry( "X-FaceEnabled", false );
00345
00346 mSignature.readConfig( config );
00347 kdDebug(5006) << "Identity::readConfig(): UOID = " << mUoid
00348 << " for identity named \"" << mIdentity << "\"" << endl;
00349 }
00350
00351
00352 void Identity::writeConfig( KConfigBase * config ) const
00353 {
00354 config->writeEntry("uoid", mUoid);
00355
00356 config->writeEntry("Identity", mIdentity);
00357 config->writeEntry("Name", mFullName);
00358 config->writeEntry("Organization", mOrganization);
00359 config->writeEntry("PGP Signing Key", mPGPSigningKey.data());
00360 config->writeEntry("PGP Encryption Key", mPGPEncryptionKey.data());
00361 config->writeEntry("SMIME Signing Key", mSMIMESigningKey.data());
00362 config->writeEntry("SMIME Encryption Key", mSMIMEEncryptionKey.data());
00363 config->writeEntry("Preferred Crypto Message Format", Kleo::cryptoMessageFormatToString( mPreferredCryptoMessageFormat ) );
00364 config->writeEntry("Email Address", mEmailAddr);
00365 config->writeEntry("Reply-To Address", mReplyToAddr);
00366 config->writeEntry("Bcc", mBcc);
00367 config->writePathEntry("VCardFile", mVCardFile);
00368 config->writeEntry("Transport", mTransport);
00369 config->writeEntry("Fcc", mFcc);
00370 config->writeEntry("Drafts", mDrafts);
00371 config->writeEntry("Templates", mTemplates);
00372 config->writeEntry( "Dictionary", mDictionary );
00373 config->writeEntry( "X-Face", mXFace );
00374 config->writeEntry( "X-FaceEnabled", mXFaceEnabled );
00375
00376 mSignature.writeConfig( config );
00377 }
00378
00379 QDataStream & KPIM::operator<<( QDataStream & stream, const KPIM::Identity & i ) {
00380 return stream << static_cast<Q_UINT32>(i.uoid())
00381 << i.identityName()
00382 << i.fullName()
00383 << i.organization()
00384 << i.pgpSigningKey()
00385 << i.pgpEncryptionKey()
00386 << i.smimeSigningKey()
00387 << i.smimeEncryptionKey()
00388 << i.emailAddr()
00389 << i.replyToAddr()
00390 << i.bcc()
00391 << i.vCardFile()
00392 << i.transport()
00393 << i.fcc()
00394 << i.drafts()
00395 << i.templates()
00396 << i.mSignature
00397 << i.dictionary()
00398 << i.xface()
00399 << QString( Kleo::cryptoMessageFormatToString( i.mPreferredCryptoMessageFormat ) );
00400 }
00401
00402 QDataStream & KPIM::operator>>( QDataStream & stream, KPIM::Identity & i ) {
00403 Q_UINT32 uoid;
00404 QString format;
00405 stream >> uoid
00406 >> i.mIdentity
00407 >> i.mFullName
00408 >> i.mOrganization
00409 >> i.mPGPSigningKey
00410 >> i.mPGPEncryptionKey
00411 >> i.mSMIMESigningKey
00412 >> i.mSMIMEEncryptionKey
00413 >> i.mEmailAddr
00414 >> i.mReplyToAddr
00415 >> i.mBcc
00416 >> i.mVCardFile
00417 >> i.mTransport
00418 >> i.mFcc
00419 >> i.mDrafts
00420 >> i.mTemplates
00421 >> i.mSignature
00422 >> i.mDictionary
00423 >> i.mXFace
00424 >> format;
00425 i.mUoid = uoid;
00426 i.mPreferredCryptoMessageFormat = Kleo::stringToCryptoMessageFormat( format.latin1() );
00427
00428 return stream;
00429 }
00430
00431
00432 bool Identity::mailingAllowed() const
00433 {
00434 return !mEmailAddr.isEmpty();
00435 }
00436
00437
00438 void Identity::setIsDefault( bool flag ) {
00439 mIsDefault = flag;
00440 }
00441
00442 void Identity::setIdentityName( const QString & name ) {
00443 mIdentity = name;
00444 }
00445
00446 void Identity::setFullName(const QString &str)
00447 {
00448 mFullName = str;
00449 }
00450
00451
00452
00453 void Identity::setOrganization(const QString &str)
00454 {
00455 mOrganization = str;
00456 }
00457
00458 void Identity::setPGPSigningKey(const QCString &str)
00459 {
00460 mPGPSigningKey = str;
00461 if ( mPGPSigningKey.isNull() )
00462 mPGPSigningKey = "";
00463 }
00464
00465 void Identity::setPGPEncryptionKey(const QCString &str)
00466 {
00467 mPGPEncryptionKey = str;
00468 if ( mPGPEncryptionKey.isNull() )
00469 mPGPEncryptionKey = "";
00470 }
00471
00472 void Identity::setSMIMESigningKey(const QCString &str)
00473 {
00474 mSMIMESigningKey = str;
00475 if ( mSMIMESigningKey.isNull() )
00476 mSMIMESigningKey = "";
00477 }
00478
00479 void Identity::setSMIMEEncryptionKey(const QCString &str)
00480 {
00481 mSMIMEEncryptionKey = str;
00482 if ( mSMIMEEncryptionKey.isNull() )
00483 mSMIMEEncryptionKey = "";
00484 }
00485
00486
00487 void Identity::setEmailAddr(const QString &str)
00488 {
00489 mEmailAddr = str;
00490 }
00491
00492
00493
00494 void Identity::setVCardFile(const QString &str)
00495 {
00496 mVCardFile = str;
00497 }
00498
00499
00500
00501 QString Identity::fullEmailAddr(void) const
00502 {
00503 if (mFullName.isEmpty()) return mEmailAddr;
00504
00505 const QString specials("()<>@,.;:[]");
00506
00507 QString result;
00508
00509
00510 bool needsQuotes=false;
00511 for (unsigned int i=0; i < mFullName.length(); i++) {
00512 if ( specials.contains( mFullName[i] ) )
00513 needsQuotes = true;
00514 else if ( mFullName[i] == '\\' || mFullName[i] == '"' ) {
00515 needsQuotes = true;
00516 result += '\\';
00517 }
00518 result += mFullName[i];
00519 }
00520
00521 if (needsQuotes) {
00522 result.insert(0,'"');
00523 result += '"';
00524 }
00525
00526 result += " <" + mEmailAddr + '>';
00527
00528 return result;
00529 }
00530
00531
00532 void Identity::setReplyToAddr(const QString& str)
00533 {
00534 mReplyToAddr = str;
00535 }
00536
00537
00538
00539 void Identity::setSignatureFile(const QString &str)
00540 {
00541 mSignature.setUrl( str, signatureIsCommand() );
00542 }
00543
00544
00545
00546 void Identity::setSignatureInlineText(const QString &str )
00547 {
00548 mSignature.setText( str );
00549 }
00550
00551
00552
00553 void Identity::setTransport( const QString &str )
00554 {
00555 mTransport = str;
00556 if ( mTransport.isNull() )
00557 mTransport = "";
00558 }
00559
00560
00561 void Identity::setFcc( const QString &str )
00562 {
00563 mFcc = str;
00564 if ( mFcc.isNull() )
00565 mFcc = "";
00566 }
00567
00568
00569 void Identity::setDrafts( const QString &str )
00570 {
00571 mDrafts = str;
00572 if ( mDrafts.isNull() )
00573 mDrafts = "";
00574 }
00575
00576
00577 void Identity::setTemplates( const QString &str )
00578 {
00579 mTemplates = str;
00580 if ( mTemplates.isNull() )
00581 mTemplates = "";
00582 }
00583
00584
00585 void Identity::setDictionary( const QString &str )
00586 {
00587 mDictionary = str;
00588 if ( mDictionary.isNull() )
00589 mDictionary = "";
00590 }
00591
00592
00593
00594 void Identity::setXFace( const QString &str )
00595 {
00596 mXFace = str;
00597 mXFace.remove( " " );
00598 mXFace.remove( "\n" );
00599 mXFace.remove( "\r" );
00600 }
00601
00602
00603
00604 void Identity::setXFaceEnabled( const bool on )
00605 {
00606 mXFaceEnabled = on;
00607 }
00608
00609
00610
00611 QString Identity::signatureText( bool * ok ) const
00612 {
00613 bool internalOK = false;
00614 QString signatureText = mSignature.withSeparator( &internalOK );
00615 if ( internalOK ) {
00616 if ( ok ) *ok=true;
00617 return signatureText;
00618 }
00619
00620
00621
00622
00623 if ( ok ) *ok = false;
00624 return QString::null;
00625
00626 #if 0 // ### FIXME: error handling
00627 if (mSignatureFile.endsWith("|"))
00628 {
00629 }
00630 else
00631 {
00632 }
00633 #endif
00634
00635 return QString::null;
00636 }