• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kleopatra

  • sources
  • kde-4.12
  • kdepim
  • kleopatra
  • kgpgconf
configreader.cpp
Go to the documentation of this file.
1 /* -*- mode: c++; c-basic-offset:4 -*-
2  configreader.cpp
3 
4  This file is part of Kleopatra, the KDE keymanager
5  Copyright (c) 2007 Klarälvdalens Datakonsult AB
6 
7  Kleopatra is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  Kleopatra is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21  In addition, as a special exception, the copyright holders give
22  permission to link the code of this program with any edition of
23  the Qt library by Trolltech AS, Norway (or with modified versions
24  of Qt that use the same license as Qt), and distribute linked
25  combinations including the two. You must obey the GNU General
26  Public License in all respects for all of the code used other than
27  Qt. If you modify this file, you may extend this exception to
28  your version of the file, but you are not obligated to do so. If
29  you do not wish to do so, delete this exception statement from
30  your version.
31 */
32 
33 #include "configreader.h"
34 #include "configuration.h"
35 #include "exception.h"
36 
37 #include <gpgme++/global.h>
38 #include <gpgme++/engineinfo.h>
39 
40 #include <KDebug>
41 #include <KLocale>
42 #include <KStandardDirs>
43 
44 #include <QBuffer>
45 #include <QByteArray>
46 #include <QMap>
47 #include <QProcess>
48 #include <QStringList>
49 #include <QFile>
50 
51 #include <cassert>
52 #include <memory>
53 
54 namespace {
55 
56 struct GpgConfResult {
57  QByteArray stdOut;
58  QByteArray stdErr;
59 };
60 
61 static const int GPGCONF_FLAG_GROUP = 1;
62 static const int GPGCONF_FLAG_OPTIONAL = 2;
63 static const int GPGCONF_FLAG_LIST = 4;
64 static const int GPGCONF_FLAG_RUNTIME = 8;
65 static const int GPGCONF_FLAG_DEFAULT = 16; // fixed default value available
66 static const int GPGCONF_FLAG_DEFAULT_DESC = 32; // runtime default value available
67 static const int GPGCONF_FLAG_NOARG_DESC = 64; // option with optional arg; special meaning if no arg set
68 static const int GPGCONF_FLAG_NO_CHANGE = 128; // readonly
69 // Change size of mFlags bitfield if adding new values here
70 
71 
72 // gpgconf arg type number -> CryptoConfigEntry arg type enum mapping
73 static ConfigEntry::ArgType knownArgType( int argType, bool& ok ) {
74  ok = true;
75  switch( argType )
76  {
77  case 0: // none
78  return ConfigEntry::None;
79  case 1: // string
80  return ConfigEntry::String;
81  case 2: // int32
82  return ConfigEntry::Int;
83  case 3: // uint32
84  return ConfigEntry::UInt;
85  case 32: // pathname
86  return ConfigEntry::Path;
87  case 33: // ldap server
88  return ConfigEntry::LdapUrl;
89  default:
90  ok = false;
91  return ConfigEntry::None;
92  }
93 }
94 
95 }
96 
97 class ConfigReader::Private
98 {
99 public:
100  GpgConfResult runGpgConf( const QStringList& args ) const;
101  GpgConfResult runGpgConf( const QString& arg ) const;
102 
103  QMap<QString,QString> readComponentInfo() const;
104  void readEntriesForComponent( ConfigComponent* component ) const;
105  ConfigEntry* createEntryFromParsedLine( const QStringList& lst ) const;
106  void readConfConf( Config* cfg ) const;
107 };
108 
109 ConfigReader::ConfigReader() : d( new Private )
110 {
111 }
112 
113 ConfigReader::~ConfigReader()
114 {
115  delete d;
116 }
117 
118 
119 Config* ConfigReader::readConfig() const
120 {
121  std::auto_ptr<Config> cfg( new Config );
122  const QMap<QString,QString> componentInfo = d->readComponentInfo();
123 
124  Q_FOREACH ( const QString& i, componentInfo )
125  {
126  std::auto_ptr<ConfigComponent> component( new ConfigComponent( i ) );
127  component->setDescription( componentInfo[i] );
128  d->readEntriesForComponent( component.get() );
129  cfg->addComponent( component.release() );
130  }
131  d->readConfConf( cfg.get() );
132  return cfg.release();
133 }
134 
135 ConfigEntry* ConfigReader::Private::createEntryFromParsedLine( const QStringList& parsedLine ) const
136 {
137  // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
138  assert( parsedLine.count() >= 10 ); // called checked for it already
139  QStringList::const_iterator it = parsedLine.begin();
140  const QString name = *it++;
141  std::auto_ptr<ConfigEntry> entry( new ConfigEntry( name ) );
142  const int flags = (*it++).toInt();
143  const int level = (*it++).toInt();
144  Q_UNUSED( level );
145  entry->setDescription( *it++ );
146  bool ok;
147  // we keep the real (int) arg type, since it influences the parsing (e.g. for ldap urls)
148  uint realArgType = (*it++).toInt();
149  ConfigEntry::ArgType argType = ::knownArgType( realArgType, ok );
150  if ( !ok && !(*it).isEmpty() ) {
151  // use ALT-TYPE
152  realArgType = (*it).toInt();
153  argType = ::knownArgType( realArgType, ok );
154  }
155  entry->setArgType( argType, flags & GPGCONF_FLAG_LIST ? ConfigEntry::List : ConfigEntry::NoList );
156  if ( !ok )
157  kWarning() << "Unsupported datatype:" << parsedLine[4] <<" :" << *it <<" for" << parsedLine[0];
158  entry->unsetDirty();
159  return entry.release();
160 }
161 
162 void ConfigReader::Private::readEntriesForComponent( ConfigComponent* component ) const
163 {
164  assert( component );
165  QStringList args;
166  args << QLatin1String("--list-options") << component->name();
167  GpgConfResult res = runGpgConf( args );
168 
169  std::auto_ptr<ConfigGroup> currentGroup;
170 
171  QBuffer buf( &res.stdOut );
172  buf.open( QIODevice::ReadOnly );
173  while( buf.canReadLine() ) {
174  QString line = QString::fromUtf8( buf.readLine() );
175  if ( line.endsWith( QLatin1Char('\n') ) )
176  line.chop( 1 );
177  if ( line.endsWith( QLatin1Char('\r') ) )
178  line.chop( 1 );
179  //kDebug(5150) <<"GOT LINE:" << line;
180  // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
181  const QStringList lst = line.split( QLatin1Char(':') );
182  if ( lst.count() >= 10 ) {
183  const int flags = lst[1].toInt();
184  const int level = lst[2].toInt();
185  if ( level > 2 ) // invisible or internal -> skip it;
186  continue;
187  if ( flags & GPGCONF_FLAG_GROUP ) {
188  if ( currentGroup.get() && !currentGroup->isEmpty() ) // only add non-empty groups
189  component->addGroup( currentGroup.release() );
190  else {
191  currentGroup.reset();
192  }
193  //else
194  // kDebug(5150) <<"Discarding empty group" << mCurrentGroupName;
195  currentGroup.reset( new ConfigGroup( lst[0] ) );
196  currentGroup->setDescription( lst[3] );
197  //currentGroup->setLevel( level );
198  } else {
199  // normal entry
200  if ( !currentGroup.get() ) { // first toplevel entry -> create toplevel group
201  currentGroup.reset( new ConfigGroup( QLatin1String("<nogroup>") ) );
202  }
203  currentGroup->addEntry( createEntryFromParsedLine( lst ) );
204  }
205  } else {
206  // This happens on lines like
207  // dirmngr[31465]: error opening `/home/dfaure/.gnupg/dirmngr_ldapservers.conf': No such file or directory
208  // so let's not bother the user with it.
209  //kWarning() <<"Parse error on gpgconf --list-options output:" << line;
210  }
211  }
212  if ( currentGroup.get() && !currentGroup->isEmpty() )
213  component->addGroup( currentGroup.release() );
214 }
215 
216 void ConfigReader::Private::readConfConf( Config* cfg ) const
217 {
218  GpgConfResult res = runGpgConf( QLatin1String("--list-config") );
219  QBuffer buf( &(res.stdOut) );
220  buf.open( QIODevice::ReadOnly | QIODevice::Text );
221  while ( buf.canReadLine() )
222  {
223  QString line = QLatin1String(buf.readLine());
224  if ( line.endsWith( QLatin1Char('\n') ) )
225  line.chop( 1 );
226  if ( line.endsWith( QLatin1Char('\r') ) )
227  line.chop( 1 );
228  const QStringList lst = line.split( QLatin1Char(':') );
229  if ( lst.isEmpty() || lst[0] != QLatin1String("r") ) // only parse 'r'-type value entries
230  continue;
231 
232  if ( lst.count() < 8 )
233  {
234  throw MalformedGpgConfOutputException( i18n( "Parse error on gpgconf --list-config output: %1", line ) );
235  }
236  ConfigComponent* const component = cfg->component( lst[3] );
237  if ( !component )
238  {
239  throw MalformedGpgConfOutputException( i18n( "gpgconf --list-config: Unknown component: %1", lst[3] ) );
240  }
241  ConfigEntry* const entry = component->entry( lst[4] );
242  if ( !entry )
243  {
244  throw MalformedGpgConfOutputException( i18n( "gpgconf --list-config: Unknown entry: %1:%2", lst[3], lst[4] ) );
245  }
246  const QString flag = lst[5];
247  const QString value = lst[6];
248  if ( !value.isEmpty() && !value.startsWith( QLatin1Char('\"') ) )
249  {
250  throw MalformedGpgConfOutputException( i18n( "gpgconf --list-config: Invalid entry: value must start with '\"': %1", lst[6] ) );
251  }
252  if ( !lst[6].isEmpty() )
253  entry->setValueFromRawString( lst[6].mid( 1 ) );
254 
255  if ( flag == QLatin1String( "no-change" ) )
256  entry->setMutability( ConfigEntry::NoChange );
257  else if ( flag == QLatin1String( "change" ) )
258  entry->setMutability( ConfigEntry::Change );
259  else if ( flag == QLatin1String( "default" ) )
260  entry->setUseBuiltInDefault( true );
261  }
262  buf.close();
263 }
264 
265 QMap<QString, QString> ConfigReader::Private::readComponentInfo() const
266 {
267  GpgConfResult res = runGpgConf( QLatin1String("--list-components") );
268  QBuffer buf( &(res.stdOut) );
269  buf.open( QIODevice::ReadOnly );
270  QMap<QString, QString> components;
271  while( buf.canReadLine() ) {
272  QString line = QString::fromUtf8( buf.readLine() );
273  if ( line.endsWith( QLatin1Char('\n') ) )
274  line.chop( 1 );
275  if ( line.endsWith( QLatin1Char('\r') ) )
276  line.chop( 1 );
277  //kDebug(5150) <<"GOT LINE:" << line;
278  // Format: NAME:DESCRIPTION
279  const QStringList lst = line.split( QLatin1Char(':') );
280  if ( lst.count() >= 2 ) {
281  components[lst[0]] = lst[1];
282  } else {
283  throw MalformedGpgConfOutputException( i18n( "Parse error on gpgconf --list-components. output: %1", line ) );
284  }
285  }
286  return components;
287 }
288 
289 GpgConfResult ConfigReader::Private::runGpgConf( const QString& arg ) const
290 {
291  return runGpgConf( QStringList( arg ) );
292 }
293 
294 static QString gpgConfPath() {
295  const GpgME::EngineInfo ei = GpgME::engineInfo( GpgME::GpgConfEngine );
296  return ei.fileName() ? QFile::decodeName( ei.fileName() ) : KStandardDirs::findExe( QLatin1String("gpgconf") ) ;
297 }
298 
299 GpgConfResult ConfigReader::Private::runGpgConf( const QStringList& args ) const
300 {
301  QProcess process;
302  process.start( gpgConfPath(), args );
303 
304  process.waitForStarted();
305  process.waitForFinished();
306 
307  if ( process.exitStatus() != QProcess::NormalExit ) {
308  switch ( process.error() )
309  {
310  case QProcess::FailedToStart:
311  throw GpgConfRunException( -2, i18n( "gpgconf not found or cannot be started" ) );
312  case QProcess::Crashed:
313  throw GpgConfRunException( -1, i18n( "gpgconf terminated unexpectedly" ) );
314  case QProcess::Timedout:
315  throw GpgConfRunException( -3, i18n( "timeout while executing gpgconf" ) );
316  case QProcess::WriteError:
317  throw GpgConfRunException( -4, i18n( "error while writing to gpgconf" ) );
318  case QProcess::ReadError:
319  throw GpgConfRunException( -5, i18n( "error while reading from gpgconf" ) );
320  case QProcess::UnknownError:
321  default:
322  throw GpgConfRunException( -6, i18n( "Unknown error while executing gpgconf" ) );
323  }
324  }
325 
326  GpgConfResult res;
327  res.stdOut = process.readAllStandardOutput();
328  res.stdErr = process.readAllStandardError();
329  return res;
330 }
331 
flags
static const char * flags[]
Definition: readerstatus.cpp:115
Config::component
ConfigComponent * component(const QString &name) const
Definition: configuration.cpp:133
ConfigComponent::name
QString name() const
Definition: configuration.cpp:155
ConfigEntry::ArgType
ArgType
Definition: configuration.h:133
ConfigComponent::entry
ConfigEntry * entry(const QString &name) const
Definition: configuration.cpp:194
ConfigEntry::setUseBuiltInDefault
void setUseBuiltInDefault(bool useDefault)
Definition: configuration.cpp:319
ConfigEntry::setValueFromRawString
void setValueFromRawString(const QString &str)
Definition: configuration.cpp:468
ConfigReader::ConfigReader
ConfigReader()
Definition: configreader.cpp:109
Config
Definition: configuration.h:46
ConfigEntry::String
Definition: configuration.h:135
exception.h
ConfigEntry::LdapUrl
Definition: configuration.h:140
d
#define d
Definition: adduseridcommand.cpp:90
gpgConfPath
static QString gpgConfPath()
Definition: configreader.cpp:294
components
static const char *const components[]
Definition: selftestcommand.cpp:69
ConfigEntry::None
Definition: configuration.h:134
ConfigEntry::Path
Definition: configuration.h:138
ConfigComponent
Definition: configuration.h:64
process
static QString process(const Dir &dir, bool *fatal)
Definition: createchecksumscontroller.cpp:532
configuration.h
MalformedGpgConfOutputException
Definition: exception.h:61
ConfigGroup
Definition: configuration.h:94
ConfigReader::readConfig
Config * readConfig() const
Definition: configreader.cpp:119
ConfigEntry::UInt
Definition: configuration.h:137
ConfigReader::~ConfigReader
~ConfigReader()
Definition: configreader.cpp:113
ConfigEntry::setMutability
void setMutability(Mutability mutability)
Definition: configuration.cpp:301
ConfigEntry::Change
Definition: configuration.h:130
ConfigEntry::NoList
Definition: configuration.h:145
ConfigEntry::Int
Definition: configuration.h:136
ConfigComponent::addGroup
void addGroup(ConfigGroup *group)
Definition: configuration.cpp:185
ConfigEntry::List
Definition: configuration.h:146
name
const char * name
Definition: uiserver/selectcertificatecommand.cpp:114
ConfigEntry::NoChange
Definition: configuration.h:129
configreader.h
ConfigEntry
Definition: configuration.h:123
GpgConfRunException
Definition: exception.h:49
QMap
Definition: signingcertificateselectiondialog.h:41
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:56:40 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kleopatra

Skip menu "kleopatra"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal