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