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

kgpg

  • sources
  • kde-4.14
  • kdeutils
  • kgpg
gpgproc.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 Rolf Eike Beer <kde@opensource.sf-tec.de>
3  */
4 
5 /***************************************************************************
6  * *
7  * This program 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  ***************************************************************************/
13 
14 #include "gpgproc.h"
15 
16 #include "kgpgsettings.h"
17 
18 #include <KDebug>
19 #include <KProcess>
20 #include <KStandardDirs>
21 #include <QDir>
22 #include <QFileInfo>
23 #include <QTextCodec>
24 
25 class GnupgBinary {
26 public:
27  GnupgBinary();
28 
29  const QString &binary() const;
30  void setBinary(const QString &executable);
31  const QStringList &standardArguments() const;
32  unsigned int version() const;
33  bool supportsDebugLevel() const;
34 
35 private:
36  QString m_binary;
37  QStringList m_standardArguments;
38  unsigned int m_version;
39  bool m_useDebugLevel;
40 };
41 
42 GnupgBinary::GnupgBinary()
43  : m_version(0),
44  m_useDebugLevel(false)
45 {
46 }
47 
48 const QString &GnupgBinary::binary() const
49 {
50  return m_binary;
51 }
52 
61 static bool checkGnupgArguments(const QString &executable, const QStringList &arguments)
62 {
63  KProcess gpg;
64 
65  // We ignore the output anyway, just make sure it doesn't clutter the output of
66  // the parent process. Simplify the handling by putting all trash in one can.
67  gpg.setOutputChannelMode(KProcess::MergedChannels);
68 
69  QStringList allArguments = arguments;
70  allArguments << QLatin1String("--version");
71  gpg.setProgram(executable, allArguments);
72 
73  return (gpg.execute() == 0);
74 }
75 
76 static QString getGpgProcessHome(const QString &binary)
77 {
78  GPGProc process(0, binary);
79  process << QLatin1String( "--version" );
80  process.start();
81  process.waitForFinished(-1);
82 
83  if (process.exitCode() == 255) {
84  return QString();
85  }
86 
87  QString line;
88  while (process.readln(line) != -1) {
89  if (line.startsWith(QLatin1String("Home: "))) {
90  line.remove(0, 6);
91  return line.trimmed();
92  }
93  }
94 
95  return QString();
96 }
97 
98 
99 void GnupgBinary::setBinary(const QString &executable)
100 {
101  kDebug(2100) << "checking version of GnuPG executable" << executable;
102  // must be set first as gpgVersionString() uses GPGProc to parse the output
103  m_binary = executable;
104  const QString verstr = GPGProc::gpgVersionString(executable);
105  m_version = GPGProc::gpgVersion(verstr);
106  kDebug(2100) << "version is" << verstr << m_version;
107 
108  m_useDebugLevel = (m_version > 0x20000);
109 
110  const QString gpgConfigFile = KGpgSettings::gpgConfigPath();
111 
112  m_standardArguments.clear();
113  m_standardArguments << QLatin1String( "--no-secmem-warning" )
114  << QLatin1String( "--no-tty" )
115  << QLatin1String("--no-greeting");
116 
117  if (!gpgConfigFile.isEmpty()) {
118  m_standardArguments << QLatin1String("--options")
119  << gpgConfigFile;
120 
121  // Check if the config file is in the default home directory
122  // of the binary. If it isn't add --homedir to command line also.
123  QString gpgdir = GPGProc::getGpgHome(executable);
124  gpgdir.chop(1); // remove trailing '/' as QFileInfo returns string without it
125  QFileInfo confFile(gpgConfigFile);
126  if (confFile.absolutePath() != gpgdir)
127  m_standardArguments << QLatin1String("--homedir")
128  << confFile.absolutePath();
129  }
130 
131  QStringList debugLevelArguments(QLatin1String("--debug-level"));
132  debugLevelArguments << QLatin1String("none");
133  if (checkGnupgArguments(executable, debugLevelArguments))
134  m_standardArguments << debugLevelArguments;
135 }
136 
137 const QStringList& GnupgBinary::standardArguments() const
138 {
139  return m_standardArguments;
140 }
141 
142 unsigned int GnupgBinary::version() const
143 {
144  return m_version;
145 }
146 
147 bool GnupgBinary::supportsDebugLevel() const
148 {
149  return m_useDebugLevel;
150 }
151 
152 K_GLOBAL_STATIC(GnupgBinary, lastBinary)
153 
154 GPGProc::GPGProc(QObject *parent, const QString &binary)
155  : KLineBufferedProcess(parent)
156 {
157  resetProcess(binary);
158 }
159 
160 GPGProc::~GPGProc()
161 {
162 }
163 
164 void
165 GPGProc::resetProcess(const QString &binary)
166 {
167  GnupgBinary *bin = lastBinary;
168  QString executable;
169  if (binary.isEmpty())
170  executable = KGpgSettings::gpgBinaryPath();
171  else
172  executable = binary;
173 
174  if (bin->binary() != executable)
175  bin->setBinary(executable);
176 
177  setProgram(executable, bin->standardArguments());
178 
179  setOutputChannelMode(OnlyStdoutChannel);
180 
181  disconnect(SIGNAL(finished(int,QProcess::ExitStatus)));
182  disconnect(SIGNAL(lineReadyStandardOutput()));
183 }
184 
185 void GPGProc::start()
186 {
187  // make sure there is exactly one connection from us to that signal
188  connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished()), Qt::UniqueConnection);
189  connect(this, SIGNAL(lineReadyStandardOutput()), this, SLOT(received()), Qt::UniqueConnection);
190  KProcess::start();
191 }
192 
193 void GPGProc::received()
194 {
195  emit readReady();
196 }
197 
198 void GPGProc::finished()
199 {
200  emit processExited();
201 }
202 
203 int GPGProc::readln(QString &line, const bool colons)
204 {
205  QByteArray a;
206  if (!readLineStandardOutput(&a))
207  return -1;
208 
209  line = recode(a, colons, m_codec);
210 
211  return line.length();
212 }
213 
214 int GPGProc::readln(QStringList &l)
215 {
216  QString s;
217 
218  int len = readln(s);
219  if (len < 0)
220  return len;
221 
222  l = s.split(QLatin1Char( ':' ));
223 
224  for (int i = 0; i < l.count(); ++i)
225  {
226  int j = 0;
227  while ((j = l[i].indexOf(QLatin1String( "\\x3a" ), j, Qt::CaseInsensitive)) >= 0)
228  {
229  l[i].replace(j, 4, QLatin1Char( ':' ));
230  j++;
231  }
232  }
233 
234  return l.count();
235 }
236 
237 QString
238 GPGProc::recode(QByteArray a, const bool colons, const QByteArray &codec)
239 {
240  const char *textcodec = codec.isEmpty() ? "utf8" : codec.constData();
241  int pos = 0;
242 
243  while ((pos = a.indexOf("\\x", pos)) >= 0) {
244  if (pos > a.length() - 4)
245  break;
246 
247  const QByteArray pattern(a.mid(pos, 4));
248  const QByteArray hexnum(pattern.right(2));
249  bool ok;
250  char n[2];
251  n[0] = hexnum.toUShort(&ok, 16);
252  n[1] = '\0'; // to use n as a 0-terminated string
253  if (!ok) {
254  // skip this occurrence
255  pos += 2;
256  continue;
257  }
258 
259  // QLatin1Char( ':' ) must be skipped, it is used as column delimiter
260  // since it is pure ascii it can be replaced in QString.
261  if (!colons && (n[0] == ':' )) {
262  pos += 3;
263  continue;
264  }
265 
266  // it is likely to find the same byte sequence more than once
267  int npos = pos;
268  do {
269  a.replace(npos, 4, n);
270  } while ((npos = a.indexOf(pattern, npos)) >= 0);
271  }
272 
273  return QTextCodec::codecForName(textcodec)->toUnicode(a);
274 }
275 
276 bool
277 GPGProc::setCodec(const QByteArray &codec)
278 {
279  const QList<QByteArray> codecs = QTextCodec::availableCodecs();
280  if (!codecs.contains(codec))
281  return false;
282 
283  m_codec = codec;
284 
285  return true;
286 }
287 
288 int GPGProc::gpgVersion(const QString &vstr)
289 {
290  if (vstr.isEmpty())
291  return -1;
292 
293  QStringList values(vstr.split(QLatin1Char( '.' )));
294  if (values.count() < 3)
295  return -2;
296 
297  return (0x10000 * values[0].toInt() + 0x100 * values[1].toInt() + values[2].toInt());
298 }
299 
300 QString GPGProc::gpgVersionString(const QString &binary)
301 {
302  GPGProc process(0, binary);
303  process << QLatin1String( "--version" );
304  process.start();
305  process.waitForFinished(-1);
306 
307  if (process.exitCode() == 255)
308  return QString();
309 
310  QString line;
311  if (process.readln(line) != -1)
312  return line.simplified().section(QLatin1Char( ' ' ), -1);
313  else
314  return QString();
315 }
316 
317 QString GPGProc::getGpgStartupError(const QString &binary)
318 {
319  GPGProc process(0, binary);
320  process << QLatin1String( "--version" );
321  process.start();
322  process.waitForFinished(-1);
323 
324  QString result;
325 
326  while (process.hasLineStandardError()) {
327  QByteArray tmp;
328  process.readLineStandardError(&tmp);
329  tmp += '\n';
330  result += QString::fromUtf8(tmp);
331  }
332 
333  return result;
334 }
335 
336 QString GPGProc::getGpgHome(const QString &binary)
337 {
338  // First try: if environment is set GnuPG will use that directory
339  // We can use this directly without starting a new process
340  QByteArray env(qgetenv("GNUPGHOME"));
341  QString gpgHome;
342  if (!env.isEmpty()) {
343  gpgHome = QLatin1String( env );
344  } else if (!binary.isEmpty()) {
345  // Second try: start GnuPG and ask what it is
346  gpgHome = getGpgProcessHome(binary);
347  }
348 
349  // Third try: guess what it is.
350  if (gpgHome.isEmpty()) {
351 #ifdef Q_OS_WIN32 //krazy:exclude=cpp
352  gpgHome = qgetenv("APPDATA") + QLatin1String( "/gnupg/" );
353  gpgHome.replace(QLatin1Char( '\\' ), QLatin1Char( '/' ));
354 #else
355  gpgHome = QDir::homePath() + QLatin1String( "/.gnupg/" );
356 #endif
357  }
358 
359  gpgHome.replace(QLatin1String( "//" ), QLatin1String( "/" ));
360 
361  if (!gpgHome.endsWith(QLatin1Char( '/' )))
362  gpgHome.append(QLatin1Char( '/' ));
363 
364  if (gpgHome.startsWith(QLatin1String("~/")))
365  gpgHome.replace(0, 1, QDir::homePath());
366 
367  KStandardDirs::makeDir(gpgHome, 0700);
368  return gpgHome;
369 }
370 
371 #include "gpgproc.moc"
GPGProc
A interface to GnuPG handling UTF8 recoding correctly.
Definition: gpgproc.h:36
QString::append
QString & append(QChar ch)
KProcess
KGpgSettings::gpgConfigPath
static QString gpgConfigPath()
Get The path of the gpg configuration file.
Definition: kgpgsettings.h:288
QByteArray
GPGProc::readln
int readln(QString &line, const bool colons=false)
Reads a line of text (excluding '\n').
Definition: gpgproc.cpp:203
GPGProc::getGpgHome
static QString getGpgHome(const QString &binary)
find users GnuPG directory
Definition: gpgproc.cpp:336
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
GPGProc::finished
void finished()
Definition: gpgproc.cpp:198
QByteArray::toUShort
ushort toUShort(bool *ok, int base) const
QByteArray::isEmpty
bool isEmpty() const
QString::simplified
QString simplified() const
GPGProc::~GPGProc
~GPGProc()
Destructor.
Definition: gpgproc.cpp:160
QByteArray::length
int length() const
QString::remove
QString & remove(int position, int n)
QString::chop
void chop(int n)
QDir::homePath
QString homePath()
GPGProc::processExited
void processExited()
Emitted when the process has finished.
QByteArray::indexOf
int indexOf(char ch, int from) const
getGpgProcessHome
static QString getGpgProcessHome(const QString &binary)
Definition: gpgproc.cpp:76
GPGProc::start
void start()
Starts the process.
Definition: gpgproc.cpp:185
QList::count
int count(const T &value) const
checkGnupgArguments
static bool checkGnupgArguments(const QString &executable, const QStringList &arguments)
check if GnuPG returns an error for this arguments
Definition: gpgproc.cpp:61
GPGProc::setCodec
bool setCodec(const QByteArray &codec)
sets the codec used to translate the incoming data
Definition: gpgproc.cpp:277
GPGProc::getGpgStartupError
static QString getGpgStartupError(const QString &binary)
run GnuPG and check if it complains about anything
Definition: gpgproc.cpp:317
QString::fromUtf8
QString fromUtf8(const char *str, int size)
GPGProc::readReady
void readReady()
Emitted when the process is ready for reading.
KGpgSettings::gpgBinaryPath
static QString gpgBinaryPath()
Get The path of the gpg binary used by KGpg.
Definition: kgpgsettings.h:307
QObject
GPGProc::gpgVersion
static int gpgVersion(const QString &vstr)
parse GnuPG version string and return version as number
Definition: gpgproc.cpp:288
QString::isEmpty
bool isEmpty() const
QString::trimmed
QString trimmed() const
QByteArray::constData
const char * constData() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
QByteArray::replace
QByteArray & replace(int pos, int len, const char *after)
gpgproc.h
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
KLineBufferedProcess
Read output of a process split into lines.
Definition: klinebufferedprocess.h:56
KLineBufferedProcess::readLineStandardOutput
bool readLineStandardOutput(QByteArray *line)
Reads a line of text (excluding '\n') from stdout.
Definition: klinebufferedprocess.cpp:88
QString
QList
QByteArray::mid
QByteArray mid(int pos, int len) const
QStringList
GPGProc::received
void received()
Definition: gpgproc.cpp:193
QFileInfo
KLineBufferedProcess::lineReadyStandardOutput
void lineReadyStandardOutput()
Emitted when there is a line of data available from stdout when there was previously none...
QLatin1Char
QList::contains
bool contains(const T &value) const
GPGProc::recode
static QString recode(QByteArray a, const bool colons=true, const QByteArray &codec=QByteArray())
Recode a line from GnuPG encoding to UTF8.
Definition: gpgproc.cpp:238
kgpgsettings.h
QString::replace
QString & replace(int position, int n, QChar after)
GPGProc::resetProcess
void resetProcess(const QString &binary=QString())
Reset the class to the state it had right after creation.
Definition: gpgproc.cpp:165
QTextCodec::availableCodecs
QList< QByteArray > availableCodecs()
QLatin1String
GPGProc::gpgVersionString
static QString gpgVersionString(const QString &binary)
get the GnuPG version string of the given binary
Definition: gpgproc.cpp:300
QTextCodec::codecForName
QTextCodec * codecForName(const QByteArray &name)
KLineBufferedProcess::readLineStandardError
bool readLineStandardError(QByteArray *line)
Reads a line of text (excluding '\n') from stderr.
Definition: klinebufferedprocess.cpp:103
QString::length
int length() const
QString::section
QString section(QChar sep, int start, int end, QFlags< QString::SectionFlag > flags) const
QTextCodec::toUnicode
QString toUnicode(const QByteArray &a) const
KLineBufferedProcess::hasLineStandardError
bool hasLineStandardError() const
Checks if a line is ready on stdout.
Definition: klinebufferedprocess.cpp:123
version
static const char version[]
Definition: main.cpp:26
QList::replace
void replace(int i, const T &value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:42:08 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kgpg

Skip menu "kgpg"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeutils API Reference

Skip menu "kdeutils API Reference"
  • ark
  • filelight
  • kcalc
  • kcharselect
  • kdf
  • kfloppy
  • kgpg
  • ktimer
  • kwallet
  • sweeper

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