1 /* -*- mode: c++; c-basic-offset:4 -*-
4 This file is part of Kleopatra, the KDE keymanager
5 Copyright (c) 2007 Klarälvdalens Datakonsult AB
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.
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.
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
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
33 #include <config-kleopatra.h>
39 #include "kdpipeiodevice.h"
41 #include "kleo_assert.h"
44 #include <kleo/exception.h>
52 #include <QApplication>
62 using namespace boost
;
66 class Process
: public QProcess
{
68 explicit Process( QObject
* parent
=0 )
69 : QProcess( parent
) {}
70 /* reimp */ void close() { closeReadChannel( StandardOutput
); }
76 class InputImplBase
: public Input
{
78 InputImplBase() : Input(), m_customLabel(), m_defaultLabel() {}
80 /* reimp */ QString
label() const { return m_customLabel
.isEmpty() ? m_defaultLabel
: m_customLabel
; }
81 void setDefaultLabel( const QString
& l
) { m_defaultLabel
= l
; }
82 /* reimp */ void setLabel( const QString
& l
) { m_customLabel
= l
; }
83 /* reimp */ QString
errorString() const {
84 if ( m_errorString
.dirty() )
85 m_errorString
= doErrorString();
90 virtual QString
doErrorString() const {
91 if ( const shared_ptr
<QIODevice
> io
= ioDevice() )
92 return io
->errorString();
94 return i18n("No input device");
98 QString m_customLabel
;
99 QString m_defaultLabel
;
100 mutable cached
<QString
> m_errorString
;
105 class PipeInput
: public InputImplBase
{
107 explicit PipeInput( assuan_fd_t fd
);
109 /* reimp */ shared_ptr
<QIODevice
> ioDevice() const { return m_io
; }
110 /* reimp */ unsigned int classification() const;
111 /* reimp */ unsigned long long size() const { return 0; }
114 shared_ptr
<QIODevice
> m_io
;
117 class ProcessStdOutInput
: public InputImplBase
{
119 explicit ProcessStdOutInput( const QString
& cmd
, const QStringList
& args
, const QDir
& wd
, const QByteArray
& stdin_
=QByteArray() );
121 /* reimp */ shared_ptr
<QIODevice
> ioDevice() const { return m_proc
; }
122 /* reimp */ unsigned int classification() const { return 0U; } // plain text
123 /* reimp */ unsigned long long size() const { return 0; }
124 /* reimp */ QString
label() const;
127 /* reimp */ QString
doErrorString() const;
130 const QString m_command
;
131 const QStringList m_arguments
;
132 const shared_ptr
<Process
> m_proc
;
135 class FileInput
: public InputImplBase
{
137 explicit FileInput( const QString
& fileName
);
138 explicit FileInput( const shared_ptr
<QFile
> & file
);
140 /* reimp */ QString
label() const {
141 return m_io
? QFileInfo( m_fileName
).fileName() : InputImplBase::label();
143 /* reimp */ shared_ptr
<QIODevice
> ioDevice() const { return m_io
; }
144 /* reimp */ unsigned int classification() const;
145 /* reimp */ unsigned long long size() const { return QFileInfo( m_fileName
).size(); }
148 shared_ptr
<QIODevice
> m_io
;
152 #ifndef QT_NO_CLIPBOARD
153 class ClipboardInput
: public Input
{
155 explicit ClipboardInput( QClipboard::Mode mode
);
157 /* reimp */ void setLabel( const QString
& label
);
158 /* reimp */ QString
label() const;
159 /* reimp */ shared_ptr
<QIODevice
> ioDevice() const { return m_buffer
; }
160 /* reimp */ unsigned int classification() const;
161 /* reimp */ unsigned long long size() const { return m_buffer
? m_buffer
->buffer().size() : 0; }
162 /* reimp */ QString
errorString() const { return QString(); }
165 const QClipboard::Mode m_mode
;
166 shared_ptr
<QBuffer
> m_buffer
;
168 #endif // QT_NO_CLIPBOARD
173 shared_ptr
<Input
> Input::createFromPipeDevice( assuan_fd_t fd
, const QString
& label
) {
174 shared_ptr
<PipeInput
> po( new PipeInput( fd
) );
175 po
->setDefaultLabel( label
);
179 PipeInput::PipeInput( assuan_fd_t fd
)
183 shared_ptr
<KDPipeIODevice
> kdp( new KDPipeIODevice
);
185 if ( !kdp
->open( fd
, QIODevice::ReadOnly
) )
186 throw Exception( errno
? gpg_error_from_errno( errno
) : gpg_error( GPG_ERR_EIO
),
187 i18n( "Could not open FD %1 for reading",
188 _detail::assuanFD2int( fd
) ) );
189 m_io
= Log::instance()->createIOLogger( kdp
, "pipe-input", Log::Read
);
193 unsigned int PipeInput::classification() const {
199 shared_ptr
<Input
> Input::createFromFile( const QString
& fileName
, bool ) {
200 return shared_ptr
<Input
>( new FileInput( fileName
) );
203 shared_ptr
<Input
> Input::createFromFile( const shared_ptr
<QFile
> & file
) {
204 return shared_ptr
<Input
>( new FileInput( file
) );
207 FileInput::FileInput( const QString
& fileName
)
209 m_io(), m_fileName( fileName
)
211 shared_ptr
<QFile
> file( new QFile( fileName
) );
214 if ( !file
->open( QIODevice::ReadOnly
) )
215 throw Exception( errno
? gpg_error_from_errno( errno
) : gpg_error( GPG_ERR_EIO
),
216 i18n( "Could not open file \"%1\" for reading", fileName
) );
217 m_io
= Log::instance()->createIOLogger( file
, "file-in", Log::Read
);
221 FileInput::FileInput( const shared_ptr
<QFile
> & file
)
223 m_io(), m_fileName( file
->fileName() )
227 if ( file
->isOpen() && !file
->isReadable() )
228 throw Exception( gpg_error( GPG_ERR_INV_ARG
),
229 i18n( "File \"%1\" is already open, but not for reading", file
->fileName() ) );
230 if ( !file
->isOpen() && !file
->open( QIODevice::ReadOnly
) )
231 throw Exception( errno
? gpg_error_from_errno( errno
) : gpg_error( GPG_ERR_EIO
),
232 i18n( "Could not open file \"%1\" for reading", m_fileName
) );
233 m_io
= Log::instance()->createIOLogger( file
, "file-in", Log::Read
);
236 unsigned int FileInput::classification() const {
237 return classify( m_fileName
);
241 shared_ptr
<Input
> Input::createFromProcessStdOut( const QString
& command
) {
242 return shared_ptr
<Input
>( new ProcessStdOutInput( command
, QStringList(), QDir::current() ) );
245 shared_ptr
<Input
> Input::createFromProcessStdOut( const QString
& command
, const QStringList
& args
) {
246 return shared_ptr
<Input
>( new ProcessStdOutInput( command
, args
, QDir::current() ) );
249 shared_ptr
<Input
> Input::createFromProcessStdOut( const QString
& command
, const QStringList
& args
, const QDir
& wd
) {
250 return shared_ptr
<Input
>( new ProcessStdOutInput( command
, args
, wd
) );
253 shared_ptr
<Input
> Input::createFromProcessStdOut( const QString
& command
, const QByteArray
& stdin_
) {
254 return shared_ptr
<Input
>( new ProcessStdOutInput( command
, QStringList(), QDir::current(), stdin_
) );
257 shared_ptr
<Input
> Input::createFromProcessStdOut( const QString
& command
, const QStringList
& args
, const QByteArray
& stdin_
) {
258 return shared_ptr
<Input
>( new ProcessStdOutInput( command
, args
, QDir::current(), stdin_
) );
261 shared_ptr
<Input
> Input::createFromProcessStdOut( const QString
& command
, const QStringList
& args
, const QDir
& wd
, const QByteArray
& stdin_
) {
262 return shared_ptr
<Input
>( new ProcessStdOutInput( command
, args
, wd
, stdin_
) );
267 const QByteArray
& data
;
268 explicit Outputter( const QByteArray
& data
) : data( data
) {}
270 static QDebug
operator<<( QDebug s
, const Outputter
& o
) {
271 if ( const quint64 size
= o
.data
.size() )
272 s
<< " << (" << size
<< "bytes)";
277 ProcessStdOutInput::ProcessStdOutInput( const QString
& cmd
, const QStringList
& args
, const QDir
& wd
, const QByteArray
& stdin_
)
281 m_proc( new Process
)
283 const QIODevice::OpenMode openMode
=
284 stdin_
.isEmpty() ? QIODevice::ReadOnly
: QIODevice::ReadWrite
;
285 kDebug() << "cd" << wd
.absolutePath() << endl
<< cmd
<< args
<< Outputter( stdin_
);
287 throw Exception( gpg_error( GPG_ERR_INV_ARG
),
288 i18n("Command not specified") );
289 m_proc
->setWorkingDirectory( wd
.absolutePath() );
290 m_proc
->start( cmd
, args
, openMode
);
291 if ( !m_proc
->waitForStarted() )
292 throw Exception( gpg_error( GPG_ERR_EIO
),
293 i18n( "Could not start %1 process: %2", cmd
, m_proc
->errorString() ) );
295 if ( !stdin_
.isEmpty() ) {
296 if ( m_proc
->write( stdin_
) != stdin_
.size() )
297 throw Exception( gpg_error( GPG_ERR_EIO
),
298 i18n( "Failed to write input to %1 process: %2", cmd
, m_proc
->errorString() ) );
299 m_proc
->closeWriteChannel();
303 QString
ProcessStdOutInput::label() const {
305 return InputImplBase::label();
306 // output max. 3 arguments
307 const QString cmdline
= ( QStringList( m_command
) + m_arguments
.mid(0,3) ).join( " " );
308 if ( m_arguments
.size() > 3 )
309 return i18nc( "e.g. \"Output of tar xf - file1 ...\"", "Output of %1 ...", cmdline
);
311 return i18nc( "e.g. \"Output of tar xf - file\"", "Output of %1", cmdline
);
314 QString
ProcessStdOutInput::doErrorString() const {
315 kleo_assert( m_proc
);
316 if ( m_proc
->exitStatus() == QProcess::NormalExit
&& m_proc
->exitCode() == 0 )
318 if ( m_proc
->error() == QProcess::UnknownError
)
319 return i18n( "Error while running %1:\n%2", m_command
,
320 QString::fromLocal8Bit( m_proc
->readAllStandardError().trimmed().constData() ) );
322 return i18n( "Failed to execute %1: %2", m_command
, m_proc
->errorString() );
325 #ifndef QT_NO_CLIPBOARD
326 shared_ptr
<Input
> Input::createFromClipboard() {
327 return shared_ptr
<Input
>( new ClipboardInput( QClipboard::Clipboard
) );
330 static QByteArray
dataFromClipboard( QClipboard::Mode mode
)
333 if ( QClipboard
* const cb
= QApplication::clipboard() )
334 return cb
->text().toUtf8();
339 ClipboardInput::ClipboardInput( QClipboard::Mode mode
)
342 m_buffer( new QBuffer
)
344 m_buffer
->setData( dataFromClipboard( mode
) );
345 if ( !m_buffer
->open( QIODevice::ReadOnly
) )
346 throw Exception( gpg_error( GPG_ERR_EIO
),
347 i18n( "Could not open clipboard for reading" ) );
350 void ClipboardInput::setLabel( const QString
& ) {
354 QString
ClipboardInput::label() const {
356 case QClipboard::Clipboard
:
357 return i18n( "Clipboard contents" );
358 case QClipboard::FindBuffer
:
359 return i18n( "FindBuffer contents" );
360 case QClipboard::Selection
:
361 return i18n( "Current selection" );
366 unsigned int ClipboardInput::classification() const {
367 return classifyContent( m_buffer
->data() );
369 #endif // QT_NO_CLIPBOARD
373 void Input::finalize() {
374 if ( const shared_ptr
<QIODevice
> io
= ioDevice() )