certmanager/lib

chiasmusbackend.cpp
00001 /*
00002     chiasmusbackend.cpp
00003 
00004     This file is part of libkleopatra, the KDE keymanagement library
00005     Copyright (c) 2005 Klarälvdalens Datakonsult AB
00006 
00007     Libkleopatra is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU General Public License as
00009     published by the Free Software Foundation; either version 2 of the
00010     License, or (at your option) any later version.
00011 
00012     Libkleopatra is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021     In addition, as a special exception, the copyright holders give
00022     permission to link the code of this program with any edition of
00023     the TQt library by Trolltech AS, Norway (or with modified versions
00024     of TQt that use the same license as TQt), and distribute linked
00025     combinations including the two.  You must obey the GNU General
00026     Public License in all respects for all of the code used other than
00027     TQt.  If you modify this file, you may extend this exception to
00028     your version of the file, but you are not obligated to do so.  If
00029     you do not wish to do so, delete this exception statement from
00030     your version.
00031 */
00032 
00033 #ifdef HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036 
00037 #include "chiasmusbackend.h"
00038 
00039 #include "config_data.h"
00040 #include "obtainkeysjob.h"
00041 #include "chiasmusjob.h"
00042 
00043 #include "kleo/cryptoconfig.h"
00044 
00045 #include <tdelocale.h>
00046 #include <tdeconfig.h>
00047 #include <kshell.h>
00048 #include <kdebug.h>
00049 
00050 #include <tqstringlist.h>
00051 #include <tqvariant.h>
00052 #include <tqfileinfo.h>
00053 
00054 #include <map>
00055 #include <memory>
00056 
00057 #include <cassert>
00058 
00059 namespace {
00060 
00061   //
00062   // The usual TQVariant template helpers:
00063   //
00064 
00065   // to<> is a demarshaller. It's a class b/c you can't partially
00066   // specialise function templates yet. However, to<> can be used as if
00067   // it was a function: TQString s = to<TQString>( myVariant );
00068   template <typename T> class to {};
00069 
00070 #define MAKE_TO( type, func ) \
00071   template <> \
00072   class to< type > { \
00073     type m; \
00074   public: \
00075     to( const TQVariant & v ) : m( v.func() ) {} \
00076     operator type() const { return m; } \
00077   }
00078 
00079   MAKE_TO( int, toInt );
00080   MAKE_TO( unsigned int, toUInt );
00081 
00082   template <>
00083   class to<KURL> {
00084     KURL m;
00085   public:
00086     to( const TQVariant & v ) {
00087       m.setPath( v.toString() );
00088     }
00089     operator KURL() const { return m; }
00090   };
00091 
00092   template <typename T>
00093   class to< TQValueList<T> > {
00094     TQValueList<T> m;
00095   public:
00096     to( const TQVariant & v ) {
00097       const TQValueList<TQVariant> vl = v.toList();
00098       for ( TQValueList<TQVariant>::const_iterator it = vl.begin(), end = vl.end() ; it != end ; ++it )
00099         m.push_back( to<T>( *it ) );
00100     }
00101     operator TQValueList<T> () const { return m; }
00102   };
00103 
00104   template <>
00105   class to<KURL::List> {
00106     KURL::List m;
00107   public:
00108     to( const TQVariant & v ) {
00109       // wow, KURL::List is broken... it lacks conversion from and to TQVL<KURL>...
00110       m += to< TQValueList<KURL> >( v );
00111     }
00112     operator KURL::List() const { return m; }
00113   };
00114 
00115 
00116   // from<> is the demarshaller. See to<> for why this is a class...
00117 
00118   template <typename T>
00119   struct from_helper : public TQVariant {
00120     from_helper( const T & t ) : TQVariant( t ) {}
00121   };
00122 
00123   template <typename T>
00124   TQVariant from( const T & t ) {
00125     return from_helper<T>( t );
00126   }
00127 
00128   // some special types:
00129   template <> struct from_helper<KURL> : public TQVariant {
00130     from_helper( const KURL & url ) : TQVariant( url.path() ) {}
00131   };
00132   template <typename T> struct from_helper< TQValueList<T> > : public TQVariant {
00133     from_helper( const TQValueList<T> & l ) {
00134       TQValueList<TQVariant> result;
00135       for ( typename TQValueList<T>::const_iterator it = l.begin(), end = l.end() ; it != end ; ++it )
00136         result.push_back( from( *it ) );
00137       TQVariant::operator=( result );
00138     }
00139   };
00140   template <> struct from_helper<KURL::List> : public from_helper< TQValueList<KURL> > {
00141     from_helper( const KURL::List & l ) : from_helper< TQValueList<KURL> >( l ) {}
00142   };
00143 
00144   class ChiasmusConfigEntry : public Kleo::CryptoConfigEntry {
00145     unsigned int mIdx;
00146     TQVariant mValue;
00147     bool mDirty;
00148   public:
00149     ChiasmusConfigEntry( unsigned int i )
00150       : Kleo::CryptoConfigEntry(),
00151         mIdx( i ), mValue( defaultValue() ), mDirty( false )
00152     {
00153       assert( i < kleo_chiasmus_config_entries_dim );
00154     }
00155     TQString name() const { return kleo_chiasmus_config_entries[mIdx].name; }
00156     TQString description() const { return i18n( kleo_chiasmus_config_entries[mIdx].description ); }
00157     bool isOptional() const { return kleo_chiasmus_config_entries[mIdx].is_optional; }
00158     bool isReadOnly() const { return false; }
00159     bool isList() const { return kleo_chiasmus_config_entries[mIdx].is_list; }
00160     bool isRuntime() const { return kleo_chiasmus_config_entries[mIdx].is_runtime; }
00161     Level level() const { return static_cast<Level>( kleo_chiasmus_config_entries[mIdx].level ); }
00162     ArgType argType() const { return static_cast<ArgType>( kleo_chiasmus_config_entries[mIdx].type ); }
00163     bool isSet() const { return mValue != defaultValue(); }
00164     bool boolValue() const { return mValue.toBool(); }
00165     TQString stringValue() const { return mValue.toString(); }
00166     int intValue() const { return mValue.toInt(); }
00167     unsigned int uintValue() const { return mValue.toUInt(); }
00168     KURL urlValue() const {
00169       if ( argType() != ArgType_Path && argType() != ArgType_DirPath ) return KURL( mValue.toString() );
00170       KURL u; u.setPath( mValue.toString() ); return u;
00171     }
00172     unsigned int numberOfTimesSet() const { return 0; }
00173     TQStringList stringValueList() const { return mValue.toStringList(); }
00174     TQValueList<int> intValueList() const { return to< TQValueList<int> >( mValue ); }
00175     TQValueList<unsigned int> uintValueList() const { return to< TQValueList<unsigned int> >( mValue ); }
00176     KURL::List urlValueList() const {
00177       if ( argType() != ArgType_Path && argType()!= ArgType_DirPath ) return mValue.toStringList();
00178       else return to<KURL::List>( mValue ); }
00179     void resetToDefault() { mValue = defaultValue(); mDirty = false; }
00180     void setBoolValue( bool value ) { setValue( TQVariant( value ) ); }
00181     void setStringValue( const TQString & value ) { setValue( value ); }
00182     void setIntValue( int value ) { setValue( value ); }
00183     void setUIntValue( unsigned int value ) { setValue( value ); }
00184     void setURLValue( const KURL & value ) {
00185       if ( argType() != ArgType_Path && argType()!= ArgType_DirPath ) setValue( value.url() );
00186       else setValue( value.path() );
00187     }
00188     void setNumberOfTimesSet( unsigned int ) {}
00189     void setStringValueList( const TQStringList & value ) { setValue( value ); }
00190     void setIntValueList( const TQValueList<int> & l ) { setValue( from( l ) ); }
00191     void setUIntValueList( const TQValueList<unsigned int> & l ) { setValue( from( l ) ); }
00192     void setURLValueList( const KURL::List & l ) { setValue( from( l ) ); }
00193     bool isDirty() const { return mDirty; }
00194 
00195     TQVariant value() const { return mValue; }
00196 
00197     void sync( TDEConfigBase * config ) {
00198       if ( !mDirty )
00199         return;
00200       mDirty = false;
00201       config->writeEntry( kleo_chiasmus_config_entries[mIdx].name, mValue );
00202     }
00203     void read( const TDEConfigBase * config ) {
00204       mDirty = false;
00205       mValue = config->readPropertyEntry( kleo_chiasmus_config_entries[mIdx].name, defaultValue() );
00206     }
00207   private:
00208     TQVariant defaultValue() const;
00209     void setValue( const TQVariant & value ) { mValue = value; mDirty = true; }
00210   };
00211 
00212   TQVariant ChiasmusConfigEntry::defaultValue() const {
00213     const kleo_chiasmus_config_data & data = kleo_chiasmus_config_entries[mIdx];
00214     switch ( data.type ) {
00215     default:
00216       return TQVariant();
00217     case ArgType_None:
00218       if ( isList() )
00219         return TQValueList<TQVariant>() << TQVariant( data.defaults.boolean.value );
00220       else
00221         return TQVariant( data.defaults.boolean.value );
00222     case ArgType_String:
00223       if ( isList() )
00224         return TQStringList( TQString::fromLatin1( data.defaults.string ) );
00225       else
00226         return TQString::fromLatin1( data.defaults.string );
00227     case ArgType_Int:
00228       if ( isList() )
00229         return TQValueList<TQVariant>() << data.defaults.integer;
00230       else
00231         return data.defaults.integer;
00232     case ArgType_UInt:
00233       if ( isList() )
00234         return TQValueList<TQVariant>() << data.defaults.unsigned_integer;
00235       else
00236         return data.defaults.unsigned_integer;
00237     case ArgType_Path:
00238     case ArgType_DirPath:
00239       if ( isList() )
00240         return TQValueList<TQVariant>() << TQString::fromLatin1( data.defaults.path );
00241       else
00242         return TQString::fromLatin1( data.defaults.path );
00243     case ArgType_URL:
00244     case ArgType_LDAPURL:
00245       if ( isList() )
00246         return TQValueList<TQVariant>() << TQString::fromLatin1( data.defaults.url );
00247       else
00248         return TQString::fromLatin1( data.defaults.url );
00249     }
00250   }
00251 
00252   class ChiasmusGeneralGroup : public Kleo::CryptoConfigGroup {
00253     mutable std::map<TQString,ChiasmusConfigEntry*> mCache;
00254     mutable TDEConfig * mConfigObject;
00255   public:
00256     ChiasmusGeneralGroup() : Kleo::CryptoConfigGroup(), mConfigObject( 0 ) {}
00257     ~ChiasmusGeneralGroup() { clear(); delete mConfigObject; }
00258     TQString name() const { return "General"; }
00259     TQString iconName() const { return "chiasmus_chi"; }
00260     TQString description() const { return i18n( "General" ); }
00261     Kleo::CryptoConfigEntry::Level level() const { return Kleo::CryptoConfigEntry::Level_Basic; }
00262     TQStringList entryList() const {
00263       TQStringList result;
00264       for ( unsigned int i = 0 ; i < kleo_chiasmus_config_entries_dim ; ++i )
00265         result.push_back( kleo_chiasmus_config_entries[i].name );
00266       return result;
00267     }
00268     Kleo::CryptoConfigEntry * entry( const TQString & name ) const {
00269       if ( ChiasmusConfigEntry * entry = mCache[name] )
00270         return entry;
00271       const TDEConfigGroup group( configObject(), "Chiasmus" );
00272       for ( unsigned int i = 0 ; i < kleo_chiasmus_config_entries_dim ; ++i )
00273         if ( name == kleo_chiasmus_config_entries[i].name ) {
00274           ChiasmusConfigEntry * entry = new ChiasmusConfigEntry( i );
00275           entry->read( &group );
00276           return mCache[name] = entry;
00277         }
00278       return 0;
00279     }
00280 
00281     void sync() {
00282       TDEConfigGroup group( configObject(), "Chiasmus" );
00283       for ( std::map<TQString,ChiasmusConfigEntry*>::const_iterator it = mCache.begin(), end = mCache.end() ; it != end ; ++it )
00284         it->second->sync( &group );
00285       group.sync();
00286       clear();
00287     }
00288   private:
00289     TDEConfig * configObject() const {
00290       if ( !mConfigObject )
00291         // this is unsafe. We're a lib, used by concurrent apps.
00292         mConfigObject = new TDEConfig( "chiasmusbackendrc" );
00293       return mConfigObject;
00294     }
00295     void clear() {
00296       for ( std::map<TQString,ChiasmusConfigEntry*>::const_iterator it = mCache.begin(), end = mCache.end() ; it != end ; ++it )
00297         delete it->second;
00298       mCache.clear();
00299     }
00300   };
00301 
00302   class ChiasmusComponent : public Kleo::CryptoConfigComponent {
00303     mutable ChiasmusGeneralGroup * mGeneralGroup;
00304   public:
00305     ChiasmusComponent() : Kleo::CryptoConfigComponent(), mGeneralGroup( 0 ) {}
00306     ~ChiasmusComponent() { delete mGeneralGroup; }
00307 
00308     void sync() {
00309       if ( mGeneralGroup )
00310         mGeneralGroup->sync();
00311     }
00312 
00313     TQString name() const { return "Chiasmus"; }
00314     TQString iconName() const { return "chiasmus_chi"; }
00315     TQString description() const { return i18n( "Chiasmus" ); }
00316     TQStringList groupList() const { return TQStringList() << "General"; }
00317     Kleo::CryptoConfigGroup * group( const TQString & name ) const {
00318       if ( name != "General" )
00319         return 0;
00320       if ( !mGeneralGroup )
00321         mGeneralGroup = new ChiasmusGeneralGroup();
00322       return mGeneralGroup;
00323     }
00324   };
00325 
00326 }
00327 
00328 class Kleo::ChiasmusBackend::CryptoConfig : public Kleo::CryptoConfig {
00329   mutable ChiasmusComponent * mComponent;
00330 public:
00331   CryptoConfig() : Kleo::CryptoConfig(), mComponent( 0 ) {}
00332   ~CryptoConfig() { delete mComponent; }
00333 
00334   TQStringList componentList() const { return TQStringList() << "Chiasmus" ; }
00335   ChiasmusComponent * component( const TQString & name ) const {
00336     if ( name != "Chiasmus" )
00337       return 0;
00338     if ( !mComponent )
00339       mComponent = new ChiasmusComponent();
00340     return mComponent;
00341   }
00342   void sync( bool ) {
00343     if ( mComponent )
00344       mComponent->sync();
00345   }
00346   void clear() { delete mComponent; mComponent = 0; }
00347 };
00348 
00349 class Kleo::ChiasmusBackend::Protocol : public Kleo::CryptoBackend::Protocol {
00350   Kleo::CryptoConfig * mCryptoConfig;
00351 public:
00352   Protocol( Kleo::CryptoConfig * config )
00353     : Kleo::CryptoBackend::Protocol(), mCryptoConfig( config )
00354   {
00355     assert( config );
00356   }
00357   ~Protocol() {}
00358 
00359   TQString name() const { return "Chiasmus"; }
00360   TQString displayName() const { return i18n( "Chiasmus command line tool" ); }
00361   KeyListJob * keyListJob( bool, bool, bool ) const { return 0; }
00362   EncryptJob * encryptJob( bool, bool ) const { return 0; }
00363   DecryptJob * decryptJob() const { return 0; }
00364   SignJob * signJob( bool, bool ) const { return 0; }
00365   VerifyDetachedJob * verifyDetachedJob( bool ) const { return 0; }
00366   VerifyOpaqueJob * verifyOpaqueJob( bool ) const { return 0; }
00367   KeyGenerationJob * keyGenerationJob() const { return 0; }
00368   ImportJob * importJob() const { return 0; }
00369   ExportJob * publicKeyExportJob( bool ) const { return 0; }
00370   ExportJob * secretKeyExportJob( bool, const TQString& ) const { return 0; }
00371   DownloadJob * downloadJob( bool ) const { return 0; }
00372   DeleteJob * deleteJob() const { return 0; }
00373   SignEncryptJob * signEncryptJob( bool, bool ) const { return 0; }
00374   DecryptVerifyJob * decryptVerifyJob( bool ) const { return 0; }
00375   RefreshKeysJob * refreshKeysJob() const { return 0; }
00376 
00377   SpecialJob * specialJob( const char * type, const TQStringVariantMap & args ) const {
00378     if ( tqstricmp( type, "x-obtain-keys" ) == 0 && args.size() == 0 )
00379       return new ObtainKeysJob();
00380     if ( tqstricmp( type, "x-encrypt" ) == 0 && args.size() == 0 )
00381       return new ChiasmusJob( ChiasmusJob::Encrypt );
00382     if ( tqstricmp( type, "x-decrypt" ) == 0 && args.size() == 0 )
00383       return new ChiasmusJob( ChiasmusJob::Decrypt );
00384     kdDebug(5150) << "ChiasmusBackend::Protocol: tried to instantiate unknown job type \""
00385                   << type << "\"" << endl;
00386 
00387     return 0;
00388   }
00389 };
00390 
00391 Kleo::ChiasmusBackend * Kleo::ChiasmusBackend::self = 0;
00392 
00393 Kleo::ChiasmusBackend::ChiasmusBackend()
00394   : Kleo::CryptoBackend(),
00395     mCryptoConfig( 0 ),
00396     mProtocol( 0 )
00397 {
00398   self = this;
00399 }
00400 
00401 Kleo::ChiasmusBackend::~ChiasmusBackend() {
00402   self = 0;
00403   delete mCryptoConfig;
00404   delete mProtocol;
00405 }
00406 
00407 TQString Kleo::ChiasmusBackend::name() const {
00408   return "Chiasmus";
00409 }
00410 
00411 TQString Kleo::ChiasmusBackend::displayName() const {
00412   return i18n( "Chiasmus" );
00413 }
00414 
00415 Kleo::CryptoConfig * Kleo::ChiasmusBackend::config() const {
00416   if ( !mCryptoConfig )
00417     mCryptoConfig = new CryptoConfig();
00418   return mCryptoConfig;
00419 }
00420 
00421 Kleo::CryptoBackend::Protocol * Kleo::ChiasmusBackend::protocol( const char * name ) const {
00422   if ( tqstricmp( name, "Chiasmus" ) != 0 )
00423     return 0;
00424   if ( !mProtocol )
00425     if ( checkForChiasmus() )
00426       mProtocol = new Protocol( config() );
00427   return mProtocol;
00428 }
00429 
00430 bool Kleo::ChiasmusBackend::checkForOpenPGP( TQString * reason ) const {
00431   if ( reason )
00432     *reason = i18n( "Unsupported protocol \"%1\"" ).arg( "OpenPGP" );
00433   return false;
00434 }
00435 
00436 bool Kleo::ChiasmusBackend::checkForSMIME( TQString * reason ) const {
00437   if ( reason )
00438     *reason = i18n( "Unsupported protocol \"%1\"" ).arg( "SMIME" );
00439   return false;
00440 }
00441 
00442 bool Kleo::ChiasmusBackend::checkForChiasmus( TQString * reason ) const {
00443 
00444   // kills the protocol instance when we return false:
00445   std::auto_ptr<Protocol> tmp( mProtocol );
00446   mProtocol = 0;
00447 
00448   const CryptoConfigEntry * path = config()->entry( "Chiasmus", "General", "path" );
00449   assert( path ); assert( path->argType() == CryptoConfigEntry::ArgType_Path );
00450   const TQString chiasmus = path->urlValue().path();
00451   const TQFileInfo fi( KShell::tildeExpand( chiasmus ) );
00452   if ( !fi.isExecutable() ) {
00453     if ( reason )
00454       *reason = i18n( "File \"%1\" does not exist or is not executable." ).arg( chiasmus );
00455     return false;
00456   }
00457 
00458   // FIXME: more checks?
00459   mProtocol = tmp.release();
00460   return true;
00461 }
00462 
00463 bool Kleo::ChiasmusBackend::checkForProtocol( const char * name, TQString * reason ) const {
00464   if ( tqstricmp( name, "Chiasmus" ) == 0 )
00465     return checkForChiasmus( reason );
00466   if ( reason )
00467     *reason = i18n( "Unsupported protocol \"%1\"" ).arg( name );
00468   return 0;
00469 }
00470 
00471 bool Kleo::ChiasmusBackend::supportsProtocol( const char * name ) const {
00472   return tqstricmp( name, "Chiasmus" ) == 0;
00473 }
00474 
00475 const char * Kleo::ChiasmusBackend::enumerateProtocols( int i ) const {
00476   return i == 0 ? "Chiasmus" : 0 ;
00477 }