• 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
assuanserverconnection.cpp
Go to the documentation of this file.
1 /* -*- mode: c++; c-basic-offset:4 -*-
2  uiserver/assuanserverconnection.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 #ifndef QT_NO_CAST_TO_ASCII
33 # define QT_NO_CAST_TO_ASCII
34 #endif
35 #ifndef QT_NO_CAST_FROM_ASCII
36 # define QT_NO_CAST_FROM_ASCII
37 #endif
38 
39 #include <config-kleopatra.h>
40 #include <version-kleopatra.h>
41 
42 #include "assuanserverconnection.h"
43 #include "assuancommand.h"
44 #include "sessiondata.h"
45 
46 #include <models/keycache.h> // :(
47 
48 #include <utils/input.h>
49 #include <utils/output.h>
50 #include <utils/gnupg-helper.h>
51 #include <utils/detail_p.h>
52 #include <utils/hex.h>
53 #include <utils/log.h>
54 #include <utils/kleo_assert.h>
55 #include <utils/getpid.h>
56 
57 #include <kleo/stl_util.h>
58 #include <kleo/exception.h>
59 
60 #include <gpgme++/data.h>
61 #include <gpgme++/key.h>
62 
63 #include <kmime/kmime_header_parsing.h>
64 
65 #include <KDebug>
66 #include <KLocalizedString>
67 #include <KWindowSystem>
68 
69 #include <QSocketNotifier>
70 #include <QTimer>
71 #include <QVariant>
72 #include <QPointer>
73 #include <QFileInfo>
74 #include <QStringList>
75 #include <QRegExp>
76 #include <QWidget>
77 
78 #include <kleo-assuan.h>
79 
80 #ifndef Q_MOC_RUN // QTBUG-22829
81 #include <boost/type_traits/remove_pointer.hpp>
82 #include <boost/lexical_cast.hpp>
83 #include <boost/bind.hpp>
84 #include <boost/mem_fn.hpp>
85 #include <boost/mpl/if.hpp>
86 #endif
87 
88 #include <vector>
89 #include <map>
90 #include <string>
91 #include <memory>
92 #include <algorithm>
93 
94 #include <errno.h>
95 
96 #ifdef __GLIBCXX__
97 # include <ext/algorithm> // for is_sorted
98 #endif
99 
100 #ifdef Q_OS_WIN32
101 # include <io.h>
102 # include <process.h>
103 #else
104 # include <sys/types.h>
105 # include <unistd.h>
106 #endif
107 
108 #ifdef Q_WS_X11
109 # include <qx11info_x11.h>
110 # include <X11/Xlib.h>
111 #endif
112 
113 using namespace Kleo;
114 using namespace boost;
115 
116 static const unsigned int INIT_SOCKET_FLAGS = 3; // says info assuan...
117 //static int(*USE_DEFAULT_HANDLER)(assuan_context_t,char*) = 0;
118 static const int FOR_READING = 0;
119 static const unsigned int MAX_ACTIVE_FDS = 32;
120 
121 #ifdef HAVE_ASSUAN2
122 static void my_assuan_release( assuan_context_t ctx ) {
123  if ( ctx )
124  assuan_release( ctx );
125 }
126 
127 #endif
128 // shared_ptr for assuan_context_t w/ deleter enforced to assuan_deinit_server:
129 typedef shared_ptr< remove_pointer<assuan_context_t>::type > AssuanContextBase;
130 struct AssuanContext : AssuanContextBase {
131  AssuanContext() : AssuanContextBase() {}
132 #ifndef HAVE_ASSUAN2
133  explicit AssuanContext( assuan_context_t ctx ) : AssuanContextBase( ctx, &assuan_deinit_server ) {}
134 #else
135  explicit AssuanContext( assuan_context_t ctx ) : AssuanContextBase( ctx, &my_assuan_release ) {}
136 #endif
137 
138 #ifndef HAVE_ASSUAN2
139  void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &assuan_deinit_server ); }
140 #else
141  void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &my_assuan_release ); }
142 #endif
143 };
144 
145 static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const char * err_msg ) {
146  return assuan_process_done( ctx, assuan_set_error( ctx, err, err_msg ) );
147 }
148 
149 static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const std::string & err_msg ) {
150  return assuan_process_done_msg( ctx, err, err_msg.c_str() );
151 }
152 
153 static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const QString & err_msg ) {
154  return assuan_process_done_msg( ctx, err, err_msg.toUtf8().constData() );
155 }
156 
157 static std::map<std::string,std::string> upcase_option( const char * option, std::map<std::string,std::string> options ) {
158  std::string value;
159  bool value_found = false;
160  std::map<std::string,std::string>::iterator it = options.begin();
161  while ( it != options.end() )
162  if ( qstricmp( it->first.c_str(), option ) == 0 ) {
163  value = it->second;
164  options.erase( it++ );
165  value_found = true;
166  } else {
167  ++it;
168  }
169  if ( value_found )
170  options[option] = value;
171  return options;
172 }
173 
174 static std::map<std::string,std::string> parse_commandline( const char * line ) {
175  std::map<std::string,std::string> result;
176  if ( line ) {
177  const char * begin = line;
178  const char * lastEQ = 0;
179  while ( *line ) {
180  if ( *line == ' ' || *line == '\t' ) {
181  if ( begin != line ) {
182  if ( begin[0] == '-' && begin[1] == '-' )
183  begin += 2; // skip initial "--"
184  if ( lastEQ && lastEQ > begin )
185  result[ std::string( begin, lastEQ - begin ) ] = hexdecode( std::string( lastEQ+1, line - (lastEQ+1) ) );
186  else
187  result[ std::string( begin, line - begin ) ] = std::string();
188  }
189  begin = line + 1;
190  } else if ( *line == '=' ) {
191  if ( line == begin )
192  throw Exception( gpg_error( GPG_ERR_ASS_SYNTAX ),
193  i18n("No option name given") );
194  else
195  lastEQ = line;
196  }
197  ++line;
198  }
199  if ( begin != line ) {
200  if ( begin[0] == '-' && begin[1] == '-' )
201  begin += 2; // skip initial "--"
202  if ( lastEQ && lastEQ > begin )
203  result[ std::string( begin, lastEQ - begin ) ] = hexdecode( std::string( lastEQ+1, line - (lastEQ+1 ) ) );
204  else
205  result[ begin ] = std::string();
206  }
207  }
208 
209  return result;
210 }
211 
212 static WId wid_from_string( const QString & winIdStr, bool * ok=0 ) {
213  return
214 #if defined(Q_OS_WIN32)
215  reinterpret_cast<WId>
216 #else
217  static_cast<WId>
218 #endif
219  ( winIdStr.toULongLong( ok, 16 ) );
220 }
221 
222 static void apply_window_id( QWidget * widget, const QString & winIdStr ) {
223  if ( !widget || winIdStr.isEmpty() )
224  return;
225  bool ok = false;
226  const WId wid = wid_from_string( winIdStr, &ok );
227  if ( !ok ) {
228  kDebug() << "window-id value" << wid << "doesn't look like a number";
229  return;
230  }
231  if ( QWidget * pw = QWidget::find( wid ) )
232  widget->setParent( pw, widget->windowFlags() );
233  else {
234  KWindowSystem::setMainWindow( widget, wid );
235  }
236 }
237 
238 //
239 //
240 // AssuanServerConnection:
241 //
242 //
243 
244 class AssuanServerConnection::Private : public QObject {
245  Q_OBJECT
246  friend class ::Kleo::AssuanServerConnection;
247  friend class ::Kleo::AssuanCommandFactory;
248  friend class ::Kleo::AssuanCommand;
249  AssuanServerConnection * const q;
250 public:
251  Private( assuan_fd_t fd_, const std::vector< shared_ptr<AssuanCommandFactory> > & factories_, AssuanServerConnection * qq );
252  ~Private();
253 
254 Q_SIGNALS:
255  void startKeyManager();
256 
257 public Q_SLOTS:
258  void slotReadActivity( int ) {
259  assert( ctx );
260 #ifndef HAVE_ASSUAN2
261  if ( const int err = assuan_process_next( ctx.get() ) ) {
262 #else
263  int done = false;
264  if ( const int err = assuan_process_next( ctx.get(), &done ) || done ) {
265 #endif
266  //if ( err == -1 || gpg_err_code(err) == GPG_ERR_EOF ) {
267  topHalfDeletion();
268  if ( nohupedCommands.empty() )
269  bottomHalfDeletion();
270  //} else {
271  //assuan_process_done( ctx.get(), err );
272  //return;
273  //}
274  }
275  }
276 
277  int startCommandBottomHalf();
278 
279 private:
280  void nohupDone( AssuanCommand * cmd ) {
281  const std::vector< shared_ptr<AssuanCommand> >::iterator it
282  = std::find_if( nohupedCommands.begin(), nohupedCommands.end(),
283  boost::bind( &shared_ptr<AssuanCommand>::get, _1 ) == cmd );
284  assert( it != nohupedCommands.end() );
285  nohupedCommands.erase( it );
286  if ( nohupedCommands.empty() && closed )
287  bottomHalfDeletion();
288  }
289 
290  void commandDone( AssuanCommand * cmd ) {
291  if ( !cmd || cmd != currentCommand.get() )
292  return;
293  currentCommand.reset();
294  }
295 
296  void topHalfDeletion() {
297  if ( currentCommand )
298  currentCommand->canceled();
299  if ( fd != ASSUAN_INVALID_FD ) {
300 #if defined(Q_OS_WIN32)
301  CloseHandle( fd );
302 #else
303  ::close( fd );
304 #endif
305  }
306  notifiers.clear();
307  closed = true;
308  }
309 
310  void bottomHalfDeletion() {
311  if ( sessionId )
312  SessionDataHandler::instance()->exitSession( sessionId );
313  cleanup();
314  const QPointer<Private> that = this;
315  emit q->closed( q );
316  if ( that ) // still there
317  q->deleteLater();
318  }
319 
320 private:
321 #ifndef HAVE_ASSUAN2
322  static void reset_handler( assuan_context_t ctx_ ) {
323 #else
324  static gpg_error_t reset_handler( assuan_context_t ctx_, char * ) {
325 #endif
326  assert( assuan_get_pointer( ctx_ ) );
327 
328  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
329 
330  conn.reset();
331 #ifdef HAVE_ASSUAN2
332 
333  return 0;
334 #endif
335  }
336 
337 #ifndef HAVE_ASSUAN2
338  static int option_handler( assuan_context_t ctx_, const char * key, const char * value ) {
339 #else
340  static gpg_error_t option_handler( assuan_context_t ctx_, const char * key, const char * value ) {
341 #endif
342  assert( assuan_get_pointer( ctx_ ) );
343 
344  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
345 
346  if ( key && key[0] == '-' && key[1] == '-' )
347  key += 2; // skip "--"
348  conn.options[key] = QString::fromUtf8( value );
349 
350  return 0;
351  //return gpg_error( GPG_ERR_UNKNOWN_OPTION );
352  }
353 
354 #ifndef HAVE_ASSUAN2
355  static int session_handler( assuan_context_t ctx_, char * line ) {
356 #else
357  static gpg_error_t session_handler( assuan_context_t ctx_, char * line ) {
358 #endif
359  assert( assuan_get_pointer( ctx_ ) );
360  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
361 
362  const QString str = QString::fromUtf8( line );
363  QRegExp rx( QLatin1String( "(\\d+)(?:\\s+(.*))?" ) );
364  if ( !rx.exactMatch( str ) ) {
365  static const QString errorString = i18n("Parse error");
366  return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_SYNTAX ), errorString );
367  }
368  bool ok = false;
369  if ( const qulonglong id = rx.cap( 1 ).toULongLong( &ok ) ) {
370  if ( ok && id <= std::numeric_limits<unsigned int>::max() ) {
371  SessionDataHandler::instance()->enterSession( id );
372  conn.sessionId = id;
373  } else {
374  static const QString errorString = i18n("Parse error: numeric session id too large");
375  return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_SYNTAX ), errorString );
376  }
377  }
378  if ( !rx.cap( 2 ).isEmpty() )
379  conn.sessionTitle = rx.cap( 2 );
380  kDebug() << "session_handler: "
381  << "id=" << static_cast<unsigned long>( conn.sessionId )
382  << ", title=" << qPrintable( conn.sessionTitle );
383  return assuan_process_done( ctx_, 0 );
384  }
385 
386 #ifndef HAVE_ASSUAN2
387  static int capabilities_handler( assuan_context_t ctx_, char * line ) {
388 #else
389  static gpg_error_t capabilities_handler( assuan_context_t ctx_, char * line ) {
390 #endif
391  if ( !QByteArray( line ).trimmed().isEmpty() ) {
392  static const QString errorString = i18n("CAPABILITIES does not take arguments");
393  return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
394  }
395  static const char capabilities[] =
396  "SENDER=info\n"
397  "RECIPIENT=info\n"
398  "SESSION\n"
399  ;
400  return assuan_process_done( ctx_, assuan_send_data( ctx_, capabilities, sizeof capabilities - 1 ) );
401  }
402 
403 #ifndef HAVE_ASSUAN2
404  static int getinfo_handler( assuan_context_t ctx_, char * line ) {
405 #else
406  static gpg_error_t getinfo_handler( assuan_context_t ctx_, char * line ) {
407 #endif
408  assert( assuan_get_pointer( ctx_ ) );
409  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
410 
411  if ( qstrcmp( line, "version" ) == 0 ) {
412  static const char version[] = "Kleopatra " KLEOPATRA_VERSION_STRING ;
413  return assuan_process_done( ctx_, assuan_send_data( ctx_, version, sizeof version - 1 ) );
414  }
415 
416  QByteArray ba;
417  if ( qstrcmp( line, "pid" ) == 0 )
418  ba = QByteArray::number( mygetpid() );
419  else if ( qstrcmp( line, "options" ) == 0 )
420  ba = conn.dumpOptions();
421  else if ( qstrcmp( line, "x-mementos" ) == 0 )
422  ba = conn.dumpMementos();
423  else if ( qstrcmp( line, "senders" ) == 0 )
424  ba = conn.dumpSenders();
425  else if ( qstrcmp( line, "recipients" ) == 0 )
426  ba = conn.dumpRecipients();
427  else if ( qstrcmp( line, "x-files" ) == 0 )
428  ba = conn.dumpFiles();
429  else {
430  static const QString errorString = i18n("Unknown value for WHAT");
431  return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
432  }
433  return assuan_process_done( ctx_, assuan_send_data( ctx_, ba.constData(), ba.size() ) );
434  }
435 
436 #ifndef HAVE_ASSUAN2
437  static int start_keymanager_handler( assuan_context_t ctx_, char * line ) {
438 #else
439  static gpg_error_t start_keymanager_handler( assuan_context_t ctx_, char * line ) {
440 #endif
441  assert( assuan_get_pointer( ctx_ ) );
442  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
443 
444  if ( line && *line ) {
445  static const QString errorString = i18n("START_KEYMANAGER does not take arguments");
446  return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
447  }
448 
449  emit conn.q->startKeyManagerRequested();
450 
451  return assuan_process_done( ctx_, 0 );
452  }
453 
454 #ifndef HAVE_ASSUAN2
455  static int start_confdialog_handler( assuan_context_t ctx_, char * line ) {
456 #else
457  static gpg_error_t start_confdialog_handler( assuan_context_t ctx_, char * line ) {
458 #endif
459  assert( assuan_get_pointer( ctx_ ) );
460  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
461 
462  if ( line && *line ) {
463  static const QString errorString = i18n("START_CONFDIALOG does not take arguments");
464  return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
465  }
466 
467  emit conn.q->startConfigDialogRequested();
468 
469  return assuan_process_done( ctx_, 0 );
470  }
471 
472  template <bool in> struct Input_or_Output : mpl::if_c<in,Input,Output> {};
473 
474  // format: TAG (FD|FD=\d+|FILE=...)
475  template <bool in, typename T_memptr>
476 #ifndef HAVE_ASSUAN2
477  static int IO_handler( assuan_context_t ctx_, char * line_, T_memptr which ) {
478 #else
479  static gpg_error_t IO_handler( assuan_context_t ctx_, char * line_, T_memptr which ) {
480 #endif
481  assert( assuan_get_pointer( ctx_ ) );
482  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
483 
484  char *binOpt = strstr ( line_, "--binary" );
485 
486  if ( binOpt && !in ) {
487  /* Note there is also --armor and --base64 allowed but we don't need
488  * to parse those because they are default.
489  * We remove it here so that it is not parsed as an Option.*/
490  memset (binOpt, ' ', 8 );
491  }
492 
493  try {
494 
495  /*const*/ std::map<std::string,std::string> options = upcase_option( "FD", upcase_option( "FILE", parse_commandline( line_ ) ) );
496  if ( options.size() < 1 || options.size() > 2 )
497  throw gpg_error( GPG_ERR_ASS_SYNTAX );
498 
499  shared_ptr< typename Input_or_Output<in>::type > io;
500 
501  if ( options.count( "FD" ) ) {
502 
503  if ( options.count( "FILE" ) )
504  throw gpg_error( GPG_ERR_CONFLICT );
505 
506  assuan_fd_t fd = ASSUAN_INVALID_FD;
507 
508  const std::string fdstr = options["FD"];
509 
510  if ( fdstr.empty() ) {
511  if ( const gpg_error_t err = assuan_receivefd( conn.ctx.get(), &fd ) )
512  throw err;
513  } else {
514 #if defined(Q_OS_WIN32)
515  fd = (assuan_fd_t)lexical_cast<intptr_t>( fdstr );
516 #else
517  fd = lexical_cast<assuan_fd_t>( fdstr );
518 #endif
519  }
520 
521  io = Input_or_Output<in>::type::createFromPipeDevice( fd, in ? i18n( "Message #%1", (conn.*which).size() + 1 ) : QString() );
522 
523  options.erase( "FD" );
524 
525  } else if ( options.count( "FILE" ) ) {
526 
527  if ( options.count( "FD" ) )
528  throw gpg_error( GPG_ERR_CONFLICT );
529 
530  const QString filePath = QFile::decodeName( options["FILE"].c_str() );
531  if ( filePath.isEmpty() )
532  throw Exception( gpg_error( GPG_ERR_ASS_SYNTAX ), i18n("Empty file path") );
533  const QFileInfo fi( filePath );
534  if ( !fi.isAbsolute() )
535  throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only absolute file paths are allowed") );
536  if ( !fi.isFile() )
537  throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only files are allowed in INPUT/OUTPUT FILE") );
538  else
539  io = Input_or_Output<in>::type::createFromFile( fi.absoluteFilePath(), true );
540 
541  options.erase( "FILE" );
542 
543  } else {
544 
545  throw gpg_error( GPG_ERR_ASS_PARAMETER );
546 
547  }
548 
549  if ( options.size() )
550  throw gpg_error( GPG_ERR_UNKNOWN_OPTION );
551 
552  (conn.*which).push_back( io );
553 
554  if ( binOpt && !in ) {
555  Output* out = reinterpret_cast <Output*>( io.get() );
556  out->setBinaryOpt( true );
557  kDebug() << "Configured output for binary data";
558  }
559 
560  kDebug() << "AssuanServerConnection: added" << io->label();
561 
562  return assuan_process_done( conn.ctx.get(), 0 );
563  } catch ( const GpgME::Exception & e ) {
564  return assuan_process_done_msg( conn.ctx.get(), e.error().encodedError(), e.message().c_str() );
565  } catch ( const std::exception & ) {
566  return assuan_process_done( conn.ctx.get(), gpg_error( GPG_ERR_ASS_SYNTAX ) );
567  } catch ( const gpg_error_t e ) {
568  return assuan_process_done( conn.ctx.get(), e );
569  } catch ( ... ) {
570  return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), "unknown exception caught" );
571  }
572 
573  }
574 
575 #ifndef HAVE_ASSUAN2
576  static int input_handler( assuan_context_t ctx, char * line ) {
577 #else
578  static gpg_error_t input_handler( assuan_context_t ctx, char * line ) {
579 #endif
580  return IO_handler<true>( ctx, line, &Private::inputs );
581  }
582 
583 #ifndef HAVE_ASSUAN2
584  static int output_handler( assuan_context_t ctx, char * line ) {
585 #else
586  static gpg_error_t output_handler( assuan_context_t ctx, char * line ) {
587 #endif
588  return IO_handler<false>( ctx, line, &Private::outputs );
589  }
590 
591 #ifndef HAVE_ASSUAN2
592  static int message_handler( assuan_context_t ctx, char * line ) {
593 #else
594  static gpg_error_t message_handler( assuan_context_t ctx, char * line ) {
595 #endif
596  return IO_handler<true>( ctx, line, &Private::messages );
597  }
598 
599 #ifndef HAVE_ASSUAN2
600  static int file_handler( assuan_context_t ctx_, char * line ) {
601 #else
602  static gpg_error_t file_handler( assuan_context_t ctx_, char * line ) {
603 #endif
604  assert( assuan_get_pointer( ctx_ ) );
605  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
606 
607  try {
608  const QFileInfo fi( QFile::decodeName( hexdecode( line ).c_str() ) );
609  if ( !fi.isAbsolute() )
610  throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only absolute file paths are allowed") );
611  if ( !fi.exists() )
612  throw gpg_error( GPG_ERR_ENOENT );
613  if ( !fi.isReadable() || ( fi.isDir() && !fi.isExecutable() ) )
614  throw gpg_error( GPG_ERR_EPERM );
615 
616  conn.files.push_back( fi.absoluteFilePath() );
617 
618  return assuan_process_done( conn.ctx.get(), 0 );
619  } catch ( const Exception & e ) {
620  return assuan_process_done_msg( conn.ctx.get(), e.error().encodedError(), e.message().toUtf8().constData() );
621  } catch ( const gpg_error_t e ) {
622  return assuan_process_done( conn.ctx.get(), e );
623  } catch ( ... ) {
624  return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("unknown exception caught").toUtf8().constData() );
625  }
626  }
627 
628  static bool parse_informative( const char * & begin, GpgME::Protocol & protocol ) {
629  protocol = GpgME::UnknownProtocol;
630  bool informative = false;
631  const char * pos = begin;
632  while ( true ) {
633  while ( *pos == ' ' || *pos == '\t' )
634  ++pos;
635  if ( qstrnicmp( pos, "--info", strlen("--info") ) == 0 ) {
636  informative = true;
637  pos += strlen("--info");
638  if ( *pos == '=' ) {
639  ++pos;
640  break;
641  }
642  } else if ( qstrnicmp( pos, "--protocol=", strlen("--protocol=") ) == 0 ) {
643  pos += strlen("--protocol=");
644  if ( qstrnicmp( pos, "OpenPGP", strlen("OpenPGP") ) == 0 ) {
645  protocol = GpgME::OpenPGP;
646  pos += strlen("OpenPGP");
647  } else if ( qstrnicmp( pos, "CMS", strlen("CMS") ) == 0 ) {
648  protocol = GpgME::CMS;
649  pos += strlen("CMS");
650  } else {
651  ;
652  }
653  } else if ( qstrncmp( pos, "-- ", strlen("-- ") ) == 0 ) {
654  pos += 3;
655  while ( *pos == ' ' || *pos == '\t' )
656  ++pos;
657  break;
658  } else
659  break;
660  }
661  begin = pos;
662  return informative;
663  }
664 
665  template <typename T_memptr, typename T_memptr2>
666 #ifndef HAVE_ASSUAN2
667  static int recipient_sender_handler( T_memptr mp, T_memptr2 info, assuan_context_t ctx, char * line, bool sender=false ) {
668 #else
669  static gpg_error_t recipient_sender_handler( T_memptr mp, T_memptr2 info, assuan_context_t ctx, char * line, bool sender=false ) {
670 #endif
671  assert( assuan_get_pointer( ctx ) );
672  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx ) );
673 
674  if ( !line || !*line )
675  return assuan_process_done( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ) );
676  const char * begin = line;
677  const char * const end = begin + qstrlen( line );
678  GpgME::Protocol proto = GpgME::UnknownProtocol;
679  const bool informative = parse_informative( begin, proto );
680  if ( !(conn.*mp).empty() && informative != (conn.*info) )
681  return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_CONFLICT ),
682  i18n("Cannot mix --info with non-info SENDER or RECIPIENT").toUtf8().constData() );
683  KMime::Types::Mailbox mb;
684  if ( !KMime::HeaderParsing::parseMailbox( begin, end, mb ) )
685  return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ),
686  i18n("Argument is not a valid RFC-2822 mailbox").toUtf8().constData() );
687  if ( begin != end )
688  return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ),
689  i18n("Garbage after valid RFC-2822 mailbox detected").toUtf8().constData() );
690  (conn.*info) = informative;
691  (conn.*mp).push_back( mb );
692 
693  const QString email = mb.addrSpec().asString();
694  (void)assuan_write_line( conn.ctx.get(), qPrintable( QString().sprintf( "# ok, parsed as \"%s\"", qPrintable( email ) ) ) );
695  if ( sender && !informative )
696  return AssuanCommandFactory::_handle( conn.ctx.get(), line, "PREP_SIGN" );
697  else
698  return assuan_process_done( ctx, 0 );
699  }
700 
701 #ifndef HAVE_ASSUAN2
702  static int recipient_handler( assuan_context_t ctx, char * line ) {
703 #else
704  static gpg_error_t recipient_handler( assuan_context_t ctx, char * line ) {
705 #endif
706  return recipient_sender_handler( &Private::recipients, &Private::informativeRecipients, ctx, line );
707  }
708 
709 #ifndef HAVE_ASSUAN2
710  static int sender_handler( assuan_context_t ctx, char * line ) {
711 #else
712  static gpg_error_t sender_handler( assuan_context_t ctx, char * line ) {
713 #endif
714  return recipient_sender_handler( &Private::senders, &Private::informativeSenders, ctx, line, true );
715  }
716 
717  QByteArray dumpOptions() const {
718  QByteArray result;
719  for ( std::map<std::string,QVariant>::const_iterator it = options.begin(), end = options.end() ; it != end ; ++it )
720  result += it->first.c_str() + it->second.toString().toUtf8() + '\n';
721  return result;
722  }
723 
724  static QByteArray dumpStringList( const QStringList & sl ) {
725  return sl.join( QLatin1String( "\n" ) ).toUtf8();
726  }
727 
728  template <typename T_container>
729  static QByteArray dumpStringList( const T_container & c ) {
730  QStringList sl;
731  std::copy( c.begin(), c.end(), std::back_inserter( sl ) );
732  return dumpStringList( sl );
733  }
734 
735  template <typename T_container>
736  static QByteArray dumpMailboxes( const T_container & c ) {
737  QStringList sl;
738  std::transform( c.begin(), c.end(),
739  std::back_inserter( sl ),
740  boost::bind( &KMime::Types::Mailbox::prettyAddress, _1 ) );
741  return dumpStringList( sl );
742  }
743 
744  QByteArray dumpSenders() const {
745  return dumpMailboxes( senders );
746  }
747 
748  QByteArray dumpRecipients() const {
749  return dumpMailboxes( recipients );
750  }
751 
752  QByteArray dumpMementos() const {
753  QByteArray result;
754  for ( std::map< QByteArray, shared_ptr<AssuanCommand::Memento> >::const_iterator it = mementos.begin(), end = mementos.end() ; it != end ; ++it ) {
755  char buf[2 + 2*sizeof(void*) + 2];
756  sprintf( buf, "0x%p\n", ( void* )it->second.get() );
757  buf[sizeof(buf)-1] = '\0';
758  result += it->first + QByteArray::fromRawData( buf, sizeof buf );
759  }
760  return result;
761  }
762 
763  QByteArray dumpFiles() const {
764  return dumpStringList( kdtools::copy<QStringList>( files ) );
765  }
766 
767  void cleanup();
768  void reset() {
769  options.clear();
770  senders.clear();
771  informativeSenders = false;
772  recipients.clear();
773  informativeRecipients = false;
774  sessionTitle.clear();
775  sessionId = 0;
776  mementos.clear();
777  files.clear();
778  std::for_each( inputs.begin(), inputs.end(),
779  boost::bind( &Input::finalize, _1 ) );
780  inputs.clear();
781  std::for_each( outputs.begin(), outputs.end(),
782  boost::bind( &Output::finalize, _1 ) );
783  outputs.clear();
784  std::for_each( messages.begin(), messages.end(),
785  boost::bind( &Input::finalize, _1 ) );
786  messages.clear();
787  bias = GpgME::UnknownProtocol;
788  }
789 
790  assuan_fd_t fd;
791  AssuanContext ctx;
792  bool closed : 1;
793  bool cryptoCommandsEnabled : 1;
794  bool commandWaitingForCryptoCommandsEnabled : 1;
795  bool currentCommandIsNohup : 1;
796  bool informativeSenders; // address taken, so no : 1
797  bool informativeRecipients; // address taken, so no : 1
798  GpgME::Protocol bias;
799  QString sessionTitle;
800  unsigned int sessionId;
801  std::vector< shared_ptr<QSocketNotifier> > notifiers;
802  std::vector< shared_ptr<AssuanCommandFactory> > factories; // sorted: _detail::ByName<std::less>
803  shared_ptr<AssuanCommand> currentCommand;
804  std::vector< shared_ptr<AssuanCommand> > nohupedCommands;
805  std::map<std::string,QVariant> options;
806  std::vector<KMime::Types::Mailbox> senders, recipients;
807  std::vector< shared_ptr<Input> > inputs, messages;
808  std::vector< shared_ptr<Output> > outputs;
809  std::vector<QString> files;
810  std::map< QByteArray, shared_ptr<AssuanCommand::Memento> > mementos;
811 };
812 
813 void AssuanServerConnection::Private::cleanup() {
814  assert( nohupedCommands.empty() );
815  reset();
816  currentCommand.reset();
817  currentCommandIsNohup = false;
818  commandWaitingForCryptoCommandsEnabled = false;
819  notifiers.clear();
820  ctx.reset();
821  fd = ASSUAN_INVALID_FD;
822 }
823 
824 AssuanServerConnection::Private::Private( assuan_fd_t fd_, const std::vector< shared_ptr<AssuanCommandFactory> > & factories_, AssuanServerConnection * qq )
825  : QObject(),
826  q( qq ),
827  fd( fd_ ),
828  closed( false ),
829  cryptoCommandsEnabled( false ),
830  commandWaitingForCryptoCommandsEnabled( false ),
831  currentCommandIsNohup( false ),
832  informativeSenders( false ),
833  informativeRecipients( false ),
834  bias( GpgME::UnknownProtocol ),
835  sessionId( 0 ),
836  factories( factories_ )
837 {
838 #ifdef __GLIBCXX__
839  assert( __gnu_cxx::is_sorted( factories_.begin(), factories_.end(), _detail::ByName<std::less>() ) );
840 #endif
841 
842  if ( fd == ASSUAN_INVALID_FD )
843  throw Exception( gpg_error( GPG_ERR_INV_ARG ), "pre-assuan_init_socket_server_ext" );
844 
845 #ifndef HAVE_ASSUAN2
846  assuan_context_t naked_ctx = 0;
847  if ( const gpg_error_t err = assuan_init_socket_server_ext( &naked_ctx, fd, INIT_SOCKET_FLAGS ) )
848 #else
849  {
850  assuan_context_t naked_ctx = 0;
851  if ( const gpg_error_t err = assuan_new( &naked_ctx ) )
852  throw Exception( err, "assuan_new" );
853  ctx.reset( naked_ctx );
854  }
855  if ( const gpg_error_t err = assuan_init_socket_server( ctx.get(), fd, INIT_SOCKET_FLAGS ) )
856 #endif
857  throw Exception( err, "assuan_init_socket_server_ext" );
858 
859 #ifndef HAVE_ASSUAN2
860  ctx.reset( naked_ctx ); naked_ctx = 0;
861 #endif
862 
863  // for callbacks, associate the context with this connection:
864  assuan_set_pointer( ctx.get(), this );
865 
866  FILE* const logFile = Log::instance()->logFile();
867  assuan_set_log_stream( ctx.get(), logFile ? logFile : stderr );
868 
869  // register FDs with the event loop:
870  assuan_fd_t fds[MAX_ACTIVE_FDS];
871  const int numFDs = assuan_get_active_fds( ctx.get(), FOR_READING, fds, MAX_ACTIVE_FDS );
872  assert( numFDs != -1 ); // == 1
873 
874  if ( !numFDs || fds[0] != fd ) {
875  const shared_ptr<QSocketNotifier> sn( new QSocketNotifier( (intptr_t)fd, QSocketNotifier::Read ), mem_fn( &QObject::deleteLater ) );
876  connect( sn.get(), SIGNAL(activated(int)), this, SLOT(slotReadActivity(int)) );
877  notifiers.push_back( sn );
878  }
879 
880  notifiers.reserve( notifiers.size() + numFDs );
881  for ( int i = 0 ; i < numFDs ; ++i ) {
882  const shared_ptr<QSocketNotifier> sn( new QSocketNotifier( (intptr_t)fds[i], QSocketNotifier::Read ), mem_fn( &QObject::deleteLater ) );
883  connect( sn.get(), SIGNAL(activated(int)), this, SLOT(slotReadActivity(int)) );
884  notifiers.push_back( sn );
885  }
886 
887 
888  // register our INPUT/OUTPUT/MESSGAE/FILE handlers:
889 #ifndef HAVE_ASSUAN2
890  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "INPUT", input_handler ) )
891 #else
892  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "INPUT", input_handler, "" ) )
893 #endif
894  throw Exception( err, "register \"INPUT\" handler" );
895 #ifndef HAVE_ASSUAN2
896  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "MESSAGE", message_handler ) )
897 #else
898  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "MESSAGE", message_handler, "" ) )
899 #endif
900  throw Exception( err, "register \"MESSAGE\" handler" );
901 #ifndef HAVE_ASSUAN2
902  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "OUTPUT", output_handler ) )
903 #else
904  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "OUTPUT", output_handler, "" ) )
905 #endif
906  throw Exception( err, "register \"OUTPUT\" handler" );
907 #ifndef HAVE_ASSUAN2
908  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "FILE", file_handler ) )
909 #else
910  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "FILE", file_handler, "" ) )
911 #endif
912  throw Exception( err, "register \"FILE\" handler" );
913 
914 
915  // register user-defined commands:
916  Q_FOREACH( shared_ptr<AssuanCommandFactory> fac, factories )
917 #ifndef HAVE_ASSUAN2
918  if ( const gpg_error_t err = assuan_register_command( ctx.get(), fac->name(), fac->_handler() ) )
919 #else
920  if ( const gpg_error_t err = assuan_register_command( ctx.get(), fac->name(), fac->_handler(), "" ) )
921 #endif
922  throw Exception( err, std::string( "register \"" ) + fac->name() + "\" handler" );
923 
924 #ifndef HAVE_ASSUAN2
925  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "GETINFO", getinfo_handler ) )
926 #else
927  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "GETINFO", getinfo_handler, "" ) )
928 #endif
929  throw Exception( err, "register \"GETINFO\" handler" );
930 #ifndef HAVE_ASSUAN2
931  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_KEYMANAGER", start_keymanager_handler ) )
932 #else
933  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_KEYMANAGER", start_keymanager_handler, "" ) )
934 #endif
935  throw Exception( err, "register \"START_KEYMANAGER\" handler" );
936 #ifndef HAVE_ASSUAN2
937  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_CONFDIALOG", start_confdialog_handler ) )
938 #else
939  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_CONFDIALOG", start_confdialog_handler, "" ) )
940 #endif
941  throw Exception( err, "register \"START_CONFDIALOG\" handler" );
942 #ifndef HAVE_ASSUAN2
943  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "RECIPIENT", recipient_handler ) )
944 #else
945  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "RECIPIENT", recipient_handler, "" ) )
946 #endif
947  throw Exception( err, "register \"RECIPIENT\" handler" );
948 #ifndef HAVE_ASSUAN2
949  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SENDER", sender_handler ) )
950 #else
951  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SENDER", sender_handler, "" ) )
952 #endif
953  throw Exception( err, "register \"SENDER\" handler" );
954 #ifndef HAVE_ASSUAN2
955  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SESSION", session_handler ) )
956 #else
957  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SESSION", session_handler, "" ) )
958 #endif
959  throw Exception( err, "register \"SESSION\" handler" );
960 #ifndef HAVE_ASSUAN2
961  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "CAPABILITIES", capabilities_handler ) )
962 #else
963  if ( const gpg_error_t err = assuan_register_command( ctx.get(), "CAPABILITIES", capabilities_handler, "" ) )
964 #endif
965  throw Exception( err, "register \"CAPABILITIES\" handler" );
966 
967  assuan_set_hello_line( ctx.get(), "GPG UI server (Kleopatra/" KLEOPATRA_VERSION_STRING ") ready to serve" );
968  //assuan_set_hello_line( ctx.get(), GPG UI server (qApp->applicationName() + " v" + kapp->applicationVersion() + "ready to serve" )
969 
970 
971  // some notifiers we're interested in:
972  if ( const gpg_error_t err = assuan_register_reset_notify( ctx.get(), reset_handler ) )
973  throw Exception( err, "register reset notify" );
974  if ( const gpg_error_t err = assuan_register_option_handler( ctx.get(), option_handler ) )
975  throw Exception( err, "register option handler" );
976 
977  // and last, we need to call assuan_accept, which doesn't block
978  // (d/t INIT_SOCKET_FLAGS), but performs vital connection
979  // establishing handling:
980  if ( const gpg_error_t err = assuan_accept( ctx.get() ) )
981  throw Exception( err, "assuan_accept" );
982 }
983 
984 AssuanServerConnection::Private::~Private() {
985  cleanup();
986 }
987 
988 AssuanServerConnection::AssuanServerConnection( assuan_fd_t fd, const std::vector< shared_ptr<AssuanCommandFactory> > & factories, QObject * p )
989  : QObject( p ), d( new Private( fd, factories, this ) )
990 {
991 
992 }
993 
994 AssuanServerConnection::~AssuanServerConnection() {}
995 
996 void AssuanServerConnection::enableCryptoCommands( bool on ) {
997  if ( on == d->cryptoCommandsEnabled )
998  return;
999  d->cryptoCommandsEnabled = on;
1000  if ( d->commandWaitingForCryptoCommandsEnabled )
1001  QTimer::singleShot( 0, d.get(), SLOT(startCommandBottomHalf()) );
1002 }
1003 
1004 
1005 //
1006 //
1007 // AssuanCommand:
1008 //
1009 //
1010 
1011 namespace Kleo {
1012 
1013 class InquiryHandler : public QObject {
1014  Q_OBJECT
1015 public:
1016 
1017 #if defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT)
1018  explicit InquiryHandler( const char * keyword_, QObject * p=0 )
1019  : QObject( p ),
1020 # if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
1021  buffer( 0 ),
1022  buflen( 0 ),
1023 # endif
1024  keyword( keyword_ )
1025  {
1026 
1027  }
1028 
1029 # if defined(HAVE_ASSUAN2) || defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
1030 # ifndef HAVE_ASSUAN2
1031  static int handler( void * cb_data, int rc, unsigned char * buffer, size_t buflen )
1032 # else
1033  static gpg_error_t handler( void * cb_data, gpg_error_t rc, unsigned char * buffer, size_t buflen )
1034 # endif
1035  {
1036  assert( cb_data );
1037  InquiryHandler * this_ = static_cast<InquiryHandler*>(cb_data);
1038  emit this_->signal( rc, QByteArray::fromRawData( reinterpret_cast<const char*>(buffer), buflen ), this_->keyword );
1039  std::free( buffer );
1040  delete this_;
1041  return 0;
1042  }
1043 # else
1044  static int handler( void * cb_data, int rc )
1045  {
1046  assert( cb_data );
1047  InquiryHandler * this_ = static_cast<InquiryHandler*>(cb_data);
1048  emit this_->signal( rc, QByteArray::fromRawData( reinterpret_cast<const char*>(this_->buffer), this_->buflen ), this_->keyword );
1049  std::free( this_->buffer );
1050  delete this_;
1051  return 0;
1052  }
1053 # endif
1054 
1055 private:
1056 #if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
1057  friend class ::Kleo::AssuanCommand;
1058  unsigned char * buffer;
1059  size_t buflen;
1060 #endif
1061  const char * keyword;
1062 #endif // defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT)
1063 
1064 Q_SIGNALS:
1065  void signal( int rc, const QByteArray & data, const QByteArray & keyword );
1066 };
1067 
1068 } // namespace Kleo
1069 
1070 class AssuanCommand::Private {
1071 public:
1072  Private()
1073  : informativeRecipients( false ),
1074  informativeSenders( false ),
1075  bias( GpgME::UnknownProtocol ),
1076  done( false ),
1077  nohup( false )
1078  {
1079 
1080  }
1081 
1082  std::map<std::string,QVariant> options;
1083  std::vector< shared_ptr<Input> > inputs, messages;
1084  std::vector< shared_ptr<Output> > outputs;
1085  std::vector<QString> files;
1086  std::vector<KMime::Types::Mailbox> recipients, senders;
1087  bool informativeRecipients, informativeSenders;
1088  GpgME::Protocol bias;
1089  QString sessionTitle;
1090  unsigned int sessionId;
1091  QByteArray utf8ErrorKeepAlive;
1092  AssuanContext ctx;
1093  bool done;
1094  bool nohup;
1095 };
1096 
1097 AssuanCommand::AssuanCommand()
1098  : d( new Private )
1099 {
1100 
1101 }
1102 
1103 AssuanCommand::~AssuanCommand() {
1104 
1105 }
1106 
1107 int AssuanCommand::start() {
1108  try {
1109  if ( const int err = doStart() )
1110  if ( !d->done )
1111  done( err );
1112  return 0;
1113  } catch ( const Exception & e ) {
1114  if ( !d->done )
1115  done( e.error_code(), e.message() );
1116  return 0;
1117  } catch ( const GpgME::Exception & e ) {
1118  if ( !d->done )
1119  done( e.error(), QString::fromLocal8Bit( e.message().c_str() ) );
1120  return 0;
1121  } catch ( const std::exception & e ) {
1122  if ( !d->done )
1123  done( makeError( GPG_ERR_INTERNAL ), i18n("Caught unexpected exception: %1", QString::fromLocal8Bit( e.what() ) ) );
1124  return 0;
1125  } catch ( ... ) {
1126  if ( !d->done )
1127  done( makeError( GPG_ERR_INTERNAL ), i18n("Caught unknown exception - please report this error to the developers." ) );
1128  return 0;
1129  }
1130 }
1131 
1132 void AssuanCommand::canceled() {
1133  d->done = true;
1134  doCanceled();
1135 }
1136 
1137 // static
1138 int AssuanCommand::makeError( int code ) {
1139  return makeGnuPGError( code );
1140 }
1141 
1142 bool AssuanCommand::hasOption( const char * opt ) const {
1143  return d->options.count( opt );
1144 }
1145 
1146 QVariant AssuanCommand::option( const char * opt ) const {
1147  const std::map<std::string,QVariant>::const_iterator it = d->options.find( opt );
1148  if ( it == d->options.end() )
1149  return QVariant();
1150  else
1151  return it->second;
1152 }
1153 
1154 const std::map<std::string,QVariant> & AssuanCommand::options() const {
1155  return d->options;
1156 }
1157 
1158 namespace {
1159  template <typename U, typename V>
1160  std::vector<U> keys( const std::map<U,V> & map ) {
1161  std::vector<U> result;
1162  result.resize( map.size() );
1163  for ( typename std::map<U,V>::const_iterator it = map.begin(), end = map.end() ; it != end ; ++it )
1164  result.push_back( it->first );
1165  return result;
1166  }
1167 }
1168 
1169 const std::map< QByteArray, shared_ptr<AssuanCommand::Memento> > & AssuanCommand::mementos() const {
1170  // oh, hack :(
1171  assert( assuan_get_pointer( d->ctx.get() ) );
1172  const AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
1173  return conn.mementos;
1174 }
1175 
1176 bool AssuanCommand::hasMemento( const QByteArray & tag ) const {
1177  if ( const unsigned int id = sessionId() )
1178  return SessionDataHandler::instance()->sessionData(id)->mementos.count( tag ) || mementos().count( tag ) ;
1179  else
1180  return mementos().count( tag );
1181 }
1182 
1183 shared_ptr<AssuanCommand::Memento> AssuanCommand::memento( const QByteArray & tag ) const {
1184  if ( const unsigned int id = sessionId() ) {
1185  const shared_ptr<SessionDataHandler> sdh = SessionDataHandler::instance();
1186  const shared_ptr<SessionData> sd = sdh->sessionData(id);
1187  const std::map< QByteArray, shared_ptr<Memento> >::const_iterator it = sd->mementos.find( tag );
1188  if ( it != sd->mementos.end() )
1189  return it->second;
1190  }
1191  const std::map< QByteArray, shared_ptr<Memento> >::const_iterator it = mementos().find( tag );
1192  if ( it == mementos().end() )
1193  return shared_ptr<Memento>();
1194  else
1195  return it->second;
1196 }
1197 
1198 QByteArray AssuanCommand::registerMemento( const shared_ptr<Memento> & mem ) {
1199  const QByteArray tag = QByteArray::number( reinterpret_cast<qulonglong>( mem.get() ), 36 );
1200  return registerMemento( tag, mem );
1201 }
1202 
1203 QByteArray AssuanCommand::registerMemento( const QByteArray & tag, const shared_ptr<Memento> & mem ) {
1204  // oh, hack :(
1205  assert( assuan_get_pointer( d->ctx.get() ) );
1206  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
1207 
1208  if ( const unsigned int id = sessionId() )
1209  SessionDataHandler::instance()->sessionData(id)->mementos[tag] = mem;
1210  else
1211  conn.mementos[tag] = mem;
1212  return tag;
1213 }
1214 
1215 void AssuanCommand::removeMemento( const QByteArray & tag ) {
1216  // oh, hack :(
1217  assert( assuan_get_pointer( d->ctx.get() ) );
1218  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
1219 
1220  conn.mementos.erase( tag );
1221  if ( const unsigned int id = sessionId() )
1222  SessionDataHandler::instance()->sessionData(id)->mementos.erase( tag );
1223 }
1224 
1225 const std::vector< shared_ptr<Input> > & AssuanCommand::inputs() const {
1226  return d->inputs;
1227 }
1228 
1229 const std::vector< shared_ptr<Input> > & AssuanCommand::messages() const {
1230  return d->messages;
1231 }
1232 
1233 const std::vector< shared_ptr<Output> > & AssuanCommand::outputs() const {
1234  return d->outputs;
1235 }
1236 
1237 QStringList AssuanCommand::fileNames() const {
1238  return kdtools::copy<QStringList>( d->files );
1239 }
1240 
1241 unsigned int AssuanCommand::numFiles() const {
1242  return d->files.size();
1243 }
1244 
1245 void AssuanCommand::sendStatus( const char * keyword, const QString & text ) {
1246  sendStatusEncoded( keyword, text.toUtf8().constData() );
1247 }
1248 
1249 void AssuanCommand::sendStatusEncoded( const char * keyword, const std::string & text ) {
1250  if ( d->nohup )
1251  return;
1252  if ( const int err = assuan_write_status( d->ctx.get(), keyword, text.c_str() ) )
1253  throw Exception( err, i18n( "Cannot send \"%1\" status", QString::fromLatin1( keyword ) ) );
1254 }
1255 
1256 void AssuanCommand::sendData( const QByteArray & data, bool moreToCome ) {
1257  if ( d->nohup )
1258  return;
1259  if ( const gpg_error_t err = assuan_send_data( d->ctx.get(), data.constData(), data.size() ) )
1260  throw Exception( err, i18n( "Cannot send data" ) );
1261  if ( !moreToCome )
1262  if ( const gpg_error_t err = assuan_send_data( d->ctx.get(), 0, 0 ) ) // flush
1263  throw Exception( err, i18n( "Cannot flush data" ) );
1264 }
1265 
1266 int AssuanCommand::inquire( const char * keyword, QObject * receiver, const char * slot, unsigned int maxSize ) {
1267  assert( keyword );
1268  assert( receiver );
1269  assert( slot );
1270 
1271  if ( d->nohup )
1272  return makeError( GPG_ERR_INV_OP );
1273 
1274 #if defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT)
1275  std::auto_ptr<InquiryHandler> ih( new InquiryHandler( keyword, receiver ) );
1276  receiver->connect( ih.get(), SIGNAL(signal(int,QByteArray,QByteArray)), slot );
1277  if ( const gpg_error_t err = assuan_inquire_ext( d->ctx.get(), keyword,
1278 # if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
1279  &ih->buffer, &ih->buflen,
1280 # endif
1281  maxSize, InquiryHandler::handler, ih.get() ) )
1282  return err;
1283  ih.release();
1284  return 0;
1285 #else
1286  return makeError( GPG_ERR_NOT_SUPPORTED ); // libassuan too old
1287 #endif // defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT)
1288 }
1289 
1290 void AssuanCommand::done( const GpgME::Error& err, const QString & details ) {
1291  if ( d->ctx && !d->done && !details.isEmpty() ) {
1292  kDebug() << "Error: " << details;
1293  d->utf8ErrorKeepAlive = details.toUtf8();
1294  if ( !d->nohup )
1295  assuan_set_error( d->ctx.get(), err.encodedError(), d->utf8ErrorKeepAlive.constData() );
1296  }
1297  done( err );
1298 }
1299 
1300 void AssuanCommand::done( const GpgME::Error& err ) {
1301  if ( !d->ctx ) {
1302  kDebug() << err.asString() << ": called with NULL ctx.";
1303  return;
1304  }
1305  if ( d->done ) {
1306  kDebug() << err.asString() << ": called twice!";
1307  return;
1308  }
1309 
1310  d->done = true;
1311 
1312  std::for_each( d->messages.begin(), d->messages.end(),
1313  boost::bind( &Input::finalize, _1 ) );
1314  std::for_each( d->inputs.begin(), d->inputs.end(),
1315  boost::bind( &Input::finalize, _1 ) );
1316  std::for_each( d->outputs.begin(), d->outputs.end(),
1317  boost::bind( &Output::finalize, _1 ) );
1318  d->messages.clear();
1319  d->inputs.clear();
1320  d->outputs.clear();
1321  d->files.clear();
1322 
1323  // oh, hack :(
1324  assert( assuan_get_pointer( d->ctx.get() ) );
1325  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
1326 
1327  if ( d->nohup ) {
1328  conn.nohupDone( this );
1329  return;
1330  }
1331 
1332  const gpg_error_t rc = assuan_process_done( d->ctx.get(), err.encodedError() );
1333  if ( gpg_err_code( rc ) != GPG_ERR_NO_ERROR )
1334  qFatal( "AssuanCommand::done: assuan_process_done returned error %d (%s)",
1335  static_cast<int>(rc), gpg_strerror(rc) );
1336 
1337  d->utf8ErrorKeepAlive.clear();
1338 
1339  conn.commandDone( this );
1340 }
1341 
1342 
1343 void AssuanCommand::setNohup( bool nohup ) {
1344  d->nohup = nohup;
1345 }
1346 
1347 bool AssuanCommand::isNohup() const {
1348  return d->nohup;
1349 }
1350 
1351 bool AssuanCommand::isDone() const {
1352  return d->done;
1353 }
1354 
1355 QString AssuanCommand::sessionTitle() const {
1356  return d->sessionTitle;
1357 }
1358 
1359 unsigned int AssuanCommand::sessionId() const {
1360  return d->sessionId;
1361 }
1362 
1363 bool AssuanCommand::informativeSenders() const {
1364  return d->informativeSenders;
1365 }
1366 
1367 bool AssuanCommand::informativeRecipients() const {
1368  return d->informativeRecipients;
1369 }
1370 
1371 const std::vector<KMime::Types::Mailbox> & AssuanCommand::recipients() const {
1372  return d->recipients;
1373 }
1374 
1375 const std::vector<KMime::Types::Mailbox> & AssuanCommand::senders() const {
1376  return d->senders;
1377 }
1378 
1379 #ifndef HAVE_ASSUAN2
1380 int AssuanCommandFactory::_handle( assuan_context_t ctx, char * line, const char * commandName ) {
1381 #else
1382 gpg_error_t AssuanCommandFactory::_handle( assuan_context_t ctx, char * line, const char * commandName ) {
1383 #endif
1384  assert( assuan_get_pointer( ctx ) );
1385  AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx ) );
1386 
1387  try {
1388 
1389  const std::vector< shared_ptr<AssuanCommandFactory> >::const_iterator it
1390  = std::lower_bound( conn.factories.begin(), conn.factories.end(), commandName, _detail::ByName<std::less>() );
1391  kleo_assert( it != conn.factories.end() );
1392  kleo_assert( *it );
1393  kleo_assert( qstricmp( (*it)->name(), commandName ) == 0 );
1394 
1395  const shared_ptr<AssuanCommand> cmd = (*it)->create();
1396  kleo_assert( cmd );
1397 
1398  cmd->d->ctx = conn.ctx;
1399  cmd->d->options = conn.options;
1400  cmd->d->inputs.swap( conn.inputs ); kleo_assert( conn.inputs.empty() );
1401  cmd->d->messages.swap( conn.messages ); kleo_assert( conn.messages.empty() );
1402  cmd->d->outputs.swap( conn.outputs ); kleo_assert( conn.outputs.empty() );
1403  cmd->d->files.swap( conn.files ); kleo_assert( conn.files.empty() );
1404  cmd->d->senders.swap( conn.senders ); kleo_assert( conn.senders.empty() );
1405  cmd->d->recipients.swap( conn.recipients ); kleo_assert( conn.recipients.empty() );
1406  cmd->d->informativeRecipients = conn.informativeRecipients;
1407  cmd->d->informativeSenders = conn.informativeSenders;
1408  cmd->d->bias = conn.bias;
1409  cmd->d->sessionTitle = conn.sessionTitle;
1410  cmd->d->sessionId = conn.sessionId;
1411 
1412  const std::map<std::string,std::string> cmdline_options = parse_commandline( line );
1413  for ( std::map<std::string,std::string>::const_iterator it = cmdline_options.begin(), end = cmdline_options.end() ; it != end ; ++it )
1414  cmd->d->options[it->first] = QString::fromUtf8( it->second.c_str() );
1415 
1416  bool nohup = false;
1417  if ( cmd->d->options.count( "nohup" ) ) {
1418  if ( !cmd->d->options["nohup"].toString().isEmpty() )
1419  return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_ASS_PARAMETER ), "--nohup takes no argument" );
1420  nohup = true;
1421  cmd->d->options.erase( "nohup" );
1422  }
1423 
1424  conn.currentCommand = cmd;
1425  conn.currentCommandIsNohup = nohup;
1426 
1427  QTimer::singleShot( 0, &conn, SLOT(startCommandBottomHalf()) );
1428 
1429  return 0;
1430 
1431  } catch ( const Exception & e ) {
1432  return assuan_process_done_msg( conn.ctx.get(), e.error_code(), e.message() );
1433  } catch ( const std::exception & e ) {
1434  return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), e.what() );
1435  } catch ( ... ) {
1436  return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unknown exception") );
1437  }
1438 }
1439 
1440 int AssuanServerConnection::Private::startCommandBottomHalf() {
1441 
1442  commandWaitingForCryptoCommandsEnabled = currentCommand && !cryptoCommandsEnabled;
1443 
1444  if ( !cryptoCommandsEnabled )
1445  return 0;
1446 
1447  const shared_ptr<AssuanCommand> cmd = currentCommand;
1448  if ( !cmd )
1449  return 0;
1450 
1451  currentCommand.reset();
1452 
1453  const bool nohup = currentCommandIsNohup;
1454  currentCommandIsNohup = false;
1455 
1456  try {
1457 
1458  if ( const int err = cmd->start() ) {
1459  if ( cmd->isDone() )
1460  return err;
1461  else
1462  return assuan_process_done( ctx.get(), err );
1463  }
1464 
1465  if ( cmd->isDone() )
1466  return 0;
1467 
1468  if ( nohup ) {
1469  cmd->setNohup( true );
1470  nohupedCommands.push_back( cmd );
1471  return assuan_process_done_msg( ctx.get(), 0, "Command put in the background to continue executing after connection end." );
1472  } else {
1473  currentCommand = cmd;
1474  return 0;
1475  }
1476 
1477  } catch ( const Exception & e ) {
1478  return assuan_process_done_msg( ctx.get(), e.error_code(), e.message() );
1479  } catch ( const std::exception & e ) {
1480  return assuan_process_done_msg( ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), e.what() );
1481  } catch ( ... ) {
1482  return assuan_process_done_msg( ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unknown exception") );
1483  }
1484 
1485 }
1486 
1487 //
1488 //
1489 // AssuanCommand convenience methods
1490 //
1491 //
1492 
1501 AssuanCommand::Mode AssuanCommand::checkMode() const {
1502  if ( !hasOption( "mode" ) )
1503  throw Exception( makeError( GPG_ERR_MISSING_VALUE ), i18n( "Required --mode option missing" ) );
1504 
1505  const QString modeString = option("mode").toString().toLower();
1506  if ( modeString == QLatin1String( "filemanager" ) )
1507  return FileManager;
1508  if ( modeString == QLatin1String( "email" ) )
1509  return EMail;
1510  throw Exception( makeError( GPG_ERR_INV_ARG ), i18n( "invalid mode: \"%1\"", modeString ) );
1511 }
1512 
1526 GpgME::Protocol AssuanCommand::checkProtocol( Mode mode, int options ) const {
1527  if ( !hasOption("protocol") )
1528  if ( d->bias != GpgME::UnknownProtocol )
1529  return d->bias;
1530  else if ( mode == AssuanCommand::EMail && ( options & AllowProtocolMissing ) == 0 )
1531  throw Exception( makeError( GPG_ERR_MISSING_VALUE ), i18n( "Required --protocol option missing" ) );
1532  else
1533  return GpgME::UnknownProtocol;
1534  else
1535  if ( mode == AssuanCommand::FileManager )
1536  throw Exception( makeError( GPG_ERR_INV_FLAG ), i18n("--protocol is not allowed here") );
1537 
1538  const QString protocolString = option("protocol").toString().toLower();
1539  if ( protocolString == QLatin1String( "openpgp" ) )
1540  return GpgME::OpenPGP;
1541  if ( protocolString == QLatin1String( "cms" ) )
1542  return GpgME::CMS;
1543  throw Exception( makeError( GPG_ERR_INV_ARG ), i18n( "invalid protocol \"%1\"", protocolString ) );
1544 }
1545 
1546 void AssuanCommand::doApplyWindowID( QWidget * widget ) const {
1547  if ( !widget || !hasOption( "window-id" ) )
1548  return;
1549  apply_window_id( widget, option("window-id").toString() );
1550 }
1551 
1552 WId AssuanCommand::parentWId() const {
1553  return wid_from_string( option("window-id").toString() );
1554 }
1555 
1556 #include "assuanserverconnection.moc"
Kleo::AssuanCommand::isNohup
bool isNohup() const
Definition: assuanserverconnection.cpp:1347
FOR_READING
static const int FOR_READING
Definition: assuanserverconnection.cpp:118
QWidget
MAX_ACTIVE_FDS
static const unsigned int MAX_ACTIVE_FDS
Definition: assuanserverconnection.cpp:119
AssuanContextBase
shared_ptr< remove_pointer< assuan_context_t >::type > AssuanContextBase
Definition: assuanserverconnection.cpp:129
Kleo::AssuanCommand::~AssuanCommand
virtual ~AssuanCommand()
Definition: assuanserverconnection.cpp:1103
output.h
apply_window_id
static void apply_window_id(QWidget *widget, const QString &winIdStr)
Definition: assuanserverconnection.cpp:222
Kleo::AssuanCommand::FileManager
Definition: assuancommand.h:249
Kleo::AssuanServerConnection::~AssuanServerConnection
~AssuanServerConnection()
Definition: assuanserverconnection.cpp:994
input.h
Kleo::AssuanCommand::hasMemento
bool hasMemento(const QByteArray &tag) const
Definition: assuanserverconnection.cpp:1176
Kleo::Output::finalize
virtual void finalize()=0
QSocketNotifier
kleo-assuan.h
parse_commandline
static std::map< std::string, std::string > parse_commandline(const char *line)
Definition: assuanserverconnection.cpp:174
QByteArray
getpid.h
email
static std::string email(const UserID &uid)
Definition: keycache.cpp:594
assuan_process_done_msg
static gpg_error_t assuan_process_done_msg(assuan_context_t ctx, gpg_error_t err, const char *err_msg)
Definition: assuanserverconnection.cpp:145
QPointer
Kleo::AssuanCommand::sendStatusEncoded
void sendStatusEncoded(const char *keyword, const std::string &text)
Definition: assuanserverconnection.cpp:1249
Kleo::AssuanCommand::setNohup
void setNohup(bool on)
Definition: assuanserverconnection.cpp:1343
Kleo::AssuanCommand::EMail
Definition: assuancommand.h:249
Kleo::AssuanCommand::memento
boost::shared_ptr< Memento > memento(const QByteArray &tag) const
Definition: assuanserverconnection.cpp:1183
QByteArray::fromRawData
QByteArray fromRawData(const char *data, int size)
upcase_option
static std::map< std::string, std::string > upcase_option(const char *option, std::map< std::string, std::string > options)
Definition: assuanserverconnection.cpp:157
Kleo::AssuanCommand::removeMemento
void removeMemento(const QByteArray &tag)
Definition: assuanserverconnection.cpp:1215
QStringList::join
QString join(const QString &separator) const
option
const char * option
Definition: kleopatraapplication.cpp:93
INIT_SOCKET_FLAGS
static const unsigned int INIT_SOCKET_FLAGS
Definition: assuanserverconnection.cpp:116
Kleo::AssuanCommand::fileNames
QStringList fileNames() const
Definition: assuanserverconnection.cpp:1237
QWidget::setParent
void setParent(QWidget *parent)
Kleo::AssuanCommand::senders
const std::vector< KMime::Types::Mailbox > & senders() const
Definition: assuanserverconnection.cpp:1375
Kleo::AssuanCommand::sendData
void sendData(const QByteArray &data, bool moreToCome=false)
Definition: assuanserverconnection.cpp:1256
wid_from_string
static WId wid_from_string(const QString &winIdStr, bool *ok=0)
Definition: assuanserverconnection.cpp:212
Kleo::AssuanCommand::Mode
Mode
Definition: assuancommand.h:249
Kleo::SessionDataHandler::instance
static boost::shared_ptr< SessionDataHandler > instance()
Definition: sessiondata.cpp:61
QByteArray::resize
void resize(int size)
kleo_assert.h
Kleo::AssuanCommand::checkMode
Mode checkMode() const
Definition: assuanserverconnection.cpp:1501
QRegExp
boost::shared_ptr
Definition: encryptemailcontroller.h:51
Kleo::AssuanCommand::inquire
int inquire(const char *keyword, QObject *receiver, const char *slot, unsigned int maxSize=0)
Definition: assuanserverconnection.cpp:1266
QString::fromLocal8Bit
QString fromLocal8Bit(const char *str, int size)
Kleo::AssuanCommand::outputs
const std::vector< boost::shared_ptr< Output > > & outputs() const
Definition: assuanserverconnection.cpp:1233
d
#define d
Definition: adduseridcommand.cpp:89
sessiondata.h
QString::fromUtf8
QString fromUtf8(const char *str, int size)
ASSUAN_INVALID_FD
#define ASSUAN_INVALID_FD
Definition: kleo-assuan.h:73
QObject
Kleo::Class::OpenPGP
Definition: classify.h:49
QString::isEmpty
bool isEmpty() const
hex.h
QByteArray::number
QByteArray number(int n, int base)
QByteArray::constData
const char * constData() const
Kleo::AssuanCommand::option
QVariant option(const char *opt) const
Definition: assuanserverconnection.cpp:1146
Kleo::AssuanCommand::sessionTitle
QString sessionTitle() const
Definition: assuanserverconnection.cpp:1355
Kleo::Output
Definition: output.h:73
kdtools::pimpl_ptr::get
T * get()
Definition: pimpl_ptr.h:39
Kleo::Class::CMS
Definition: classify.h:48
Kleo::AssuanServerConnection::enableCryptoCommands
void enableCryptoCommands(bool enable=true)
Definition: assuanserverconnection.cpp:996
QObject::deleteLater
void deleteLater()
QString
QString::toULongLong
qulonglong toULongLong(bool *ok, int base) const
Kleo::AssuanCommand::AssuanCommand
AssuanCommand()
Definition: assuanserverconnection.cpp:1097
QStringList
gnupg-helper.h
assuancommand.h
Kleo::AssuanCommand::sendStatus
void sendStatus(const char *keyword, const QString &text)
Definition: assuanserverconnection.cpp:1245
QFileInfo
Kleo::AssuanCommand::recipients
const std::vector< KMime::Types::Mailbox > & recipients() const
Definition: assuanserverconnection.cpp:1371
Kleo::AssuanCommandFactory::_handle
static int _handle(assuan_context_s *, char *, const char *)
Definition: assuanserverconnection.cpp:1380
Kleo::Output::setBinaryOpt
virtual void setBinaryOpt(bool value)=0
signal
const char * signal
Definition: keylistcontroller.cpp:289
Kleo::AssuanCommand::makeError
static int makeError(int code)
Definition: assuanserverconnection.cpp:1138
Kleo::makeGnuPGError
int makeGnuPGError(int code)
Definition: gnupg-helper.cpp:69
Kleo::AssuanCommand::numFiles
unsigned int numFiles() const
Definition: assuanserverconnection.cpp:1241
kleo_assert
#define kleo_assert(cond)
Definition: kleo_assert.h:86
assuanserverconnection.h
Kleo::AssuanCommand::parentWId
WId parentWId() const
Definition: assuanserverconnection.cpp:1552
string
const char * string
Definition: verifychecksumscontroller.cpp:510
QWidget::windowFlags
windowFlags
Kleo::AssuanCommand::inputs
const std::vector< boost::shared_ptr< Input > > & inputs() const
Definition: assuanserverconnection.cpp:1225
Kleo::AssuanCommand::start
int start()
Definition: assuanserverconnection.cpp:1107
Kleo::AssuanCommand
Base class for GnuPG UI Server commands.
Definition: assuancommand.h:215
QLatin1String
Kleo::AssuanCommand::done
void done(const GpgME::Error &err=GpgME::Error())
Definition: assuanserverconnection.cpp:1300
slot
const char * slot
Definition: keylistcontroller.cpp:290
QWidget::find
QWidget * find(WId id)
Kleo::Input::finalize
void finalize()
Definition: input.cpp:373
Kleo::AssuanCommand::hasOption
bool hasOption(const char *opt) const
Definition: assuanserverconnection.cpp:1142
Kleo::AssuanCommand::canceled
void canceled()
Definition: assuanserverconnection.cpp:1132
q
#define q
Definition: adduseridcommand.cpp:90
Kleo::_detail::ByName
Definition: detail_p.h:54
detail_p.h
Kleo::AssuanCommand::registerMemento
QByteArray registerMemento(const boost::shared_ptr< Memento > &mem)
Definition: assuanserverconnection.cpp:1198
QString::fromLatin1
QString fromLatin1(const char *str, int size)
assuan_fd_t
int assuan_fd_t
Definition: kleo-assuan.h:72
Kleo::AssuanCommand::checkProtocol
GpgME::Protocol checkProtocol(Mode mode, int options=0) const
Definition: assuanserverconnection.cpp:1526
Kleo::AssuanCommand::sessionId
unsigned int sessionId() const
Definition: assuanserverconnection.cpp:1359
keycache.h
Kleo::AssuanCommand::informativeSenders
bool informativeSenders() const
Definition: assuanserverconnection.cpp:1363
log.h
QByteArray::size
int size() const
Kleo::AssuanCommand::informativeRecipients
bool informativeRecipients() const
Definition: assuanserverconnection.cpp:1367
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
Kleo::AssuanCommand::options
const std::map< std::string, QVariant > & options() const
Definition: assuanserverconnection.cpp:1154
Kleo::mygetpid
static qint64 mygetpid()
Definition: getpid.h:49
QFile::decodeName
QString decodeName(const QByteArray &localFileName)
Kleo::hexdecode
std::string hexdecode(const char *s)
Definition: hex.cpp:117
Kleo::AssuanCommand::messages
const std::vector< boost::shared_ptr< Input > > & messages() const
Definition: assuanserverconnection.cpp:1229
Kleo::AssuanCommand::isDone
bool isDone() const
Definition: assuanserverconnection.cpp:1351
QTimer::singleShot
singleShot
QVariant
QString::toUtf8
QByteArray toUtf8() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:33:10 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