Better wording
[kdepim.git] / kleopatra / utils / input.cpp
bloba973e92c9a1da7027738cdff41dd20c2b3297870
1 /* -*- mode: c++; c-basic-offset:4 -*-
2 utils/input.cpp
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
30 your version.
33 #include <config-kleopatra.h>
35 #include "input.h"
37 #include "detail_p.h"
38 #include "classify.h"
39 #include "kdpipeiodevice.h"
40 #include "log.h"
41 #include "kleo_assert.h"
42 #include "cached.h"
44 #include <kleo/exception.h>
46 #include <KDebug>
47 #include <KLocale>
49 #include <QFile>
50 #include <QString>
51 #include <QClipboard>
52 #include <QApplication>
53 #include <QByteArray>
54 #include <QBuffer>
55 #include <QDir>
56 #include <QFileInfo>
57 #include <QProcess>
59 #include <errno.h>
61 using namespace Kleo;
62 using namespace boost;
64 namespace {
66 class Process : public QProcess {
67 public:
68 explicit Process( QObject * parent=0 )
69 : QProcess( parent ) {}
70 /* reimp */ void close() { closeReadChannel( StandardOutput ); }
74 namespace {
76 class InputImplBase : public Input {
77 public:
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();
86 return m_errorString;
89 private:
90 virtual QString doErrorString() const {
91 if ( const shared_ptr<QIODevice> io = ioDevice() )
92 return io->errorString();
93 else
94 return i18n("No input device");
97 private:
98 QString m_customLabel;
99 QString m_defaultLabel;
100 mutable cached<QString> m_errorString;
105 class PipeInput : public InputImplBase {
106 public:
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; }
113 private:
114 shared_ptr<QIODevice> m_io;
117 class ProcessStdOutInput : public InputImplBase {
118 public:
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;
126 private:
127 /* reimp */ QString doErrorString() const;
129 private:
130 const QString m_command;
131 const QStringList m_arguments;
132 const shared_ptr<Process> m_proc;
135 class FileInput : public InputImplBase {
136 public:
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(); }
147 private:
148 shared_ptr<QIODevice> m_io;
149 QString m_fileName;
152 #ifndef QT_NO_CLIPBOARD
153 class ClipboardInput : public Input {
154 public:
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(); }
164 private:
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 );
176 return po;
179 PipeInput::PipeInput( assuan_fd_t fd )
180 : InputImplBase(),
181 m_io()
183 shared_ptr<KDPipeIODevice> kdp( new KDPipeIODevice );
184 errno = 0;
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 {
194 notImplemented();
195 return 0;
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 )
208 : InputImplBase(),
209 m_io(), m_fileName( fileName )
211 shared_ptr<QFile> file( new QFile( fileName ) );
213 errno = 0;
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 )
222 : InputImplBase(),
223 m_io(), m_fileName( file->fileName() )
225 kleo_assert( file );
226 errno = 0;
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_ ) );
265 namespace {
266 struct Outputter {
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)";
273 return s;
277 ProcessStdOutInput::ProcessStdOutInput( const QString & cmd, const QStringList & args, const QDir & wd, const QByteArray & stdin_ )
278 : InputImplBase(),
279 m_command( cmd ),
280 m_arguments( args ),
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_ );
286 if ( cmd.isEmpty() )
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 {
304 if ( !m_proc )
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 );
310 else
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 )
317 return QString();
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() ) );
321 else
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 )
332 Q_UNUSED( mode );
333 if ( QClipboard * const cb = QApplication::clipboard() )
334 return cb->text().toUtf8();
335 else
336 return QByteArray();
339 ClipboardInput::ClipboardInput( QClipboard::Mode mode )
340 : Input(),
341 m_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 & ) {
351 notImplemented();
354 QString ClipboardInput::label() const {
355 switch ( m_mode ) {
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" );
363 return QString();
366 unsigned int ClipboardInput::classification() const {
367 return classifyContent( m_buffer->data() );
369 #endif // QT_NO_CLIPBOARD
371 Input::~Input() {}
373 void Input::finalize() {
374 if ( const shared_ptr<QIODevice> io = ioDevice() )
375 if ( io->isOpen() )
376 io->close();