• 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
  • smartcard
readerstatus.cpp
Go to the documentation of this file.
1 /* -*- mode: c++; c-basic-offset:4 -*-
2  smartcard/readerstatus.cpp
3 
4  This file is part of Kleopatra, the KDE keymanager
5  Copyright (c) 2009 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 "readerstatus.h"
36 
37 #include <utils/gnupg-helper.h>
38 #include <utils/kdsignalblocker.h>
39 #include <utils/filesystemwatcher.h>
40 
41 #include <kleo/stl_util.h>
42 
43 #include <gpgme++/context.h>
44 #include <gpgme++/assuanresult.h>
45 #include <gpgme++/defaultassuantransaction.h>
46 #include <gpgme++/key.h>
47 #include <gpgme++/keylistresult.h>
48 
49 #include <gpg-error.h>
50 
51 #include <KDebug>
52 
53 #include <QStringList>
54 #include <QDir>
55 #include <QFileInfo>
56 #include <QMutex>
57 #include <QWaitCondition>
58 #include <QThread>
59 #include <QTimer>
60 #include <QPointer>
61 
62 #ifndef _WIN32_WCE
63 #include <boost/algorithm/string/split.hpp>
64 #include <boost/algorithm/string/classification.hpp>
65 #include <boost/algorithm/string/case_conv.hpp>
66 #endif
67 #include <boost/static_assert.hpp>
68 #include <boost/range.hpp>
69 #include <boost/bind.hpp>
70 
71 #include <vector>
72 #include <set>
73 #include <list>
74 #include <algorithm>
75 #include <iterator>
76 #include <utility>
77 #include <cstdlib>
78 
79 using namespace Kleo;
80 using namespace Kleo::SmartCard;
81 using namespace GpgME;
82 using namespace boost;
83 
84 static const unsigned int RETRY_WAIT = 2; // seconds
85 static const unsigned int CHECK_INTERVAL = 2000; // msecs
86 
87 static ReaderStatus * self = 0;
88 
89 struct CardInfo {
90  CardInfo()
91  : fileName(),
92  status( ReaderStatus::NoCard ),
93  appType( ReaderStatus::UnknownApplication ),
94  appVersion( -1 )
95  {
96 
97  }
98  CardInfo( const QString & fn, ReaderStatus::Status s )
99  : fileName( fn ),
100  status( s ),
101  appType( ReaderStatus::UnknownApplication ),
102  appVersion( -1 )
103  {
104 
105  }
106 
107  QString fileName;
108  ReaderStatus::Status status;
109  std::string serialNumber;
110  ReaderStatus::AppType appType;
111  int appVersion;
112  std::vector<ReaderStatus::PinState> pinStates;
113 };
114 
115 static const char * flags[] = {
116  "NOCARD",
117  "PRESENT",
118  "ACTIVE",
119  "USABLE",
120 };
121 BOOST_STATIC_ASSERT(( sizeof flags/sizeof *flags == ReaderStatus::_NumScdStates ));
122 
123 static const char * prettyFlags[] = {
124  "NoCard",
125  "CardPresent",
126  "CardActive",
127  "CardUsable",
128  "CardCanLearnKeys",
129  "CardHasNullPin",
130  "CardError",
131 };
132 BOOST_STATIC_ASSERT(( sizeof prettyFlags/sizeof *prettyFlags == ReaderStatus::NumStates ));
133 
134 static QByteArray read_file( const QString & fileName ) {
135  QFile file( fileName );
136  if ( !file.exists() ) {
137  kDebug() << "read_file: file" << fileName << "does not exist";
138  return QByteArray();
139  }
140  if ( !file.open( QIODevice::ReadOnly ) ) {
141  kDebug() << "read_file: failed to open" << fileName << ':' << file.errorString();
142  return QByteArray();
143  }
144  return file.readAll().trimmed();
145 }
146 
147 static unsigned int parseFileName( const QString & fileName, bool * ok ) {
148  QRegExp rx( QLatin1String( "reader_(\\d+)\\.status" ) );
149  if ( ok )
150  *ok = false;
151  if ( rx.exactMatch( QFileInfo( fileName ).fileName() ) )
152  return rx.cap(1).toUInt( ok, 10 );
153  return 0;
154 }
155 
156 namespace {
157  template <typename T_Target, typename T_Source>
158  std::auto_ptr<T_Target> dynamic_pointer_cast( std::auto_ptr<T_Source> & in ) {
159  if ( T_Target * const target = dynamic_cast<T_Target*>( in.get() ) ) {
160  in.release();
161  return std::auto_ptr<T_Target>( target );
162  } else {
163  return std::auto_ptr<T_Target>();
164  }
165  }
166 
167  template <typename T>
168  const T & _trace__impl( const T & t, const char * msg ) {
169  kDebug() << msg << t;
170  return t;
171  }
172 #define TRACE( x ) _trace__impl( x, #x )
173 }
174 
175 static QDebug operator<<( QDebug s, const std::vector< std::pair<std::string,std::string> > & v ) {
176  typedef std::pair<std::string,std::string> pair;
177  s << '(';
178  Q_FOREACH( const pair & p, v )
179  s << "status(" << QString::fromStdString( p.first ) << ") =" << QString::fromStdString( p.second ) << endl;
180  return s << ')';
181 }
182 
183 static const char * app_types[] = {
184  "_", // will hopefully never be used as an app-type :)
185  "openpgp",
186  "nks",
187  "p15",
188  "dinsig",
189  "geldkarte",
190 };
191 BOOST_STATIC_ASSERT(( sizeof app_types / sizeof *app_types == ReaderStatus::NumAppTypes ));
192 
193 
194 static ReaderStatus::AppType parse_app_type( const std::string & s ) {
195  kDebug() << "parse_app_type(" << s.c_str() << ")";
196 #ifndef _WIN32_WCE
197  const char ** it = std::find( begin( app_types ), end( app_types ), to_lower_copy( s ) );
198 #else
199  std::string lowerStr ;
200  for (std::string::const_iterator itr = s.begin();itr!=s.end();++itr) {
201  lowerStr+=tolower(*itr);
202  }
203  const char ** it = std::find( begin( app_types ), end( app_types ), lowerStr );
204 #endif
205  if ( it == end( app_types ) )
206  return TRACE( ReaderStatus::UnknownApplication );
207  return TRACE( static_cast<ReaderStatus::AppType>( it - begin( app_types ) ) );
208 
209 }
210 
211 static int parse_app_version( const std::string & s ) {
212  return std::atoi( s.c_str() );
213 }
214 
215 static ReaderStatus::PinState parse_pin_state( const std::string & s ) {
216  switch ( int i = std::atoi( s.c_str() ) ) {
217  case -4: return ReaderStatus::NullPin;
218  case -3: return ReaderStatus::PinBlocked;
219  case -2: return ReaderStatus::NoPin;
220  case -1: return ReaderStatus::UnknownPinState;
221  default:
222  if ( i < 0 )
223  return ReaderStatus::UnknownPinState;
224  else
225  return ReaderStatus::PinOk;
226  }
227 }
228 
229 static std::auto_ptr<DefaultAssuanTransaction> gpgagent_transact( shared_ptr<Context> & gpgAgent, const char * command, Error & err ) {
230 #ifdef DEBUG_SCREADER
231  kDebug() << "gpgagent_transact(" << command << ")";
232 #endif
233  const AssuanResult res = gpgAgent->assuanTransact( command );
234  err = res.error();
235  if ( !err.code() )
236  err = res.assuanError();
237  if ( err.code() ) {
238 #ifdef DEBUG_SCREADER
239  kDebug() << "gpgagent_transact(" << command << "):" << QString::fromLocal8Bit( err.asString() );
240 #endif
241  if ( err.code() >= GPG_ERR_ASS_GENERAL && err.code() <= GPG_ERR_ASS_UNKNOWN_INQUIRE ) {
242  kDebug() << "Assuan problem, killing context";
243  gpgAgent.reset();
244  }
245  return std::auto_ptr<DefaultAssuanTransaction>();
246  }
247  std::auto_ptr<AssuanTransaction> t = gpgAgent->takeLastAssuanTransaction();
248  return dynamic_pointer_cast<DefaultAssuanTransaction>( t );
249 }
250 
251 // returns const std::string so template deduction in boost::split works, and we don't need a temporary
252 static const std::string scd_getattr_status( shared_ptr<Context> & gpgAgent, const char * what, Error & err ) {
253  std::string cmd = "SCD GETATTR ";
254  cmd += what;
255  const std::auto_ptr<DefaultAssuanTransaction> t = gpgagent_transact( gpgAgent, cmd.c_str(), err );
256  if ( t.get() ) {
257  kDebug() << "scd_getattr_status(" << what << "): got" << t->statusLines();
258  return t->firstStatusLine( what );
259  } else {
260  kDebug() << "scd_getattr_status(" << what << "): t == NULL";
261  return std::string();
262  }
263 }
264 
265 static unsigned int parse_event_counter( const std::string & str ) {
266  unsigned int result;
267  if ( sscanf( str.c_str(), "%*u %*u %u ", &result ) == 1 )
268  return result;
269  return -1;
270 }
271 
272 static unsigned int get_event_counter( shared_ptr<Context> & gpgAgent ) {
273  Error err;
274  const std::auto_ptr<DefaultAssuanTransaction> t = gpgagent_transact( gpgAgent, "GETEVENTCOUNTER", err );
275  if ( err.code() )
276  kDebug() << "get_event_counter(): got error" << err.asString();
277  if ( t.get() ) {
278 #ifdef DEBUG_SCREADER
279  kDebug() << "get_event_counter(): got" << t->statusLines();
280 #endif
281  return parse_event_counter( t->firstStatusLine( "EVENTCOUNTER" ) );
282  } else {
283  kDebug() << "scd_getattr_status(): t == NULL";
284  return -1;
285  }
286 }
287 
288 // returns const std::string so template deduction in boost::split works, and we don't need a temporary
289 static const std::string gpgagent_data( shared_ptr<Context> & gpgAgent, const char * what, Error & err ) {
290  const std::auto_ptr<DefaultAssuanTransaction> t = gpgagent_transact( gpgAgent, what, err );
291  if ( t.get() )
292  return t->data();
293  else
294  return std::string();
295 }
296 
297 static std::string parse_keypairinfo( const std::string & kpi ) {
298  static const char hexchars[] = "0123456789abcdefABCDEF";
299  return '&' + kpi.substr( 0, kpi.find_first_not_of( hexchars ) );
300 }
301 
302 static bool parse_keypairinfo_and_lookup_key( Context * ctx, const std::string & kpi ) {
303  if ( !ctx )
304  return false;
305  const std::string pattern = parse_keypairinfo( kpi );
306  kDebug() << "parse_keypairinfo_and_lookup_key: pattern=" << pattern.c_str();
307  if ( const Error err = ctx->startKeyListing( pattern.c_str() ) ) {
308  kDebug() << "parse_keypairinfo_and_lookup_key: startKeyListing failed:" << err.asString();
309  return false;
310  }
311  Error e;
312  const Key key = ctx->nextKey( e );
313  ctx->endKeyListing();
314  kDebug() << "parse_keypairinfo_and_lookup_key: e=" << e.code() << "; key.isNull()" << key.isNull();
315  return !e && !key.isNull();
316 }
317 
318 static CardInfo get_card_status( const QString & fileName, unsigned int idx, shared_ptr<Context> & gpg_agent ) {
319 #ifdef DEBUG_SCREADER
320  kDebug() << "get_card_status(" << fileName << ',' << idx << ',' << gpg_agent.get() << ')';
321 #endif
322  CardInfo ci( fileName, ReaderStatus::CardUsable );
323  if ( idx != 0 || !gpg_agent )
324  return ci;
325  Error err;
326  ci.serialNumber = gpgagent_data( gpg_agent, "SCD SERIALNO", err );
327  if ( err.code() == GPG_ERR_CARD_NOT_PRESENT || err.code() == GPG_ERR_CARD_REMOVED ) {
328  ci.status = ReaderStatus::NoCard;
329  return ci;
330  }
331  if ( err.code() ) {
332  ci.status = ReaderStatus::CardError;
333  return ci;
334  }
335  ci.appType = parse_app_type( scd_getattr_status( gpg_agent, "APPTYPE", err ) );
336  if ( err.code() )
337  return ci;
338  if ( ci.appType != ReaderStatus::NksApplication ) {
339  kDebug() << "get_card_status: not a NetKey card, giving up";
340  return ci;
341  }
342  ci.appVersion = parse_app_version( scd_getattr_status( gpg_agent, "NKS-VERSION", err ) );
343  if ( err.code() )
344  return ci;
345  if ( ci.appVersion != 3 ) {
346  kDebug() << "get_card_status: not a NetKey v3 card, giving up";
347  return ci;
348  }
349 
350  // the following only works for NKS v3...
351  std::vector<std::string> chvStatus;
352  chvStatus.reserve( 4 ); // expected number of fields
353 #ifdef _WIN32_WCE
354  for ( std::string::size_type b = 0, e = scd_getattr_status( gpg_agent, "CHV-STATUS", err ).find( ' \t', 0 ) ; e != std::string::npos ; b = e+1, e = scd_getattr_status( gpg_agent, "CHV-STATUS", err ).find( ' \t', b ) )
355  if ( e > b )
356  chvStatus.push_back( scd_getattr_status( gpg_agent, "CHV-STATUS", err ).substr( b, e-b ) );
357 #else
358  split( chvStatus, scd_getattr_status( gpg_agent, "CHV-STATUS", err ), is_any_of( " \t" ), token_compress_on );
359 #endif
360  if ( err.code() )
361  return ci;
362  std::transform( chvStatus.begin(), chvStatus.end(),
363  std::back_inserter( ci.pinStates ),
364  parse_pin_state );
365 
366  if ( kdtools::contains( ci.pinStates, ReaderStatus::NullPin ) ) {
367  ci.status = ReaderStatus::CardHasNullPin;
368  return ci;
369  }
370 
371  // check for keys to learn:
372  const std::auto_ptr<DefaultAssuanTransaction> result = gpgagent_transact( gpg_agent, "SCD LEARN --keypairinfo", err );
373  if ( err.code() || !result.get() )
374  return ci;
375  const std::vector<std::string> keyPairInfos = result->statusLine( "KEYPAIRINFO" );
376  if ( keyPairInfos.empty() )
377  return ci;
378 
379  // check that any of the
380  const std::auto_ptr<Context> klc( Context::createForProtocol( CMS ) ); // what about OpenPGP?
381  if ( !klc.get() )
382  return ci;
383  klc->setKeyListMode( Ephemeral );
384 
385  if ( kdtools::any( keyPairInfos, !boost::bind( &parse_keypairinfo_and_lookup_key, klc.get(), _1 ) ) )
386  ci.status = ReaderStatus::CardCanLearnKeys;
387 
388 #ifdef DEBUG_SCREADER
389  kDebug() << "get_card_status: ci.status " << prettyFlags[ci.status];
390 #endif
391 
392  return ci;
393 }
394 
395 static std::vector<CardInfo> update_cardinfo( const QString & gnupgHomePath, shared_ptr<Context> & gpgAgent ) {
396 #ifdef DEBUG_SCREADER
397  kDebug() << "<update_cardinfo>";
398 #endif
399  const QDir gnupgHome( gnupgHomePath );
400  if ( !gnupgHome.exists() )
401  kWarning() << "gnupg home" << gnupgHomePath << "does not exist!";
402 
403  const CardInfo ci = get_card_status( gnupgHome.absoluteFilePath( QLatin1String( "reader_0.status" ) ), 0, gpgAgent );
404 #ifdef DEBUG_SCREADER
405  kDebug() << "</update_cardinfo>";
406 #endif
407  return std::vector<CardInfo>( 1, ci );
408 }
409 
410 static bool check_event_counter_changed( shared_ptr<Context> & gpg_agent, unsigned int & counter ) {
411  const unsigned int oldCounter = counter;
412  counter = get_event_counter( gpg_agent );
413  if ( oldCounter != counter ) {
414 #ifdef DEBUG_SCREADER
415  kDebug() << "ReaderStatusThread[2nd]: events:" << oldCounter << "->" << counter ;
416 #endif
417  return true;
418  } else {
419  return false;
420  }
421 }
422 
423 struct Transaction {
424  QByteArray command;
425  QPointer<QObject> receiver;
426  const char * slot;
427  GpgME::Error error;
428 };
429 
430 static const Transaction checkTransaction = { "__check__", 0, 0, Error() };
431 static const Transaction updateTransaction = { "__update__", 0, 0, Error() };
432 static const Transaction quitTransaction = { "__quit__", 0, 0, Error() };
433 
434 namespace {
435  class ReaderStatusThread : public QThread {
436  Q_OBJECT
437  public:
438  explicit ReaderStatusThread( QObject * parent=0 )
439  : QThread( parent ),
440  m_gnupgHomePath( Kleo::gnupgHomeDirectory() ),
441  m_transactions( 1, updateTransaction ) // force initial scan
442  {
443  connect( this, SIGNAL(oneTransactionFinished()),
444  this, SLOT(slotOneTransactionFinished()) );
445  }
446 
447  std::vector<CardInfo> cardInfos() const {
448  const QMutexLocker locker( &m_mutex );
449  return m_cardInfos;
450  }
451 
452  ReaderStatus::Status cardStatus( unsigned int slot ) const {
453  const QMutexLocker locker( &m_mutex );
454  if ( slot < m_cardInfos.size() )
455  return m_cardInfos[slot].status;
456  else
457  return ReaderStatus::NoCard;
458  }
459 
460  void addTransaction( const Transaction & t ) {
461  const QMutexLocker locker( &m_mutex );
462  m_transactions.push_back( t );
463  m_waitForTransactions.wakeOne();
464  }
465 
466  // make QThread::sleep public
467  using QThread::sleep;
468 
469  Q_SIGNALS:
470  void anyCardHasNullPinChanged( bool );
471  void anyCardCanLearnKeysChanged( bool );
472  void cardStatusChanged( unsigned int, Kleo::SmartCard::ReaderStatus::Status );
473  void oneTransactionFinished();
474 
475  public Q_SLOTS:
476  void ping() {
477  kDebug() << "ReaderStatusThread[GUI]::ping()";
478  addTransaction( updateTransaction );
479  }
480 
481  void stop() {
482  const QMutexLocker locker( &m_mutex );
483  m_transactions.push_front( quitTransaction );
484  m_waitForTransactions.wakeOne();
485  }
486 
487  void slotReaderStatusFileChanged() {
488  const QDir gnupgHome( m_gnupgHomePath );
489  if ( !gnupgHome.exists() ) {
490  kWarning() << "gnupg home" << m_gnupgHomePath << "does not exist!";
491  return;
492  }
493 
494  QStringList files = gnupgHome.entryList( QStringList( QLatin1String( "reader_*.status" ) ), QDir::Files, QDir::Name );
495  bool * dummy = 0;
496  kdtools::sort( files, boost::bind( parseFileName, _1, dummy ) < boost::bind( parseFileName, _2, dummy ) );
497 
498  std::vector<QByteArray> contents;
499 
500  Q_FOREACH( const QString & file, files ) {
501  bool ok = false;
502  const unsigned int idx = parseFileName( file, &ok );
503  if ( !ok ) {
504  kDebug() << "filename" << file << ": cannot parse reader slot number";
505  continue;
506  }
507  assert( idx >= contents.size() );
508  contents.resize( idx );
509  contents.push_back( read_file( gnupgHome.absoluteFilePath( file ) ) );
510  }
511 
512  // canonicalise by removing empty stuff from the end
513  while ( !contents.empty() && contents.back().isEmpty() )
514  contents.pop_back();
515 
516  if ( contents != readerStatusFileContents )
517  ping();
518 
519  readerStatusFileContents.swap( contents );
520  }
521 
522  private Q_SLOTS:
523  void slotOneTransactionFinished() {
524  std::list<Transaction> ft;
525  KDAB_SYNCHRONIZED( m_mutex )
526  ft.splice( ft.begin(), m_finishedTransactions );
527  Q_FOREACH( const Transaction & t, ft )
528  if ( t.receiver && t.slot && *t.slot )
529  QMetaObject::invokeMethod( t.receiver, t.slot, Qt::DirectConnection, Q_ARG( GpgME::Error, t.error ) );
530  }
531 
532  private:
533  /* reimp */ void run() {
534 
535  shared_ptr<Context> gpgAgent;
536  unsigned int eventCounter = -1;
537 
538  while ( true ) {
539 
540  QByteArray command;
541  bool nullSlot;
542  std::list<Transaction> item;
543  std::vector<CardInfo> oldCardInfos;
544 
545  if ( !gpgAgent ) {
546  Error err;
547  std::auto_ptr<Context> c = Context::createForEngine( AssuanEngine, &err );
548  if ( err.code() == GPG_ERR_NOT_SUPPORTED )
549  return;
550  gpgAgent = c;
551  }
552 
553  KDAB_SYNCHRONIZED( m_mutex ) {
554 
555  while ( m_transactions.empty() ) {
556  // go to sleep waiting for more work:
557 #ifdef DEBUG_SCREADER
558  kDebug() << "ReaderStatusThread[2nd]: .zZZ";
559 #endif
560  if ( !m_waitForTransactions.wait( &m_mutex, CHECK_INTERVAL ) )
561  m_transactions.push_front( checkTransaction );
562 #ifdef DEBUG_SCREADER
563  kDebug() << "ReaderStatusThread[2nd]: .oOO";
564 #endif
565  }
566 
567  // splice off the first transaction without
568  // copying, so we own it without really importing
569  // it into this thread (the QPointer isn't
570  // thread-safe):
571  item.splice( item.end(),
572  m_transactions, m_transactions.begin() );
573 
574  // make local copies of the interesting stuff so
575  // we can release the mutex again:
576  command = item.front().command;
577  nullSlot = !item.front().slot;
578  oldCardInfos = m_cardInfos;
579  }
580 
581 #ifdef DEBUG_SCREADER
582  kDebug() << "ReaderStatusThread[2nd]: new iteration command=" << command << " ; nullSlot=" << nullSlot;
583 #endif
584  // now, let's see what we got:
585 
586  if ( nullSlot && command == quitTransaction.command )
587  return; // quit
588 
589  if ( nullSlot && command == updateTransaction.command ||
590  nullSlot && command == checkTransaction.command ) {
591 
592  if ( nullSlot && command == checkTransaction.command && !check_event_counter_changed( gpgAgent, eventCounter ) )
593  continue; // early out
594 
595  std::vector<CardInfo> newCardInfos
596  = update_cardinfo( m_gnupgHomePath, gpgAgent );
597 
598  newCardInfos.resize( std::max( newCardInfos.size(), oldCardInfos.size() ) );
599  oldCardInfos.resize( std::max( newCardInfos.size(), oldCardInfos.size() ) );
600 
601  KDAB_SYNCHRONIZED( m_mutex )
602  m_cardInfos = newCardInfos;
603 
604  std::vector<CardInfo>::const_iterator
605  nit = newCardInfos.begin(), nend = newCardInfos.end(),
606  oit = oldCardInfos.begin(), oend = oldCardInfos.end() ;
607 
608  unsigned int idx = 0;
609  bool anyLC = false;
610  bool anyNP = false;
611  bool anyError = false;
612  while ( nit != nend && oit != oend ) {
613  if ( nit->status != oit->status ) {
614 #ifdef DEBUG_SCREADER
615  kDebug() << "ReaderStatusThread[2nd]: slot" << idx << ":" << prettyFlags[oit->status] << "->" << prettyFlags[nit->status];
616 #endif
617  emit cardStatusChanged( idx, nit->status );
618  }
619  if ( nit->status == ReaderStatus::CardCanLearnKeys )
620  anyLC = true;
621  if ( nit->status == ReaderStatus::CardHasNullPin )
622  anyNP = true;
623  if ( nit->status == ReaderStatus::CardError )
624  anyError = true;
625  ++nit;
626  ++oit;
627  ++idx;
628  }
629 
630  emit anyCardHasNullPinChanged( anyNP );
631  emit anyCardCanLearnKeysChanged( anyLC );
632 
633  if ( anyError )
634  gpgAgent.reset();
635 
636  } else {
637 
638  (void)gpgagent_transact( gpgAgent, command.constData(), item.front().error );
639 
640  KDAB_SYNCHRONIZED( m_mutex )
641  // splice 'item' into m_finishedTransactions:
642  m_finishedTransactions.splice( m_finishedTransactions.end(), item );
643 
644  emit oneTransactionFinished();
645 
646  }
647 
648  // update event counter in case anything above changed
649  // it:
650  if ( gpgAgent )
651  eventCounter = get_event_counter( gpgAgent );
652  else
653  eventCounter = -1;
654 #ifdef DEBUG_SCREADER
655  kDebug() << "eventCounter:" << eventCounter;
656 #endif
657 
658  }
659  }
660 
661  private:
662  mutable QMutex m_mutex;
663  QWaitCondition m_waitForTransactions;
664  const QString m_gnupgHomePath;
665  std::vector<QByteArray> readerStatusFileContents;
666  // protected by m_mutex:
667  std::vector<CardInfo> m_cardInfos;
668  std::list<Transaction> m_transactions, m_finishedTransactions;
669  };
670 
671 }
672 
673 class ReaderStatus::Private : ReaderStatusThread {
674  friend class Kleo::SmartCard::ReaderStatus;
675  ReaderStatus * const q;
676 public:
677  explicit Private( ReaderStatus * qq )
678  : ReaderStatusThread( qq ),
679  q( qq ),
680  watcher()
681  {
682  KDAB_SET_OBJECT_NAME( watcher );
683 
684  qRegisterMetaType<Status>( "Kleo::SmartCard::ReaderStatus::Status" );
685 
686  watcher.whitelistFiles( QStringList( QLatin1String( "reader_*.status" ) ) );
687  watcher.addPath( Kleo::gnupgHomeDirectory() );
688  watcher.setDelay( 100 );
689 
690  connect( this, SIGNAL(cardStatusChanged(uint,Kleo::SmartCard::ReaderStatus::Status)),
691  q, SIGNAL(cardStatusChanged(uint,Kleo::SmartCard::ReaderStatus::Status)) );
692  connect( this, SIGNAL(anyCardHasNullPinChanged(bool)),
693  q, SIGNAL(anyCardHasNullPinChanged(bool)) );
694  connect( this, SIGNAL(anyCardCanLearnKeysChanged(bool)),
695  q, SIGNAL(anyCardCanLearnKeysChanged(bool)) );
696 
697  connect( &watcher, SIGNAL(triggered()), this, SLOT(slotReaderStatusFileChanged()) );
698 
699  }
700  ~Private() {
701  stop();
702  if ( !wait( 100 ) ) {
703  terminate();
704  wait();
705  }
706  }
707 
708 private:
709  bool anyCardHasNullPinImpl() const {
710  return kdtools::any( cardInfos(), boost::bind( &CardInfo::status, _1 ) == CardHasNullPin );
711  }
712 
713  bool anyCardCanLearnKeysImpl() const {
714  return kdtools::any( cardInfos(), boost::bind( &CardInfo::status, _1 ) == CardCanLearnKeys );
715  }
716 
717 private:
718  FileSystemWatcher watcher;
719 };
720 
721 
722 ReaderStatus::ReaderStatus( QObject * parent )
723  : QObject( parent ), d( new Private( this ) )
724 {
725  self = this;
726 }
727 
728 ReaderStatus::~ReaderStatus() { self = 0; }
729 
730 // slot
731 void ReaderStatus::startMonitoring() {
732  d->start();
733 }
734 
735 // static
736 ReaderStatus * ReaderStatus::mutableInstance() {
737  return self;
738 }
739 
740 // static
741 const ReaderStatus * ReaderStatus::instance() {
742  return self;
743 }
744 
745 ReaderStatus::Status ReaderStatus::cardStatus( unsigned int slot ) const {
746  return d->cardStatus( slot );
747 }
748 
749 bool ReaderStatus::anyCardHasNullPin() const {
750  return d->anyCardHasNullPinImpl();
751 }
752 
753 bool ReaderStatus::anyCardCanLearnKeys() const {
754  return d->anyCardCanLearnKeysImpl();
755 }
756 
757 std::vector<ReaderStatus::PinState> ReaderStatus::pinStates( unsigned int slot ) const {
758  const std::vector<CardInfo> ci = d->cardInfos();
759  if ( slot < ci.size() )
760  return ci[slot].pinStates;
761  else
762  return std::vector<PinState>();
763 }
764 
765 void ReaderStatus::startSimpleTransaction( const QByteArray & command, QObject * receiver, const char * slot ) {
766  const Transaction t = { command, receiver, slot, Error() };
767  d->addTransaction( t );
768 }
769 
770 void ReaderStatus::updateStatus() {
771  d->ping();
772 }
773 
774 #include "moc_readerstatus.cpp"
775 #include "readerstatus.moc"
parse_event_counter
static unsigned int parse_event_counter(const std::string &str)
Definition: readerstatus.cpp:265
flags
static const char * flags[]
Definition: readerstatus.cpp:115
Kleo::SmartCard::ReaderStatus::_NumScdStates
Definition: readerstatus.h:84
Kleo::SmartCard::ReaderStatus::CardError
Definition: readerstatus.h:89
Kleo::SmartCard::ReaderStatus::updateStatus
void updateStatus()
Definition: readerstatus.cpp:770
updateTransaction
static const Transaction updateTransaction
Definition: readerstatus.cpp:431
Kleo::SmartCard::ReaderStatus::CardUsable
Definition: readerstatus.h:82
Kleo::SmartCard::ReaderStatus::NumStates
Definition: readerstatus.h:91
Kleo::SmartCard::ReaderStatus::mutableInstance
static ReaderStatus * mutableInstance()
Definition: readerstatus.cpp:736
Kleo::SmartCard::ReaderStatus::anyCardCanLearnKeysChanged
void anyCardCanLearnKeysChanged(bool)
Kleo::gnupgHomeDirectory
QString gnupgHomeDirectory()
Definition: gnupg-helper.cpp:56
Kleo::SmartCard::ReaderStatus::UnknownApplication
Definition: readerstatus.h:58
app_types
static const char * app_types[]
Definition: readerstatus.cpp:183
Kleo::SmartCard::ReaderStatus::startMonitoring
void startMonitoring()
Definition: readerstatus.cpp:731
check_event_counter_changed
static bool check_event_counter_changed(shared_ptr< Context > &gpg_agent, unsigned int &counter)
Definition: readerstatus.cpp:410
parseFileName
static unsigned int parseFileName(const QString &fileName, bool *ok)
Definition: readerstatus.cpp:147
Kleo::SmartCard::ReaderStatus::NoPin
Definition: readerstatus.h:72
Kleo::SmartCard::ReaderStatus::PinBlocked
Definition: readerstatus.h:71
Kleo::SmartCard::ReaderStatus::AppType
AppType
Definition: readerstatus.h:57
readerstatus.h
Kleo::SmartCard::ReaderStatus::NullPin
Definition: readerstatus.h:70
Kleo::SmartCard::ReaderStatus::ReaderStatus
ReaderStatus(QObject *parent=0)
Definition: readerstatus.cpp:722
parse_keypairinfo
static std::string parse_keypairinfo(const std::string &kpi)
Definition: readerstatus.cpp:297
kdsignalblocker.h
Kleo::SmartCard::ReaderStatus::NumAppTypes
Definition: readerstatus.h:65
status
VerifyChecksumsDialog::Status status
Definition: verifychecksumscontroller.cpp:512
boost::shared_ptr
Definition: encryptemailcontroller.h:51
gpgagent_transact
static std::auto_ptr< DefaultAssuanTransaction > gpgagent_transact(shared_ptr< Context > &gpgAgent, const char *command, Error &err)
Definition: readerstatus.cpp:229
KDAB_SYNCHRONIZED
#define KDAB_SYNCHRONIZED(mutex)
Definition: kdtoolsglobal.h:68
d
#define d
Definition: adduseridcommand.cpp:90
scd_getattr_status
static const std::string scd_getattr_status(shared_ptr< Context > &gpgAgent, const char *what, Error &err)
Definition: readerstatus.cpp:252
Kleo::SmartCard::ReaderStatus::anyCardCanLearnKeys
bool anyCardCanLearnKeys() const
Definition: readerstatus.cpp:753
parse_keypairinfo_and_lookup_key
static bool parse_keypairinfo_and_lookup_key(Context *ctx, const std::string &kpi)
Definition: readerstatus.cpp:302
TRACE
#define TRACE(x)
Definition: readerstatus.cpp:172
Kleo::FileSystemWatcher
Definition: filesystemwatcher.h:45
Kleo::SmartCard::ReaderStatus::startSimpleTransaction
void startSimpleTransaction(const QByteArray &cmd, QObject *receiver, const char *slot)
Definition: readerstatus.cpp:765
Kleo::SmartCard::ReaderStatus::Status
Status
Definition: readerstatus.h:78
parse_app_type
static ReaderStatus::AppType parse_app_type(const std::string &s)
Definition: readerstatus.cpp:194
KDAB_SET_OBJECT_NAME
#define KDAB_SET_OBJECT_NAME(x)
Definition: kdtoolsglobal.h:66
Kleo::Class::CMS
Definition: classify.h:48
Kleo::SmartCard::ReaderStatus::cardStatus
Status cardStatus(unsigned int slot) const
Definition: readerstatus.cpp:745
read_file
static QByteArray read_file(const QString &fileName)
Definition: readerstatus.cpp:134
Kleo::SmartCard::ReaderStatus::instance
static const ReaderStatus * instance()
Definition: readerstatus.cpp:741
Kleo::SmartCard::ReaderStatus::CardHasNullPin
Definition: readerstatus.h:87
gnupg-helper.h
RETRY_WAIT
static const unsigned int RETRY_WAIT
Definition: readerstatus.cpp:84
BOOST_STATIC_ASSERT
BOOST_STATIC_ASSERT((sizeof flags/sizeof *flags==ReaderStatus::_NumScdStates))
string
const char * string
Definition: verifychecksumscontroller.cpp:511
gpgagent_data
static const std::string gpgagent_data(shared_ptr< Context > &gpgAgent, const char *what, Error &err)
Definition: readerstatus.cpp:289
parse_app_version
static int parse_app_version(const std::string &s)
Definition: readerstatus.cpp:211
Kleo::SmartCard::ReaderStatus
Definition: readerstatus.h:46
Kleo::SmartCard::ReaderStatus::anyCardHasNullPin
bool anyCardHasNullPin() const
Definition: readerstatus.cpp:749
CHECK_INTERVAL
static const unsigned int CHECK_INTERVAL
Definition: readerstatus.cpp:85
Kleo::SmartCard::ReaderStatus::CardCanLearnKeys
Definition: readerstatus.h:86
filesystemwatcher.h
q
#define q
Definition: adduseridcommand.cpp:91
Kleo::SmartCard::ReaderStatus::~ReaderStatus
~ReaderStatus()
Definition: readerstatus.cpp:728
parse_pin_state
static ReaderStatus::PinState parse_pin_state(const std::string &s)
Definition: readerstatus.cpp:215
Kleo::SmartCard::ReaderStatus::PinState
PinState
Definition: readerstatus.h:68
Kleo::SmartCard::ReaderStatus::NoCard
Definition: readerstatus.h:79
checkTransaction
static const Transaction checkTransaction
Definition: readerstatus.cpp:430
Kleo::SmartCard::ReaderStatus::anyCardHasNullPinChanged
void anyCardHasNullPinChanged(bool)
prettyFlags
static const char * prettyFlags[]
Definition: readerstatus.cpp:123
Kleo::SmartCard::ReaderStatus::PinOk
Definition: readerstatus.h:73
get_card_status
static CardInfo get_card_status(const QString &fileName, unsigned int idx, shared_ptr< Context > &gpg_agent)
Definition: readerstatus.cpp:318
quitTransaction
static const Transaction quitTransaction
Definition: readerstatus.cpp:432
Kleo::SmartCard::ReaderStatus::cardStatusChanged
void cardStatusChanged(unsigned int slot, Kleo::SmartCard::ReaderStatus::Status status)
update_cardinfo
static std::vector< CardInfo > update_cardinfo(const QString &gnupgHomePath, shared_ptr< Context > &gpgAgent)
Definition: readerstatus.cpp:395
Kleo::SmartCard::ReaderStatus::NksApplication
Definition: readerstatus.h:60
slot
const char * slot
Definition: keytreeview.cpp:360
Kleo::SmartCard::ReaderStatus::pinStates
std::vector< PinState > pinStates(unsigned int slot) const
Definition: readerstatus.cpp:757
Kleo::SmartCard::ReaderStatus::UnknownPinState
Definition: readerstatus.h:69
get_event_counter
static unsigned int get_event_counter(shared_ptr< Context > &gpgAgent)
Definition: readerstatus.cpp:272
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:56:41 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