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