TDE personal information management applications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

qgpgmecryptoconfig.cpp 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. /*
  2. qgpgmecryptoconfig.cpp
  3. This file is part of libkleopatra, the KDE keymanagement library
  4. Copyright (c) 2004 Klarälvdalens Datakonsult AB
  5. Libkleopatra is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the
  8. License, or (at your option) any later version.
  9. Libkleopatra is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. In addition, as a special exception, the copyright holders give
  17. permission to link the code of this program with any edition of
  18. the Qt library by Trolltech AS, Norway (or with modified versions
  19. of Qt that use the same license as Qt), and distribute linked
  20. combinations including the two. You must obey the GNU General
  21. Public License in all respects for all of the code used other than
  22. Qt. If you modify this file, you may extend this exception to
  23. your version of the file, but you are not obligated to do so. If
  24. you do not wish to do so, delete this exception statement from
  25. your version.
  26. */
  27. #include "qgpgmecryptoconfig.h"
  28. #include <kdebug.h>
  29. #include <kprocio.h>
  30. #include <errno.h>
  31. #include <kmessagebox.h>
  32. #include <klocale.h>
  33. #include <assert.h>
  34. #include <ktempfile.h>
  35. #include <tqfile.h>
  36. #include <stdlib.h>
  37. #include <tqtextcodec.h>
  38. // Just for the Q_ASSERT in the dtor. Not thread-safe, but who would
  39. // have 2 threads talking to gpgconf anyway? :)
  40. static bool s_duringClear = false;
  41. static const int GPGCONF_FLAG_GROUP = 1;
  42. static const int GPGCONF_FLAG_OPTIONAL = 2;
  43. static const int GPGCONF_FLAG_LIST = 4;
  44. static const int GPGCONF_FLAG_RUNTIME = 8;
  45. static const int GPGCONF_FLAG_DEFAULT = 16; // fixed default value available
  46. static const int GPGCONF_FLAG_DEFAULT_DESC = 32; // runtime default value available
  47. static const int GPGCONF_FLAG_NOARG_DESC = 64; // option with optional arg; special meaning if no arg set
  48. static const int GPGCONF_FLAG_NO_CHANGE = 128; // readonly
  49. // Change size of mFlags bitfield if adding new values here
  50. QGpgMECryptoConfig::QGpgMECryptoConfig()
  51. : mComponents( 7 ), mParsed( false )
  52. {
  53. mComponents.setAutoDelete( true );
  54. }
  55. QGpgMECryptoConfig::~QGpgMECryptoConfig()
  56. {
  57. }
  58. void QGpgMECryptoConfig::runGpgConf( bool showErrors )
  59. {
  60. // Run gpgconf --list-components to make the list of components
  61. KProcIO proc( TQTextCodec::codecForName( "utf8" ) );
  62. proc << "gpgconf"; // must be in the PATH
  63. proc << "--list-components";
  64. TQObject::connect( &proc, TQT_SIGNAL( readReady(KProcIO*) ),
  65. this, TQT_SLOT( slotCollectStdOut(KProcIO*) ) );
  66. // run the process:
  67. int rc = 0;
  68. if ( !proc.start( KProcess::Block ) )
  69. rc = -1;
  70. else
  71. rc = ( proc.normalExit() ) ? proc.exitStatus() : -2 ;
  72. // handle errors, if any (and if requested)
  73. if ( showErrors && rc != 0 ) {
  74. TQString wmsg = i18n("<qt>Failed to execute gpgconf:<br>%1</qt>");
  75. if ( rc == -1 )
  76. wmsg = wmsg.arg( i18n( "program not found" ) );
  77. else if ( rc == -2 )
  78. wmsg = wmsg.arg( i18n( "program cannot be executed" ) );
  79. else
  80. wmsg = wmsg.arg( strerror(rc) );
  81. kdWarning(5150) << wmsg << endl; // to see it from test_cryptoconfig.cpp
  82. KMessageBox::error(0, wmsg);
  83. }
  84. mParsed = true;
  85. }
  86. void QGpgMECryptoConfig::slotCollectStdOut( KProcIO* proc )
  87. {
  88. TQString line;
  89. int result;
  90. while( ( result = proc->readln(line) ) != -1 ) {
  91. //kdDebug(5150) << "GOT LINE:" << line << endl;
  92. // Format: NAME:DESCRIPTION
  93. TQStringList lst = TQStringList::split( ':', line, true );
  94. if ( lst.count() >= 2 ) {
  95. mComponents.insert( lst[0], new QGpgMECryptoConfigComponent( this, lst[0], lst[1] ) );
  96. } else {
  97. kdWarning(5150) << "Parse error on gpgconf --list-components output: " << line << endl;
  98. }
  99. }
  100. }
  101. TQStringList QGpgMECryptoConfig::componentList() const
  102. {
  103. if ( !mParsed )
  104. const_cast<QGpgMECryptoConfig*>( this )->runGpgConf( true );
  105. TQDictIterator<QGpgMECryptoConfigComponent> it( mComponents );
  106. TQStringList names;
  107. for( ; it.current(); ++it )
  108. names.push_back( it.currentKey() );
  109. return names;
  110. }
  111. Kleo::CryptoConfigComponent* QGpgMECryptoConfig::component( const TQString& name ) const
  112. {
  113. if ( !mParsed )
  114. const_cast<QGpgMECryptoConfig*>( this )->runGpgConf( false );
  115. return mComponents.find( name );
  116. }
  117. void QGpgMECryptoConfig::sync( bool runtime )
  118. {
  119. TQDictIterator<QGpgMECryptoConfigComponent> it( mComponents );
  120. for( ; it.current(); ++it )
  121. it.current()->sync( runtime );
  122. }
  123. void QGpgMECryptoConfig::clear()
  124. {
  125. s_duringClear = true;
  126. mComponents.clear();
  127. s_duringClear = false;
  128. mParsed = false; // next call to componentList/component will need to run gpgconf again
  129. }
  130. ////
  131. QGpgMECryptoConfigComponent::QGpgMECryptoConfigComponent( QGpgMECryptoConfig*, const TQString& name, const TQString& description )
  132. : mGroups( 7 ), mName( name ), mDescription( description )
  133. {
  134. mGroups.setAutoDelete( true );
  135. runGpgConf();
  136. }
  137. QGpgMECryptoConfigComponent::~QGpgMECryptoConfigComponent()
  138. {
  139. }
  140. void QGpgMECryptoConfigComponent::runGpgConf()
  141. {
  142. // Run gpgconf --list-options <component>, and create all groups and entries for that component
  143. KProcIO proc( TQTextCodec::codecForName( "utf8" ) );
  144. proc << "gpgconf"; // must be in the PATH
  145. proc << "--list-options";
  146. proc << mName;
  147. //kdDebug(5150) << "Running gpgconf --list-options " << mName << endl;
  148. TQObject::connect( &proc, TQT_SIGNAL( readReady(KProcIO*) ),
  149. this, TQT_SLOT( slotCollectStdOut(KProcIO*) ) );
  150. mCurrentGroup = 0;
  151. // run the process:
  152. int rc = 0;
  153. if ( !proc.start( KProcess::Block ) )
  154. rc = -1;
  155. else
  156. rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ;
  157. if( rc != 0 ) // can happen when using the wrong version of gpg...
  158. kdWarning(5150) << "Running 'gpgconf --list-options " << mName << "' failed. " << strerror( rc ) << ", but try that command to see the real output" << endl;
  159. else {
  160. if ( mCurrentGroup && !mCurrentGroup->mEntries.isEmpty() ) // only add non-empty groups
  161. mGroups.insert( mCurrentGroupName, mCurrentGroup );
  162. }
  163. }
  164. void QGpgMECryptoConfigComponent::slotCollectStdOut( KProcIO* proc )
  165. {
  166. TQString line;
  167. int result;
  168. while( ( result = proc->readln(line) ) != -1 ) {
  169. //kdDebug(5150) << "GOT LINE:" << line << endl;
  170. // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
  171. const TQStringList lst = TQStringList::split( ':', line, true );
  172. if ( lst.count() >= 10 ) {
  173. const int flags = lst[1].toInt();
  174. const int level = lst[2].toInt();
  175. if ( level > 2 ) // invisible or internal -> skip it;
  176. continue;
  177. if ( flags & GPGCONF_FLAG_GROUP ) {
  178. if ( mCurrentGroup && !mCurrentGroup->mEntries.isEmpty() ) // only add non-empty groups
  179. mGroups.insert( mCurrentGroupName, mCurrentGroup );
  180. //else
  181. // kdDebug(5150) << "Discarding empty group " << mCurrentGroupName << endl;
  182. mCurrentGroup = new QGpgMECryptoConfigGroup( lst[0], lst[3], level );
  183. mCurrentGroupName = lst[0];
  184. } else {
  185. // normal entry
  186. if ( !mCurrentGroup ) { // first toplevel entry -> create toplevel group
  187. mCurrentGroup = new QGpgMECryptoConfigGroup( "<nogroup>", TQString::null, 0 );
  188. mCurrentGroupName = "<nogroup>";
  189. }
  190. mCurrentGroup->mEntries.insert( lst[0], new QGpgMECryptoConfigEntry( lst ) );
  191. }
  192. } else {
  193. // This happens on lines like
  194. // dirmngr[31465]: error opening `/home/dfaure/.gnupg/dirmngr_ldapservers.conf': No such file or directory
  195. // so let's not bother the user with it.
  196. //kdWarning(5150) << "Parse error on gpgconf --list-options output: " << line << endl;
  197. }
  198. }
  199. }
  200. TQStringList QGpgMECryptoConfigComponent::groupList() const
  201. {
  202. TQDictIterator<QGpgMECryptoConfigGroup> it( mGroups );
  203. TQStringList names;
  204. for( ; it.current(); ++it )
  205. names.push_back( it.currentKey() );
  206. return names;
  207. }
  208. Kleo::CryptoConfigGroup* QGpgMECryptoConfigComponent::group(const TQString& name ) const
  209. {
  210. return mGroups.find( name );
  211. }
  212. void QGpgMECryptoConfigComponent::sync( bool runtime )
  213. {
  214. KTempFile tmpFile;
  215. tmpFile.setAutoDelete( true );
  216. TQValueList<QGpgMECryptoConfigEntry *> dirtyEntries;
  217. // Collect all dirty entries
  218. TQDictIterator<QGpgMECryptoConfigGroup> groupit( mGroups );
  219. for( ; groupit.current(); ++groupit ) {
  220. TQDictIterator<QGpgMECryptoConfigEntry> it( groupit.current()->mEntries );
  221. for( ; it.current(); ++it ) {
  222. if ( it.current()->isDirty() ) {
  223. // OK, we can set it.currentKey() to it.current()->outputString()
  224. TQString line = it.currentKey();
  225. if ( it.current()->isSet() ) { // set option
  226. line += ":0:";
  227. line += it.current()->outputString();
  228. } else { // unset option
  229. line += ":16:";
  230. }
  231. line += '\n';
  232. TQCString line8bit = line.utf8(); // encode with utf8, and KProcIO uses utf8 when reading.
  233. tmpFile.file()->writeBlock( line8bit.data(), line8bit.size()-1 /*no 0*/ );
  234. dirtyEntries.append( it.current() );
  235. }
  236. }
  237. }
  238. tmpFile.close();
  239. if ( dirtyEntries.isEmpty() )
  240. return;
  241. // Call gpgconf --change-options <component>
  242. TQString commandLine = "gpgconf";
  243. if ( runtime )
  244. commandLine += " --runtime";
  245. commandLine += " --change-options ";
  246. commandLine += KProcess::quote( mName );
  247. commandLine += " < ";
  248. commandLine += KProcess::quote( tmpFile.name() );
  249. //kdDebug(5150) << commandLine << endl;
  250. //system( TQCString( "cat " ) + tmpFile.name().latin1() ); // DEBUG
  251. KProcess proc;
  252. proc.setUseShell( true );
  253. proc << commandLine;
  254. // run the process:
  255. int rc = 0;
  256. if ( !proc.start( KProcess::Block ) )
  257. rc = -1;
  258. else
  259. rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ;
  260. if ( rc == -1 )
  261. {
  262. TQString wmsg = i18n( "Could not start gpgconf\nCheck that gpgconf is in the PATH and that it can be started" );
  263. kdWarning(5150) << wmsg << endl;
  264. KMessageBox::error(0, wmsg);
  265. }
  266. else if( rc != 0 ) // Happens due to bugs in gpgconf (e.g. issues 104/115)
  267. {
  268. TQString wmsg = i18n( "Error from gpgconf while saving configuration: %1" ).arg( TQString::fromLocal8Bit( strerror( rc ) ) );
  269. kdWarning(5150) << k_funcinfo << ":" << strerror( rc ) << endl;
  270. KMessageBox::error(0, wmsg);
  271. }
  272. else
  273. {
  274. TQValueList<QGpgMECryptoConfigEntry *>::Iterator it = dirtyEntries.begin();
  275. for( ; it != dirtyEntries.end(); ++it ) {
  276. (*it)->setDirty( false );
  277. }
  278. }
  279. }
  280. ////
  281. QGpgMECryptoConfigGroup::QGpgMECryptoConfigGroup( const TQString & name, const TQString& description, int level )
  282. : mEntries( 29 ),
  283. mName( name ),
  284. mDescription( description ),
  285. mLevel( static_cast<Kleo::CryptoConfigEntry::Level>( level ) )
  286. {
  287. mEntries.setAutoDelete( true );
  288. }
  289. TQStringList QGpgMECryptoConfigGroup::entryList() const
  290. {
  291. TQDictIterator<QGpgMECryptoConfigEntry> it( mEntries );
  292. TQStringList names;
  293. for( ; it.current(); ++it )
  294. names.push_back( it.currentKey() );
  295. return names;
  296. }
  297. Kleo::CryptoConfigEntry* QGpgMECryptoConfigGroup::entry( const TQString& name ) const
  298. {
  299. return mEntries.find( name );
  300. }
  301. ////
  302. static TQString gpgconf_unescape( const TQString& str )
  303. {
  304. // Looks like it's the same rules as KURL.
  305. return KURL::decode_string( str, 106 );
  306. }
  307. static TQString gpgconf_escape( const TQString& str )
  308. {
  309. // Escape special chars (including ':' and '%')
  310. TQString enc = KURL::encode_string( str, 106 ); // and convert to utf8 first (to get %12%34 for one special char)
  311. // Also encode commas, for lists.
  312. enc.replace( ',', "%2c" );
  313. return enc;
  314. }
  315. static TQString urlpart_encode( const TQString& str )
  316. {
  317. TQString enc( str );
  318. enc.replace( '%', "%25" ); // first!
  319. enc.replace( ':', "%3a" );
  320. //kdDebug() << " urlpart_encode: " << str << " -> " << enc << endl;
  321. return enc;
  322. }
  323. static TQString urlpart_decode( const TQString& str )
  324. {
  325. return KURL::decode_string( str );
  326. }
  327. // gpgconf arg type number -> CryptoConfigEntry arg type enum mapping
  328. static Kleo::CryptoConfigEntry::ArgType knownArgType( int argType, bool& ok ) {
  329. ok = true;
  330. switch( argType ) {
  331. case 0: // none
  332. return Kleo::CryptoConfigEntry::ArgType_None;
  333. case 1: // string
  334. return Kleo::CryptoConfigEntry::ArgType_String;
  335. case 2: // int32
  336. return Kleo::CryptoConfigEntry::ArgType_Int;
  337. case 3: // uint32
  338. return Kleo::CryptoConfigEntry::ArgType_UInt;
  339. case 32: // pathname
  340. return Kleo::CryptoConfigEntry::ArgType_Path;
  341. case 33: // ldap server
  342. return Kleo::CryptoConfigEntry::ArgType_LDAPURL;
  343. default:
  344. ok = false;
  345. return Kleo::CryptoConfigEntry::ArgType_None;
  346. }
  347. }
  348. QGpgMECryptoConfigEntry::QGpgMECryptoConfigEntry( const TQStringList& parsedLine )
  349. {
  350. // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
  351. assert( parsedLine.count() >= 10 ); // called checked for it already
  352. TQStringList::const_iterator it = parsedLine.begin();
  353. mName = *it++;
  354. mFlags = (*it++).toInt();
  355. mLevel = (*it++).toInt();
  356. mDescription = *it++;
  357. bool ok;
  358. // we keep the real (int) arg type, since it influences the parsing (e.g. for ldap urls)
  359. mRealArgType = (*it++).toInt();
  360. mArgType = knownArgType( mRealArgType, ok );
  361. if ( !ok && !(*it).isEmpty() ) {
  362. // use ALT-TYPE
  363. mRealArgType = (*it).toInt();
  364. mArgType = knownArgType( mRealArgType, ok );
  365. }
  366. if ( !ok )
  367. kdWarning(5150) << "Unsupported datatype: " << parsedLine[4] << " : " << *it << " for " << parsedLine[0] << endl;
  368. ++it; // done with alt-type
  369. ++it; // skip argname (not useful in GUIs)
  370. mSet = false;
  371. TQString value;
  372. if ( mFlags & GPGCONF_FLAG_DEFAULT ) {
  373. value = *it; // get default value
  374. mDefaultValue = stringToValue( value, true );
  375. }
  376. ++it; // done with DEFAULT
  377. ++it; // ### skip ARGDEF for now. It's only for options with an "optional arg"
  378. //kdDebug(5150) << "Entry " << parsedLine[0] << " val=" << *it << endl;
  379. if ( !(*it).isEmpty() ) { // a real value was set
  380. mSet = true;
  381. value = *it;
  382. mValue = stringToValue( value, true );
  383. }
  384. else {
  385. mValue = mDefaultValue;
  386. }
  387. mDirty = false;
  388. }
  389. TQVariant QGpgMECryptoConfigEntry::stringToValue( const TQString& str, bool unescape ) const
  390. {
  391. bool isString = isStringType();
  392. if ( isList() ) {
  393. if ( argType() == ArgType_None ) {
  394. bool ok = true;
  395. const TQVariant v = str.isEmpty() ? 0U : str.toUInt( &ok ) ;
  396. if ( !ok )
  397. kdWarning(5150) << "list-of-none should have an unsigned int as value:" << str << endl;
  398. return v;
  399. }
  400. TQValueList<TQVariant> lst;
  401. TQStringList items = TQStringList::split( ',', str );
  402. for( TQStringList::const_iterator valit = items.begin(); valit != items.end(); ++valit ) {
  403. TQString val = *valit;
  404. if ( isString ) {
  405. if ( val.isEmpty() ) {
  406. lst << TQString::null;
  407. continue;
  408. }
  409. else if ( unescape ) {
  410. if( val[0] != '"' ) // see README.gpgconf
  411. kdWarning(5150) << "String value should start with '\"' : " << val << endl;
  412. val = val.mid( 1 );
  413. }
  414. }
  415. lst << TQVariant( unescape ? gpgconf_unescape( val ) : val );
  416. }
  417. return lst;
  418. } else { // not a list
  419. TQString val( str );
  420. if ( isString ) {
  421. if ( val.isEmpty() )
  422. return TQVariant( TQString::null ); // not set [ok with lists too?]
  423. else if ( unescape ) {
  424. Q_ASSERT( val[0] == '"' ); // see README.gpgconf
  425. val = val.mid( 1 );
  426. }
  427. }
  428. return TQVariant( unescape ? gpgconf_unescape( val ) : val );
  429. }
  430. }
  431. QGpgMECryptoConfigEntry::~QGpgMECryptoConfigEntry()
  432. {
  433. #ifndef NDEBUG
  434. if ( !s_duringClear && mDirty )
  435. kdWarning(5150) << "Deleting a QGpgMECryptoConfigEntry that was modified (" << mDescription << ")\n"
  436. << "You forgot to call sync() (to commit) or clear() (to discard)" << endl;
  437. #endif
  438. }
  439. bool QGpgMECryptoConfigEntry::isOptional() const
  440. {
  441. return mFlags & GPGCONF_FLAG_OPTIONAL;
  442. }
  443. bool QGpgMECryptoConfigEntry::isReadOnly() const
  444. {
  445. return mFlags & GPGCONF_FLAG_NO_CHANGE;
  446. }
  447. bool QGpgMECryptoConfigEntry::isList() const
  448. {
  449. return mFlags & GPGCONF_FLAG_LIST;
  450. }
  451. bool QGpgMECryptoConfigEntry::isRuntime() const
  452. {
  453. return mFlags & GPGCONF_FLAG_RUNTIME;
  454. }
  455. bool QGpgMECryptoConfigEntry::isSet() const
  456. {
  457. return mSet;
  458. }
  459. bool QGpgMECryptoConfigEntry::boolValue() const
  460. {
  461. Q_ASSERT( mArgType == ArgType_None );
  462. Q_ASSERT( !isList() );
  463. return mValue.toBool();
  464. }
  465. TQString QGpgMECryptoConfigEntry::stringValue() const
  466. {
  467. return toString( false );
  468. }
  469. int QGpgMECryptoConfigEntry::intValue() const
  470. {
  471. Q_ASSERT( mArgType == ArgType_Int );
  472. Q_ASSERT( !isList() );
  473. return mValue.toInt();
  474. }
  475. unsigned int QGpgMECryptoConfigEntry::uintValue() const
  476. {
  477. Q_ASSERT( mArgType == ArgType_UInt );
  478. Q_ASSERT( !isList() );
  479. return mValue.toUInt();
  480. }
  481. static KURL parseURL( int mRealArgType, const TQString& str )
  482. {
  483. if ( mRealArgType == 33 ) { // LDAP server
  484. // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
  485. TQStringList items = TQStringList::split( ':', str, true );
  486. if ( items.count() == 5 ) {
  487. TQStringList::const_iterator it = items.begin();
  488. KURL url;
  489. url.setProtocol( "ldap" );
  490. url.setHost( urlpart_decode( *it++ ) );
  491. url.setPort( (*it++).toInt() );
  492. url.setPath( "/" ); // workaround KURL parsing bug
  493. url.setUser( urlpart_decode( *it++ ) );
  494. url.setPass( urlpart_decode( *it++ ) );
  495. url.setQuery( urlpart_decode( *it ) );
  496. return url;
  497. } else
  498. kdWarning(5150) << "parseURL: malformed LDAP server: " << str << endl;
  499. }
  500. // other URLs : assume wellformed URL syntax.
  501. return KURL( str );
  502. }
  503. // The opposite of parseURL
  504. static TQString splitURL( int mRealArgType, const KURL& url )
  505. {
  506. if ( mRealArgType == 33 ) { // LDAP server
  507. // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
  508. Q_ASSERT( url.protocol() == "ldap" );
  509. return urlpart_encode( url.host() ) + ":" +
  510. TQString::number( url.port() ) + ":" +
  511. urlpart_encode( url.user() ) + ":" +
  512. urlpart_encode( url.pass() ) + ":" +
  513. // KURL automatically encoded the query (e.g. for spaces inside it),
  514. // so decode it before writing it out to gpgconf (issue119)
  515. urlpart_encode( KURL::decode_string( url.query().mid(1) ) );
  516. }
  517. return url.path();
  518. }
  519. KURL QGpgMECryptoConfigEntry::urlValue() const
  520. {
  521. Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
  522. Q_ASSERT( !isList() );
  523. TQString str = mValue.toString();
  524. if ( mArgType == ArgType_Path )
  525. {
  526. KURL url;
  527. url.setPath( str );
  528. return url;
  529. }
  530. return parseURL( mRealArgType, str );
  531. }
  532. unsigned int QGpgMECryptoConfigEntry::numberOfTimesSet() const
  533. {
  534. Q_ASSERT( mArgType == ArgType_None );
  535. Q_ASSERT( isList() );
  536. return mValue.toUInt();
  537. }
  538. TQStringList QGpgMECryptoConfigEntry::stringValueList() const
  539. {
  540. Q_ASSERT( isStringType() );
  541. Q_ASSERT( isList() );
  542. return mValue.toStringList();
  543. }
  544. TQValueList<int> QGpgMECryptoConfigEntry::intValueList() const
  545. {
  546. Q_ASSERT( mArgType == ArgType_Int );
  547. Q_ASSERT( isList() );
  548. TQValueList<int> ret;
  549. TQValueList<TQVariant> lst = mValue.toList();
  550. for( TQValueList<TQVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
  551. ret.append( (*it).toInt() );
  552. }
  553. return ret;
  554. }
  555. TQValueList<unsigned int> QGpgMECryptoConfigEntry::uintValueList() const
  556. {
  557. Q_ASSERT( mArgType == ArgType_UInt );
  558. Q_ASSERT( isList() );
  559. TQValueList<unsigned int> ret;
  560. TQValueList<TQVariant> lst = mValue.toList();
  561. for( TQValueList<TQVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
  562. ret.append( (*it).toUInt() );
  563. }
  564. return ret;
  565. }
  566. KURL::List QGpgMECryptoConfigEntry::urlValueList() const
  567. {
  568. Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
  569. Q_ASSERT( isList() );
  570. TQStringList lst = mValue.toStringList();
  571. KURL::List ret;
  572. for( TQStringList::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
  573. if ( mArgType == ArgType_Path ) {
  574. KURL url;
  575. url.setPath( *it );
  576. ret << url;
  577. } else {
  578. ret << parseURL( mRealArgType, *it );
  579. }
  580. }
  581. return ret;
  582. }
  583. void QGpgMECryptoConfigEntry::resetToDefault()
  584. {
  585. mSet = false;
  586. mDirty = true;
  587. if ( mFlags & GPGCONF_FLAG_DEFAULT )
  588. mValue = mDefaultValue;
  589. else if ( mArgType == ArgType_None )
  590. if ( isList() )
  591. mValue = 0U;
  592. else
  593. mValue = false;
  594. }
  595. void QGpgMECryptoConfigEntry::setBoolValue( bool b )
  596. {
  597. Q_ASSERT( mArgType == ArgType_None );
  598. Q_ASSERT( !isList() );
  599. // A "no arg" option is either set or not set.
  600. // Being set means mSet==true + mValue==true, being unset means resetToDefault(), i.e. both false
  601. mValue = b;
  602. mSet = b;
  603. mDirty = true;
  604. }
  605. void QGpgMECryptoConfigEntry::setStringValue( const TQString& str )
  606. {
  607. mValue = stringToValue( str, false );
  608. // When setting a string to empty (and there's no default), we need to act like resetToDefault
  609. // Otherwise we try e.g. "ocsp-responder:0:" and gpgconf answers:
  610. // "gpgconf: argument required for option ocsp-responder"
  611. if ( str.isEmpty() && !isOptional() )
  612. mSet = false;
  613. else
  614. mSet = true;
  615. mDirty = true;
  616. }
  617. void QGpgMECryptoConfigEntry::setIntValue( int i )
  618. {
  619. Q_ASSERT( mArgType == ArgType_Int );
  620. Q_ASSERT( !isList() );
  621. mValue = i;
  622. mSet = true;
  623. mDirty = true;
  624. }
  625. void QGpgMECryptoConfigEntry::setUIntValue( unsigned int i )
  626. {
  627. mValue = i;
  628. mSet = true;
  629. mDirty = true;
  630. }
  631. void QGpgMECryptoConfigEntry::setURLValue( const KURL& url )
  632. {
  633. TQString str = splitURL( mRealArgType, url );
  634. if ( str.isEmpty() && !isOptional() )
  635. mSet = false;
  636. else
  637. mSet = true;
  638. mValue = str;
  639. mDirty = true;
  640. }
  641. void QGpgMECryptoConfigEntry::setNumberOfTimesSet( unsigned int i )
  642. {
  643. Q_ASSERT( mArgType == ArgType_None );
  644. Q_ASSERT( isList() );
  645. mValue = i;
  646. mSet = i > 0;
  647. mDirty = true;
  648. }
  649. void QGpgMECryptoConfigEntry::setStringValueList( const TQStringList& lst )
  650. {
  651. mValue = lst;
  652. if ( lst.isEmpty() && !isOptional() )
  653. mSet = false;
  654. else
  655. mSet = true;
  656. mDirty = true;
  657. }
  658. void QGpgMECryptoConfigEntry::setIntValueList( const TQValueList<int>& lst )
  659. {
  660. TQValueList<TQVariant> ret;
  661. for( TQValueList<int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
  662. ret << TQVariant( *it );
  663. }
  664. mValue = ret;
  665. if ( ret.isEmpty() && !isOptional() )
  666. mSet = false;
  667. else
  668. mSet = true;
  669. mDirty = true;
  670. }
  671. void QGpgMECryptoConfigEntry::setUIntValueList( const TQValueList<unsigned int>& lst )
  672. {
  673. TQValueList<TQVariant> ret;
  674. for( TQValueList<unsigned int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
  675. ret << TQVariant( *it );
  676. }
  677. if ( ret.isEmpty() && !isOptional() )
  678. mSet = false;
  679. else
  680. mSet = true;
  681. mValue = ret;
  682. mDirty = true;
  683. }
  684. void QGpgMECryptoConfigEntry::setURLValueList( const KURL::List& urls )
  685. {
  686. TQStringList lst;
  687. for( KURL::List::const_iterator it = urls.begin(); it != urls.end(); ++it ) {
  688. lst << splitURL( mRealArgType, *it );
  689. }
  690. mValue = lst;
  691. if ( lst.isEmpty() && !isOptional() )
  692. mSet = false;
  693. else
  694. mSet = true;
  695. mDirty = true;
  696. }
  697. TQString QGpgMECryptoConfigEntry::toString( bool escape ) const
  698. {
  699. // Basically the opposite of stringToValue
  700. if ( isStringType() ) {
  701. if ( mValue.isNull() )
  702. return TQString::null;
  703. else if ( isList() ) { // string list
  704. TQStringList lst = mValue.toStringList();
  705. if ( escape ) {
  706. for( TQStringList::iterator it = lst.begin(); it != lst.end(); ++it ) {
  707. if ( !(*it).isNull() )
  708. *it = gpgconf_escape( *it ).prepend( "\"" );
  709. }
  710. }
  711. TQString res = lst.join( "," );
  712. kdDebug(5150) << "toString: " << res << endl;
  713. return res;
  714. } else { // normal string
  715. TQString res = mValue.toString();
  716. if ( escape )
  717. res = gpgconf_escape( res ).prepend( "\"" );
  718. return res;
  719. }
  720. }
  721. if ( !isList() ) // non-list non-string
  722. {
  723. if ( mArgType == ArgType_None ) {
  724. return mValue.toBool() ? TQString::fromLatin1( "1" ) : TQString::null;
  725. } else { // some int
  726. Q_ASSERT( mArgType == ArgType_Int || mArgType == ArgType_UInt );
  727. return mValue.toString(); // int to string conversion
  728. }
  729. }
  730. // Lists (of other types than strings)
  731. if ( mArgType == ArgType_None )
  732. return TQString::number( numberOfTimesSet() );
  733. TQStringList ret;
  734. TQValueList<TQVariant> lst = mValue.toList();
  735. for( TQValueList<TQVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
  736. ret << (*it).toString(); // TQVariant does the conversion
  737. }
  738. return ret.join( "," );
  739. }
  740. TQString QGpgMECryptoConfigEntry::outputString() const
  741. {
  742. Q_ASSERT( mSet );
  743. return toString( true );
  744. }
  745. bool QGpgMECryptoConfigEntry::isStringType() const
  746. {
  747. return ( mArgType == Kleo::CryptoConfigEntry::ArgType_String
  748. || mArgType == Kleo::CryptoConfigEntry::ArgType_Path
  749. || mArgType == Kleo::CryptoConfigEntry::ArgType_URL
  750. || mArgType == Kleo::CryptoConfigEntry::ArgType_LDAPURL );
  751. }
  752. void QGpgMECryptoConfigEntry::setDirty( bool b )
  753. {
  754. mDirty = b;
  755. }
  756. #include "qgpgmecryptoconfig.moc"