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

kleopatra

  • sources
  • kde-4.14
  • kdepim
  • kleopatra
  • uiserver
uiserver.cpp
Go to the documentation of this file.
1 /* -*- mode: c++; c-basic-offset:4 -*-
2  uiserver/uiserver.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 <config-kleopatra.h>
34 
35 #include "uiserver.h"
36 #include "uiserver_p.h"
37 
38 #include "sessiondata.h"
39 
40 #include <utils/detail_p.h>
41 #include <utils/gnupg-helper.h>
42 
43 #include <kleo/stl_util.h>
44 #include <kleo/exception.h>
45 
46 #include <KDebug>
47 #include <KLocalizedString>
48 
49 #include <QTcpSocket>
50 #include <QDir>
51 #include <QEventLoop>
52 #include <QTimer>
53 #include <QFile>
54 
55 #ifndef Q_MOC_RUN
56 #include <boost/range/empty.hpp>
57 #include <boost/bind.hpp>
58 #endif
59 
60 #include <algorithm>
61 #include <cassert>
62 #include <cerrno>
63 
64 using namespace Kleo;
65 using namespace boost;
66 
67 // static
68 void UiServer::setLogStream( FILE * stream ) {
69  assuan_set_assuan_log_stream( stream );
70 }
71 
72 UiServer::Private::Private( UiServer * qq )
73  : QTcpServer(),
74  q( qq ),
75  file(),
76  factories(),
77  connections(),
78  suggestedSocketName(),
79  actualSocketName(),
80  cryptoCommandsEnabled( false )
81 {
82 #ifndef HAVE_ASSUAN2
83  assuan_set_assuan_err_source( GPG_ERR_SOURCE_DEFAULT );
84 #else
85  assuan_set_gpg_err_source( GPG_ERR_SOURCE_DEFAULT );
86  assuan_sock_init();
87 #endif
88 }
89 
90 bool UiServer::Private::isStaleAssuanSocket( const QString& fileName )
91 {
92  assuan_context_t ctx = 0;
93 #ifndef HAVE_ASSUAN2
94  const bool error = assuan_socket_connect_ext( &ctx, QFile::encodeName( fileName ).constData(), -1, 0 );
95 #else
96  const bool error = assuan_new( &ctx ) || assuan_socket_connect( ctx, QFile::encodeName( fileName ).constData(), ASSUAN_INVALID_PID, 0 );
97 #endif
98  if ( !error )
99 #ifndef HAVE_ASSUAN2
100  assuan_disconnect( ctx );
101 #else
102  assuan_release( ctx );
103 #endif
104  return error;
105 }
106 
107 UiServer::UiServer( const QString & socket, QObject * p )
108  : QObject( p ), d( new Private( this ) )
109 {
110  d->suggestedSocketName = d->makeFileName( socket );
111 }
112 
113 UiServer::~UiServer() {
114  if ( QFile::exists( d->actualSocketName ) )
115  QFile::remove( d->actualSocketName );
116 }
117 
118 bool UiServer::registerCommandFactory( const shared_ptr<AssuanCommandFactory> & cf ) {
119  if ( cf && empty( std::equal_range( d->factories.begin(), d->factories.end(), cf, _detail::ByName<std::less>() ) ) ) {
120  d->factories.push_back( cf );
121  std::inplace_merge( d->factories.begin(), d->factories.end() - 1, d->factories.end(), _detail::ByName<std::less>() );
122  return true;
123  } else {
124  if ( !cf ) {
125  kWarning() << "NULL factory";
126  } else {
127  kWarning() << ( void* )cf.get() << " factory already registered";
128  }
129 
130  return false;
131  }
132 }
133 
134 void UiServer::start() {
135  d->makeListeningSocket();
136 }
137 
138 void UiServer::stop() {
139 
140  d->close();
141 
142  if ( d->file.exists() )
143  d->file.remove();
144 
145  if ( isStopped() ) {
146  SessionDataHandler::instance()->clear();
147  emit stopped();
148  }
149 
150 }
151 
152 void UiServer::enableCryptoCommands( bool on ) {
153  if ( on == d->cryptoCommandsEnabled )
154  return;
155  d->cryptoCommandsEnabled = on;
156  kdtools::for_each( d->connections,
157  boost::bind( &AssuanServerConnection::enableCryptoCommands, _1, on ) );
158 }
159 
160 QString UiServer::socketName() const {
161  return d->actualSocketName;
162 }
163 
164 bool UiServer::waitForStopped( unsigned int ms ) {
165  if ( isStopped() )
166  return true;
167  QEventLoop loop;
168  QTimer timer;
169  timer.setInterval( ms );
170  timer.setSingleShot( true );
171  connect( &timer, SIGNAL(timeout()), &loop, SLOT(quit()) );
172  connect( this, SIGNAL(stopped()), &loop, SLOT(quit()) );
173  loop.exec();
174  return !timer.isActive();
175 }
176 
177 bool UiServer::isStopped() const {
178  return d->connections.empty() && !d->isListening() ;
179 }
180 
181 bool UiServer::isStopping() const {
182  return !d->connections.empty() && !d->isListening() ;
183 }
184 
185 void UiServer::Private::slotConnectionClosed( Kleo::AssuanServerConnection * conn ) {
186  kDebug() << "UiServer: connection " << ( void* )conn << " closed";
187  connections.erase( std::remove_if( connections.begin(), connections.end(),
188  boost::bind( &boost::shared_ptr<AssuanServerConnection>::get, _1 ) == conn ),
189  connections.end() );
190  if ( q->isStopped() ) {
191  SessionDataHandler::instance()->clear();
192  emit q->stopped();
193  }
194 }
195 
196 
197 void UiServer::Private::incomingConnection( int fd ) {
198  try {
199  kDebug() << "UiServer: client connect on fd " << fd;
200 #if defined(HAVE_ASSUAN_SOCK_GET_NONCE) || defined(HAVE_ASSUAN2)
201  if ( assuan_sock_check_nonce( (assuan_fd_t)fd, &nonce ) ) {
202  kDebug() << "UiServer: nonce check failed";
203  assuan_sock_close( (assuan_fd_t)fd );
204  return;
205  }
206 #endif
207  const shared_ptr<AssuanServerConnection> c( new AssuanServerConnection( (assuan_fd_t)fd, factories ) );
208  connect( c.get(), SIGNAL(closed(Kleo::AssuanServerConnection*)),
209  this, SLOT(slotConnectionClosed(Kleo::AssuanServerConnection*)) );
210  connect( c.get(), SIGNAL(startKeyManagerRequested()),
211  q, SIGNAL(startKeyManagerRequested()), Qt::QueuedConnection );
212  connect( c.get(), SIGNAL(startConfigDialogRequested()),
213  q, SIGNAL(startConfigDialogRequested()), Qt::QueuedConnection );
214  c->enableCryptoCommands( cryptoCommandsEnabled );
215  connections.push_back( c );
216  kDebug() << "UiServer: client connection " << ( void *)c.get() << " established successfully";
217  } catch ( const Exception & e ) {
218  kDebug() << "UiServer: client connection failed: " << e.what();
219  QTcpSocket s;
220  s.setSocketDescriptor( fd );
221  QTextStream( &s ) << "ERR " << e.error_code() << " " << e.what() << "\r\n";
222  s.waitForBytesWritten();
223  s.close();
224  } catch ( ... ) {
225  kDebug() << "UiServer: client connection failed: unknown exception caught";
226  // this should never happen...
227  QTcpSocket s;
228  s.setSocketDescriptor( fd );
229  QTextStream( &s ) << "ERR 63 unknown exception caught\r\n";
230  s.waitForBytesWritten();
231  s.close();
232  }
233 }
234 
235 QString UiServer::Private::makeFileName( const QString & socket ) const {
236  if ( !socket.isEmpty() )
237  return socket;
238  const QString gnupgHome = gnupgHomeDirectory();
239  if ( gnupgHome.isEmpty() )
240  throw_<std::runtime_error>( i18n( "Could not determine the GnuPG home directory. Consider setting the GNUPGHOME environment variable." ) );
241  ensureDirectoryExists( gnupgHome );
242  const QDir dir( gnupgHome );
243  assert( dir.exists() );
244  return dir.absoluteFilePath( QLatin1String("S.uiserver") );
245 }
246 
247 void UiServer::Private::ensureDirectoryExists( const QString& path ) const {
248  const QFileInfo info( path );
249  if ( info.exists() && !info.isDir() )
250  throw_<std::runtime_error>( i18n( "Cannot determine the GnuPG home directory: %1 exists but is not a directory.", path ) );
251  if ( info.exists() )
252  return;
253  const QDir dummy; //there is no static QDir::mkpath()...
254  errno = 0;
255  if ( !dummy.mkpath( path ) )
256  throw_<std::runtime_error>( i18n( "Could not create GnuPG home directory %1: %2", path, systemErrorString() ) );
257 }
258 
259 void UiServer::Private::makeListeningSocket() {
260 
261  // First, create a file (we do this only for the name, gmpfh)
262  const QString fileName = suggestedSocketName;
263 
264  if ( QFile::exists( fileName ) ) {
265  if ( isStaleAssuanSocket( fileName ) ) {
266  QFile::remove( fileName );
267  } else {
268  throw_<std::runtime_error>( i18n( "Detected another running gnupg UI server listening at %1.", fileName ) );
269  }
270  }
271 
272  doMakeListeningSocket( QFile::encodeName( fileName ) );
273 
274  actualSocketName = suggestedSocketName;
275 }
276 
277 #include "moc_uiserver_p.cpp"
QTimer::setInterval
void setInterval(int msec)
Kleo::UiServer::startKeyManagerRequested
void startKeyManagerRequested()
QEventLoop
Kleo::gnupgHomeDirectory
QString gnupgHomeDirectory()
Definition: gnupg-helper.cpp:56
QFile::remove
bool remove()
Kleo::UiServer::isStopped
bool isStopped() const
Definition: uiserver.cpp:177
QFile::exists
bool exists() const
QAbstractSocket::setSocketDescriptor
bool setSocketDescriptor(int socketDescriptor, SocketState socketState, QFlags< QIODevice::OpenModeFlag > openMode)
connections
static const struct @10 connections[]
Kleo::UiServer::stop
void stop()
Definition: uiserver.cpp:138
Kleo::UiServer::registerCommandFactory
bool registerCommandFactory(const boost::shared_ptr< AssuanCommandFactory > &cmdFactory)
Definition: uiserver.cpp:118
QTextStream
Kleo::SessionDataHandler::instance
static boost::shared_ptr< SessionDataHandler > instance()
Definition: sessiondata.cpp:61
boost::shared_ptr
Definition: encryptemailcontroller.h:51
d
#define d
Definition: adduseridcommand.cpp:89
sessiondata.h
QAbstractSocket::close
virtual void close()
Kleo::UiServer
Definition: uiserver.h:52
QTimer
QEventLoop::exec
int exec(QFlags< QEventLoop::ProcessEventsFlag > flags)
QObject
Kleo::UiServer::Private
Definition: uiserver_p.h:63
Kleo::UiServer::isStopping
bool isStopping() const
Definition: uiserver.cpp:181
QAbstractSocket::waitForBytesWritten
virtual bool waitForBytesWritten(int msecs)
QString::isEmpty
bool isEmpty() const
Kleo::UiServer::stopped
void stopped()
Kleo::UiServer::startConfigDialogRequested
void startConfigDialogRequested()
Kleo::AssuanServerConnection::enableCryptoCommands
void enableCryptoCommands(bool enable=true)
Definition: assuanserverconnection.cpp:996
QString
gnupg-helper.h
QFileInfo
Kleo::UiServer::waitForStopped
bool waitForStopped(unsigned int ms=0xFFFFFFFF)
Definition: uiserver.cpp:164
QTcpServer
Kleo::UiServer::Private::Private
Private(UiServer *qq)
Definition: uiserver.cpp:72
Kleo::UiServer::setLogStream
static void setLogStream(FILE *file)
Definition: uiserver.cpp:68
Kleo::UiServer::Private::incomingConnection
void incomingConnection(int fd)
Definition: uiserver.cpp:197
QDir
dir
static QString dir(const QString &id)
Definition: filedialog.cpp:54
Kleo::UiServer::enableCryptoCommands
void enableCryptoCommands(bool enable=true)
Definition: uiserver.cpp:152
uiserver_p.h
Kleo::UiServer::UiServer
UiServer(const QString &socket, QObject *parent=0)
Definition: uiserver.cpp:107
QLatin1String
q
#define q
Definition: adduseridcommand.cpp:90
Kleo::_detail::ByName
Definition: detail_p.h:54
Kleo::UiServer::~UiServer
~UiServer()
Definition: uiserver.cpp:113
Kleo::UiServer::Private::isStaleAssuanSocket
static bool isStaleAssuanSocket(const QString &socketName)
Definition: uiserver.cpp:90
detail_p.h
Kleo::UiServer::start
void start()
Definition: uiserver.cpp:134
Kleo::UiServer::socketName
QString socketName() const
Definition: uiserver.cpp:160
assuan_fd_t
int assuan_fd_t
Definition: kleo-assuan.h:72
QTcpSocket
QTimer::isActive
bool isActive() const
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Kleo::AssuanServerConnection
Definition: assuanserverconnection.h:53
uiserver.h
QFile::encodeName
QByteArray encodeName(const QString &fileName)
QDir::mkpath
bool mkpath(const QString &dirPath) const
QTimer::setSingleShot
void setSingleShot(bool singleShot)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:33:11 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
  • pimprint

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