33 #include <config-kleopatra.h>
43 #include <kleo/exception.h>
46 #include <KMessageBox>
50 #include <QTemporaryFile>
53 #include <QApplication>
68 using namespace Kleo::_detail;
69 using namespace boost;
74 class OverwritePolicy::Private {
100 class TemporaryFile :
public QTemporaryFile {
102 explicit TemporaryFile() : QTemporaryFile() {}
103 explicit TemporaryFile(
const QString & templateName ) : QTemporaryFile( templateName ) {}
104 explicit TemporaryFile( QObject * parent ) : QTemporaryFile( parent ) {}
105 explicit TemporaryFile(
const QString & templateName, QObject * parent ) : QTemporaryFile( templateName, parent ) {}
109 m_oldFileName = fileName();
110 QTemporaryFile::close();
113 bool openNonInheritable() {
114 if ( !QTemporaryFile::open() )
116 #if defined(Q_OS_WIN) && !defined(_WIN32_WCE)
121 return SetHandleInformation( (HANDLE)_get_osfhandle( handle() ), HANDLE_FLAG_INHERIT, 0 );
126 QString oldFileName()
const {
return m_oldFileName; }
129 QString m_oldFileName;
133 template <
typename T_IODevice>
134 struct inhibit_close : T_IODevice {
135 explicit inhibit_close() : T_IODevice() {}
136 template <
typename T1>
137 explicit inhibit_close( T1 & t1 ) : T_IODevice( t1 ) {}
140 void reallyClose() { T_IODevice::close(); }
143 template <
typename T_IODevice>
144 struct redirect_close : T_IODevice {
145 explicit redirect_close() : T_IODevice(), m_closed( false ) {}
146 template <
typename T1>
147 explicit redirect_close( T1 & t1 ) : T_IODevice( t1 ), m_closed( false ) {}
149 void close() { this->closeWriteChannel(); m_closed =
true; }
151 bool isClosed()
const {
return m_closed; }
157 class OutputImplBase :
public Output {
164 m_isFinalized( false ),
165 m_isFinalizing( false ),
166 m_cancelPending( false ),
173 QString label()
const {
return m_customLabel.isEmpty() ? m_defaultLabel : m_customLabel; }
174 void setLabel(
const QString & label ) { m_customLabel = label; }
175 void setDefaultLabel(
const QString & l ) { m_defaultLabel = l; }
176 void setBinaryOpt(
bool value ) { m_binaryOpt = value; }
177 bool binaryOpt()
const {
return m_binaryOpt; }
179 QString errorString()
const {
180 if ( m_errorString.dirty() )
181 m_errorString = doErrorString();
182 return m_errorString;
185 bool isFinalized()
const {
return m_isFinalized; }
188 if ( m_isFinalized || m_isFinalizing )
190 m_isFinalizing =
true;
191 try { doFinalize(); }
catch ( ... ) { m_isFinalizing =
false;
throw; }
192 m_isFinalizing =
false;
193 m_isFinalized =
true;
194 if ( m_cancelPending )
200 if ( m_isFinalizing ) {
201 m_cancelPending =
true;
202 }
else if ( !m_canceled ) {
203 m_isFinalizing =
true;
204 try { doCancel(); }
catch ( ... ) {}
205 m_isFinalizing =
false;
206 m_isFinalized =
true;
211 virtual QString doErrorString()
const {
213 return io->errorString();
215 return i18n(
"No output device");
217 virtual void doFinalize() = 0;
218 virtual void doCancel() = 0;
220 QString m_defaultLabel;
221 QString m_customLabel;
223 bool m_isFinalized : 1;
224 bool m_isFinalizing : 1;
225 bool m_cancelPending : 1;
227 bool m_binaryOpt : 1;
231 class PipeOutput :
public OutputImplBase {
236 void doFinalize() { m_io->reallyClose(); }
237 void doCancel() { doFinalize(); }
243 class ProcessStdInOutput :
public OutputImplBase {
245 explicit ProcessStdInOutput(
const QString & cmd,
const QStringList & args,
const QDir & wd );
257 kDebug(5151) <<
"Waiting for " << m_proc->bytesToWrite()
258 <<
" Bytes to be written";
261 if ( !m_proc->isClosed() ) {
270 QString label()
const;
273 QString doErrorString()
const;
276 const QString m_command;
277 const QStringList m_arguments;
282 class FileOutput :
public OutputImplBase {
285 ~FileOutput() { kDebug() <<
this; }
287 QString label()
const {
return QFileInfo( m_fileName ).fileName(); }
290 void doCancel() { kDebug() <<
this; }
292 bool obtainOverwritePermission();
295 const QString m_fileName;
300 #ifndef QT_NO_CLIPBOARD
301 class ClipboardOutput :
public OutputImplBase {
303 explicit ClipboardOutput( QClipboard::Mode mode );
305 QString label()
const;
311 QString doErrorString()
const {
return QString(); }
313 const QClipboard::Mode m_mode;
316 #endif // QT_NO_CLIPBOARD
323 po->setDefaultLabel( label );
332 if ( !m_io->open( fd, QIODevice::WriteOnly ) )
333 throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
334 i18n(
"Could not open FD %1 for writing",
345 kDebug() << fo.get();
351 m_fileName( fileName ),
352 m_tmpFile( new TemporaryFile( fileName ) ),
357 if ( !m_tmpFile->openNonInheritable() )
358 throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
359 i18n(
"Could not create temporary file for output \"%1\"", fileName ) );
362 bool FileOutput::obtainOverwritePermission() {
365 const int sel = KMessageBox::questionYesNoCancel( m_policy->parentWidget(), i18n(
"The file <b>%1</b> already exists.\n"
366 "Overwrite?", m_fileName ),
367 i18n(
"Overwrite Existing File?"),
368 KStandardGuiItem::overwrite(),
369 KGuiItem( i18n(
"Overwrite All" ) ),
370 KStandardGuiItem::cancel() );
371 if ( sel == KMessageBox::No )
373 return sel == KMessageBox::Yes || sel == KMessageBox::No;
376 void FileOutput::doFinalize() {
381 ~Remover() {
if ( QFile::exists( file ) ) QFile::remove( file ); }
386 if ( m_tmpFile->isOpen() )
389 const QString tmpFileName = remover.file = m_tmpFile->oldFileName();
391 m_tmpFile->setAutoRemove(
false );
392 QPointer<QObject> guard = m_tmpFile.get();
396 kDebug() <<
this <<
" renaming " << tmpFileName <<
"->" << m_fileName ;
398 if ( QFile::rename( tmpFileName, m_fileName ) ) {
399 kDebug() <<
this <<
"succeeded";
403 kDebug() <<
this <<
"failed";
405 if ( !obtainOverwritePermission() )
406 throw Exception( gpg_error( GPG_ERR_CANCELED ),
407 i18n(
"Overwriting declined" ) );
409 kDebug() <<
this <<
"going to overwrite" << m_fileName ;
411 if ( !QFile::remove( m_fileName ) )
412 throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
413 i18n(
"Could not remove file \"%1\" for overwriting.", m_fileName ) );
415 kDebug() <<
this <<
"succeeded, renaming " << tmpFileName <<
"->" << m_fileName;
417 if ( QFile::rename( tmpFileName, m_fileName ) ) {
418 kDebug() <<
this <<
"succeeded";
422 kDebug() <<
this <<
"failed";
424 throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
425 i18n(
"Could not rename file \"%1\" to \"%2\"",
426 tmpFileName, m_fileName ) );
431 return shared_ptr<Output>(
new ProcessStdInOutput( command, QStringList(), QDir::current() ) );
435 return shared_ptr<Output>(
new ProcessStdInOutput( command, args, QDir::current() ) );
442 ProcessStdInOutput::ProcessStdInOutput(
const QString & cmd,
const QStringList & args,
const QDir & wd )
446 m_proc( new redirect_close<QProcess> )
448 kDebug() <<
"cd" << wd.absolutePath() << endl << cmd << args;
450 throw Exception( gpg_error( GPG_ERR_INV_ARG ),
451 i18n(
"Command not specified") );
452 m_proc->setWorkingDirectory( wd.absolutePath() );
453 m_proc->start( cmd, args );
454 m_proc->setReadChannel( QProcess::StandardError );
455 if ( !m_proc->waitForStarted() )
456 throw Exception( gpg_error( GPG_ERR_EIO ),
457 i18n(
"Could not start %1 process: %2", cmd, m_proc->errorString() ) );
460 QString ProcessStdInOutput::label()
const {
462 return OutputImplBase::label();
464 const QString cmdline = ( QStringList( m_command ) + m_arguments.mid(0,3) ).join( QLatin1String(
" ") );
465 if ( m_arguments.size() > 3 )
466 return i18nc(
"e.g. \"Input to tar xf - file1 ...\"",
"Input to %1 ...", cmdline );
468 return i18nc(
"e.g. \"Input to tar xf - file\"",
"Input to %1", cmdline );
471 QString ProcessStdInOutput::doErrorString()
const {
473 if ( m_proc->exitStatus() == QProcess::NormalExit && m_proc->exitCode() == 0 )
475 if ( m_proc->error() == QProcess::UnknownError )
476 return i18n(
"Error while running %1: %2", m_command,
477 QString::fromLocal8Bit( m_proc->readAllStandardError().trimmed().constData() ) );
479 return i18n(
"Failed to execute %1: %2", m_command, m_proc->errorString() );
482 #ifndef QT_NO_CLIPBOARD
487 ClipboardOutput::ClipboardOutput( QClipboard::Mode mode )
490 m_buffer( new QBuffer )
493 if ( !m_buffer->open( QIODevice::WriteOnly ) )
494 throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
495 i18n(
"Could not write to clipboard" ) );
498 QString ClipboardOutput::label()
const {
500 case QClipboard::Clipboard:
501 return i18n(
"Clipboard" );
502 case QClipboard::FindBuffer:
503 return i18n(
"Find buffer" );
504 case QClipboard::Selection:
505 return i18n(
"Selection" );
510 void ClipboardOutput::doFinalize() {
511 if ( m_buffer->isOpen() )
513 if ( QClipboard *
const cb = QApplication::clipboard() )
514 cb->setText( QString::fromUtf8( m_buffer->data() ) );
516 throw Exception( gpg_error( GPG_ERR_EIO ),
517 i18n(
"Could not find clipboard" ) );
519 #endif // QT_NO_CLIPBOARD
static boost::shared_ptr< Output > createFromClipboard()
static boost::shared_ptr< Output > createFromPipeDevice(assuan_fd_t fd, const QString &label)
static qulonglong assuanFD2int(assuan_fd_t fd)
OverwritePolicy(QWidget *parent, Policy initialPolicy=Ask)
static boost::shared_ptr< Output > createFromFile(const QString &fileName, const boost::shared_ptr< OverwritePolicy > &)
#define kleo_assert(cond)
static boost::shared_ptr< Output > createFromProcessStdIn(const QString &command)
QWidget * parentWidget() const
static const int PROCESS_MAX_RUNTIME_TIMEOUT
static const int PROCESS_TERMINATE_TIMEOUT