Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F37954774
decryptverifycommand.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
30 KB
Subscribers
None
decryptverifycommand.cpp
View Options
/* -*- mode: c++; c-basic-offset:4 -*-
uiserver/verifycommand.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
"decryptverifycommand.h"
#include
"decryptverifywizard.h"
#include
"decryptverifyresultwidget.h"
#include
"decryptverifyoperationwidget.h"
#include
"kleo-assuan.h"
#include
"classify.h"
#include
"detail_p.h"
#include
<models/keycache.h>
#include
<models/predicates.h>
#include
<utils/formatting.h>
#include
<utils/stl_util.h>
#include
<kleo/verifyopaquejob.h>
#include
<kleo/verifydetachedjob.h>
#include
<kleo/decryptjob.h>
#include
<kleo/decryptverifyjob.h>
#include
<gpgme++/error.h>
#include
<gpgme++/key.h>
#include
<gpgme++/verificationresult.h>
#include
<gpgme++/decryptionresult.h>
#include
<gpg-error.h>
#include
<KLocale>
#include
<KIconLoader>
#include
<KMessageBox>
#include
<QFileDialog>
#include
<QObject>
#include
<QIODevice>
#include
<QMap>
#include
<QHash>
#include
<QPointer>
#include
<QTemporaryFile>
#include
<boost/bind.hpp>
#include
<cassert>
#include
<algorithm>
#include
<functional>
#include
<errno.h>
using
namespace
Kleo
;
using
namespace
GpgME
;
using
namespace
boost
;
// -- helpers ---
static
// dup of same function in decryptverifyresultwidget.cpp
const
GpgME
::
Key
&
keyForSignature
(
const
Signature
&
sig
,
const
std
::
vector
<
Key
>
&
keys
)
{
if
(
const
char
*
const
fpr
=
sig
.
fingerprint
()
)
{
const
std
::
vector
<
Key
>::
const_iterator
it
=
std
::
lower_bound
(
keys
.
begin
(),
keys
.
end
(),
fpr
,
_detail
::
ByFingerprint
<
std
::
less
>
()
);
if
(
it
!=
keys
.
end
()
&&
_detail
::
ByFingerprint
<
std
::
equal_to
>
()(
*
it
,
fpr
)
)
return
*
it
;
}
static
const
Key
null
;
return
null
;
}
namespace
{
enum
Type
{
Decrypt
,
DecryptVerify
,
VerifyOpaque
,
VerifyDetached
}
type
;
struct
DVResult
{
Type
type
;
VerificationResult
verificationResult
;
DecryptionResult
decryptionResult
;
QByteArray
stuff
;
int
error
;
QString
errorString
;
static
DVResult
fromDecryptResult
(
const
DecryptionResult
&
dr
,
const
QByteArray
&
plaintext
)
{
const
DVResult
res
=
{
Decrypt
,
VerificationResult
(),
dr
,
plaintext
,
0
,
QString
()
};
return
res
;
}
static
DVResult
fromDecryptResult
(
const
Error
&
err
)
{
return
fromDecryptResult
(
DecryptionResult
(
err
),
QByteArray
()
);
}
static
DVResult
fromDecryptVerifyResult
(
const
DecryptionResult
&
dr
,
const
VerificationResult
&
vr
,
const
QByteArray
&
plaintext
)
{
const
DVResult
res
=
{
DecryptVerify
,
vr
,
dr
,
plaintext
,
0
,
QString
()
};
return
res
;
}
static
DVResult
fromDecryptVerifyResult
(
const
Error
&
err
)
{
return
fromDecryptVerifyResult
(
DecryptionResult
(
err
),
VerificationResult
(),
QByteArray
()
);
}
static
DVResult
fromVerifyOpaqueResult
(
const
VerificationResult
&
vr
,
const
QByteArray
&
plaintext
)
{
const
DVResult
res
=
{
VerifyOpaque
,
vr
,
DecryptionResult
(),
plaintext
,
0
,
QString
()
};
return
res
;
}
static
DVResult
fromVerifyOpaqueResult
(
const
Error
&
err
)
{
return
fromVerifyOpaqueResult
(
VerificationResult
(
err
),
QByteArray
()
);
}
static
DVResult
fromVerifyDetachedResult
(
const
VerificationResult
&
vr
)
{
const
DVResult
res
=
{
VerifyDetached
,
vr
,
DecryptionResult
(),
QByteArray
(),
0
,
QString
()
};
return
res
;
}
static
DVResult
fromVerifyDetachedResult
(
const
Error
&
err
)
{
return
fromVerifyDetachedResult
(
VerificationResult
(
err
)
);
}
};
struct
Input
{
private
:
Input
(
const
Input
&
);
Input
&
operator
=
(
const
Input
&
);
public
:
Input
()
:
type
(
VerifyDetached
),
backend
(
0
)
{}
Type
type
;
struct
_Input
{
shared_ptr
<
QIODevice
>
io
;
QString
fileName
;
shared_ptr
<
QFile
>
file
;
// only used when != {INPUT,MESSAGE} (shared_ptr b/c QFile isn't copyable)
}
input
,
signedData
;
struct
_Output
{
shared_ptr
<
QIODevice
>
io
;
QString
fileName
;
shared_ptr
<
QTemporaryFile
>
tmp
;
}
output
;
const
CryptoBackend
::
Protocol
*
backend
;
shared_ptr
<
DVResult
>
result
;
static
_Input
fromOpenFile
(
const
shared_ptr
<
QFile
>
&
file
)
{
assuan_assert
(
file
->
isOpen
()
);
const
_Input
input
=
{
file
,
file
->
fileName
(),
file
};
return
input
;
}
static
_Input
openExistingFile
(
const
QString
&
fname
)
{
if
(
fname
.
isEmpty
()
)
throw
assuan_exception
(
gpg_error
(
GPG_ERR_ASS_NO_INPUT
),
i18n
(
"Empty filename provided"
)
);
const
shared_ptr
<
QFile
>
f
(
new
QFile
(
fname
)
);
if
(
!
f
->
open
(
QIODevice
::
ReadOnly
)
)
// ### ask again?
throw
assuan_exception
(
gpg_error
(
GPG_ERR_ASS_NO_INPUT
),
i18n
(
"Can't open file
\"
%1
\"
for reading: %2"
,
fname
,
f
->
errorString
()
)
);
const
_Input
input
=
{
f
,
fname
,
f
};
return
input
;
}
static
_Output
makeTemporaryOutput
(
const
QString
&
fname
)
{
const
shared_ptr
<
QTemporaryFile
>
tmp
(
new
QTemporaryFile
(
fname
)
);
if
(
!
tmp
->
open
()
)
throw
assuan_exception
(
gpg_error
(
GPG_ERR_ASS_NO_OUTPUT
),
i18n
(
"Can't open temporary file
\"
%1
\"
: %2"
,
tmp
->
fileName
(),
tmp
->
errorString
()
)
);
const
_Output
output
=
{
tmp
,
fname
,
tmp
,
};
return
output
;
}
void
finalizeOutput
(
bool
silent
);
};
}
// anon namespace
class
DecryptVerifyCommand
::
Private
:
public
QObject
{
Q_OBJECT
friend
class
::
Kleo
::
DecryptVerifyCommand
;
DecryptVerifyCommand
*
const
q
;
public
:
explicit
Private
(
DecryptVerifyCommand
*
qq
)
:
QObject
(),
q
(
qq
),
wizard
(),
inputList
(),
m_statusSent
(
0U
),
m_error
(
0U
)
{
}
~
Private
()
{
delete
wizard
;
}
std
::
vector
<
shared_ptr
<
Input
>
>
buildInputList
();
static
shared_ptr
<
Input
>
inputFromOperationWidget
(
const
DecryptVerifyOperationWidget
*
w
,
const
shared_ptr
<
QFile
>
&
file
,
const
QDir
&
outDir
);
void
startJobs
();
void
trySendingStatus
(
const
char
*
tag
,
const
QString
&
str
)
{
// ### FIXME: make AssuanCommand::sendStatus() throw the exception
if
(
const
int
err
=
q
->
sendStatus
(
tag
,
str
)
)
throw
assuan_exception
(
err
,
i18n
(
"Problem writing out verification status."
)
);
}
QString
signatureToString
(
const
Signature
&
sig
,
const
Key
&
key
)
const
;
void
createWizard
()
{
if
(
wizard
)
return
;
wizard
=
q
->
applyWindowID
(
new
DecryptVerifyWizard
);
connect
(
wizard
,
SIGNAL
(
finished
(
int
)),
this
,
SLOT
(
slotDialogClosed
())
);
//if ( requestedWindowTitle().isEmpty() )
wizard
->
setWindowTitle
(
i18n
(
"Decrypt/Verify Wizard"
)
);
//else
// wizard->setWindowTitle( i18n("Decrypt/Verify Wizard: %1", requestedWindowTitle() ) );
}
void
showWizard
()
{
if
(
wizard
)
{
if
(
!
wizard
->
isVisible
()
)
wizard
->
show
();
wizard
->
raise
();
}
}
public
Q_SLOTS
:
void
finished
();
void
slotProgress
(
const
QString
&
what
,
int
current
,
int
total
);
public
:
void
registerJob
(
int
id
,
VerifyDetachedJob
*
job
)
{
connect
(
job
,
SIGNAL
(
result
(
GpgME
::
VerificationResult
)),
this
,
SLOT
(
slotVerifyDetachedResult
(
GpgME
::
VerificationResult
))
);
m_senderToId
[
job
]
=
id
;
}
void
registerJob
(
int
id
,
VerifyOpaqueJob
*
job
)
{
connect
(
job
,
SIGNAL
(
result
(
GpgME
::
VerificationResult
,
QByteArray
)),
this
,
SLOT
(
slotVerifyOpaqueResult
(
GpgME
::
VerificationResult
,
QByteArray
))
);
m_senderToId
[
job
]
=
id
;
}
void
registerJob
(
int
id
,
DecryptJob
*
job
)
{
connect
(
job
,
SIGNAL
(
result
(
GpgME
::
DecryptionResult
,
QByteArray
)),
this
,
SLOT
(
slotDecryptResult
(
GpgME
::
DecryptionResult
,
QByteArray
))
);
m_senderToId
[
job
]
=
id
;
}
void
registerJob
(
int
id
,
DecryptVerifyJob
*
job
)
{
connect
(
job
,
SIGNAL
(
result
(
GpgME
::
DecryptionResult
,
GpgME
::
VerificationResult
,
QByteArray
)),
this
,
SLOT
(
slotDecryptVerifyResult
(
GpgME
::
DecryptionResult
,
GpgME
::
VerificationResult
,
QByteArray
))
);
m_senderToId
[
job
]
=
id
;
}
bool
hasError
()
const
{
return
m_error
;
}
unsigned
int
error
()
const
{
return
m_error
;
}
void
addResult
(
unsigned
int
id
,
const
DVResult
&
res
);
private
Q_SLOTS
:
void
slotDialogClosed
()
{
if
(
hasError
()
)
q
->
done
(
error
()
);
else
q
->
done
();
}
void
slotVerifyOpaqueResult
(
const
GpgME
::
VerificationResult
&
result
,
const
QByteArray
&
plainText
)
{
assert
(
m_senderToId
.
contains
(
sender
()
)
);
const
unsigned
int
id
=
m_senderToId
[
sender
()];
addResult
(
id
,
DVResult
::
fromVerifyOpaqueResult
(
result
,
plainText
)
);
}
void
slotVerifyDetachedResult
(
const
GpgME
::
VerificationResult
&
result
)
{
assert
(
m_senderToId
.
contains
(
sender
()
)
);
const
unsigned
int
id
=
m_senderToId
[
sender
()];
addResult
(
id
,
DVResult
::
fromVerifyDetachedResult
(
result
)
);
}
void
slotDecryptResult
(
const
GpgME
::
DecryptionResult
&
result
,
const
QByteArray
&
plainText
)
{
assert
(
m_senderToId
.
contains
(
sender
()
)
);
const
unsigned
int
id
=
m_senderToId
[
sender
()];
addResult
(
id
,
DVResult
::
fromDecryptResult
(
result
,
plainText
)
);
}
void
slotDecryptVerifyResult
(
const
GpgME
::
DecryptionResult
&
dr
,
const
GpgME
::
VerificationResult
&
vr
,
const
QByteArray
&
plainText
)
{
assert
(
m_senderToId
.
contains
(
sender
()
)
);
const
unsigned
int
id
=
m_senderToId
[
sender
()];
addResult
(
id
,
DVResult
::
fromDecryptVerifyResult
(
dr
,
vr
,
plainText
)
);
}
private
:
QPointer
<
DecryptVerifyWizard
>
wizard
;
std
::
vector
<
shared_ptr
<
Input
>
>
inputList
;
QHash
<
QObject
*
,
unsigned
int
>
m_senderToId
;
unsigned
int
m_statusSent
;
unsigned
int
m_error
;
};
DecryptVerifyCommand
::
DecryptVerifyCommand
()
:
AssuanCommandMixin
<
DecryptVerifyCommand
>
(),
d
(
new
Private
(
this
)
)
{
}
DecryptVerifyCommand
::~
DecryptVerifyCommand
()
{}
int
DecryptVerifyCommand
::
doStart
()
{
d
->
inputList
=
d
->
buildInputList
();
if
(
d
->
inputList
.
empty
()
)
throw
assuan_exception
(
makeError
(
GPG_ERR_ASS_NO_INPUT
),
i18n
(
"No usable inputs found"
)
);
try
{
d
->
startJobs
();
return
0
;
}
catch
(
...
)
{
//d->showWizard();
throw
;
}
}
void
DecryptVerifyCommand
::
doCanceled
()
{}
std
::
vector
<
shared_ptr
<
Input
>
>
DecryptVerifyCommand
::
Private
::
buildInputList
()
{
if
(
!
q
->
senders
().
empty
()
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CONFLICT
),
i18n
(
"Can't use SENDER"
)
);
if
(
!
q
->
recipients
().
empty
()
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CONFLICT
),
i18n
(
"Can't use RECIPIENT"
)
);
const
unsigned
int
numInputs
=
q
->
numBulkInputDevices
();
const
unsigned
int
numMessages
=
q
->
numBulkMessageDevices
();
const
unsigned
int
numOutputs
=
q
->
numBulkOutputDevices
();
const
unsigned
int
op
=
q
->
operation
();
const
Mode
mode
=
q
->
mode
();
const
GpgME
::
Protocol
proto
=
q
->
checkProtocol
(
mode
);
const
unsigned
int
numFiles
=
q
->
numFiles
();
assuan_assert
(
op
!=
0
);
std
::
vector
<
shared_ptr
<
Input
>
>
inputs
;
if
(
mode
==
EMail
)
{
if
(
numFiles
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CONFLICT
),
i18n
(
"FILES present"
)
);
if
(
!
numInputs
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_ASS_NO_INPUT
),
i18n
(
"At least one INPUT needs to be provided"
)
);
if
(
numMessages
)
if
(
numMessages
!=
numInputs
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_ASS_NO_INPUT
),
//TODO use better error code if possible
i18n
(
"INPUT/MESSAGE count mismatch"
)
);
else
if
(
op
!=
VerifyImplied
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CONFLICT
),
i18n
(
"MESSAGE can only be given for detached signature verification"
)
);
if
(
numOutputs
)
if
(
numOutputs
!=
numInputs
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_ASS_NO_OUTPUT
),
//TODO use better error code if possible
i18n
(
"INPUT/OUTPUT count mismatch"
)
);
else
if
(
numMessages
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CONFLICT
),
i18n
(
"Can't use OUTPUT and MESSAGE simultaneously"
)
);
assuan_assert
(
proto
!=
UnknownProtocol
);
const
CryptoBackend
::
Protocol
*
const
backend
=
CryptoBackendFactory
::
instance
()
->
protocol
(
proto
);
if
(
!
backend
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_UNSUPPORTED_PROTOCOL
),
proto
==
OpenPGP
?
i18n
(
"No backend support for OpenPGP"
)
:
proto
==
CMS
?
i18n
(
"No backend support for S/MIME"
)
:
QString
()
);
Type
type
;
if
(
numMessages
)
type
=
VerifyDetached
;
else
if
(
(
op
&
DecryptMask
)
==
DecryptOff
)
type
=
VerifyOpaque
;
else
if
(
(
op
&
VerifyMask
)
==
VerifyOff
)
type
=
Decrypt
;
else
type
=
DecryptVerify
;
for
(
unsigned
int
i
=
0
;
i
<
numInputs
;
++
i
)
{
shared_ptr
<
Input
>
input
(
new
Input
);
input
->
type
=
type
;
input
->
input
.
io
=
q
->
bulkInputDevice
(
i
);
input
->
input
.
fileName
=
q
->
bulkInputDeviceFileName
(
i
);
assuan_assert
(
input
->
input
.
io
);
if
(
type
==
VerifyDetached
)
{
input
->
signedData
.
io
=
q
->
bulkInputDevice
(
i
);
input
->
signedData
.
fileName
=
q
->
bulkInputDeviceFileName
(
i
);
assuan_assert
(
input
->
signedData
.
io
);
}
if
(
numOutputs
)
{
input
->
output
.
io
=
q
->
bulkOutputDevice
(
i
);
input
->
output
.
fileName
=
q
->
bulkOutputDeviceFileName
(
i
);
assuan_assert
(
input
->
output
.
io
);
}
input
->
backend
=
backend
;
inputs
.
push_back
(
input
);
}
}
else
{
if
(
numInputs
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CONFLICT
),
i18n
(
"INPUT present"
)
);
if
(
numMessages
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CONFLICT
),
i18n
(
"MESSAGE present"
)
);
if
(
numOutputs
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CONFLICT
),
i18n
(
"OUTPUT present"
)
);
createWizard
();
std
::
vector
<
shared_ptr
<
QFile
>
>
files
;
unsigned
int
counter
=
0
;
Q_FOREACH
(
const
shared_ptr
<
QFile
>
&
file
,
q
->
files
()
)
{
assuan_assert
(
file
);
const
QString
fname
=
file
->
fileName
();
assuan_assert
(
!
fname
.
isEmpty
()
);
const
unsigned
int
classification
=
classify
(
fname
);
if
(
mayBeOpaqueSignature
(
classification
)
||
mayBeCipherText
(
classification
)
)
{
DecryptVerifyOperationWidget
*
const
op
=
wizard
->
operationWidget
(
counter
++
);
assuan_assert
(
op
!=
0
);
op
->
setMode
(
DecryptVerifyOperationWidget
::
DecryptVerifyOpaque
);
op
->
setInputFileName
(
fname
);
op
->
setSignedDataFileName
(
QString
()
);
files
.
push_back
(
file
);
}
else
if
(
mayBeDetachedSignature
(
classification
)
)
{
// heuristics say it's a detached signature
DecryptVerifyOperationWidget
*
const
op
=
wizard
->
operationWidget
(
counter
++
);
assuan_assert
(
op
!=
0
);
op
->
setMode
(
DecryptVerifyOperationWidget
::
VerifyDetachedWithSignature
);
op
->
setInputFileName
(
fname
);
op
->
setSignedDataFileName
(
findSignedData
(
fname
)
);
files
.
push_back
(
file
);
}
else
{
// probably the signed data file was selected:
QStringList
signatures
=
findSignatures
(
fname
);
if
(
signatures
.
empty
()
)
signatures
.
push_back
(
QString
()
);
Q_FOREACH
(
const
QString
s
,
signatures
)
{
DecryptVerifyOperationWidget
*
op
=
wizard
->
operationWidget
(
counter
++
);
assuan_assert
(
op
!=
0
);
op
->
setMode
(
DecryptVerifyOperationWidget
::
VerifyDetachedWithSignedData
);
op
->
setInputFileName
(
s
);
op
->
setSignedDataFileName
(
fname
);
files
.
push_back
(
file
);
}
}
}
assuan_assert
(
counter
==
files
.
size
()
);
if
(
!
counter
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_ASS_NO_INPUT
),
i18n
(
"No usable inputs found"
)
);
wizard
->
setOutputDirectory
(
q
->
heuristicBaseDirectory
()
);
showWizard
();
if
(
!
wizard
->
waitForOperationSelection
()
)
throw
assuan_exception
(
q
->
makeError
(
GPG_ERR_CANCELED
),
i18n
(
"Confirmation dialog canceled"
)
);
const
QFileInfo
outDirInfo
(
wizard
->
outputDirectory
()
);
assuan_assert
(
outDirInfo
.
isDir
()
);
const
QDir
outDir
(
outDirInfo
.
absoluteFilePath
()
);
assuan_assert
(
outDir
.
exists
()
);
for
(
unsigned
int
i
=
0
;
i
<
counter
;
++
i
)
try
{
inputs
.
push_back
(
inputFromOperationWidget
(
wizard
->
operationWidget
(
i
),
files
[
i
],
outDir
)
);
}
catch
(
const
GpgME
::
Exception
&
e
)
{
//addResult( DVResult::fromDecryptVerifyResult( e.error(), e.what(), i ) );
}
}
return
inputs
;
}
static
const
CryptoBackend
::
Protocol
*
backendFor
(
const
QString
&
str
)
{
return
CryptoBackendFactory
::
instance
()
->
protocol
(
findProtocol
(
str
)
);
}
// static
shared_ptr
<
Input
>
DecryptVerifyCommand
::
Private
::
inputFromOperationWidget
(
const
DecryptVerifyOperationWidget
*
w
,
const
shared_ptr
<
QFile
>
&
file
,
const
QDir
&
outDir
)
{
assuan_assert
(
w
);
shared_ptr
<
Input
>
input
(
new
Input
);
switch
(
w
->
mode
()
)
{
case
DecryptVerifyOperationWidget
::
VerifyDetachedWithSignature
:
input
->
type
=
VerifyDetached
;
input
->
input
=
Input
::
fromOpenFile
(
file
);
input
->
signedData
=
Input
::
openExistingFile
(
w
->
signedDataFileName
()
);
assuan_assert
(
file
->
fileName
()
==
w
->
inputFileName
()
);
break
;
case
DecryptVerifyOperationWidget
::
VerifyDetachedWithSignedData
:
input
->
type
=
VerifyDetached
;
input
->
input
=
Input
::
openExistingFile
(
w
->
inputFileName
()
);
input
->
signedData
=
Input
::
fromOpenFile
(
file
);
assuan_assert
(
file
->
fileName
()
==
w
->
signedDataFileName
()
);
break
;
case
DecryptVerifyOperationWidget
::
DecryptVerifyOpaque
:
input
->
type
=
DecryptVerify
;
input
->
input
=
Input
::
fromOpenFile
(
file
);
input
->
output
=
Input
::
makeTemporaryOutput
(
outDir
.
absoluteFilePath
(
QFileInfo
(
file
->
fileName
()
).
fileName
()
)
);
assuan_assert
(
file
->
fileName
()
==
w
->
inputFileName
()
);
break
;
}
input
->
backend
=
backendFor
(
input
->
input
.
fileName
);
return
input
;
}
void
DecryptVerifyCommand
::
Private
::
startJobs
()
{
assuan_assert
(
!
inputList
.
empty
()
);
unsigned
int
i
=
0
;
Q_FOREACH
(
shared_ptr
<
Input
>
input
,
inputList
)
{
assuan_assert
(
input
->
backend
);
switch
(
input
->
type
)
{
case
Decrypt
:
try
{
DecryptJob
*
const
job
=
input
->
backend
->
decryptJob
();
assuan_assert
(
job
);
registerJob
(
i
,
job
);
job
->
start
(
input
->
input
.
io
,
input
->
output
.
io
);
}
catch
(
const
GpgME
::
Exception
&
e
)
{
addResult
(
i
,
DVResult
::
fromDecryptResult
(
e
.
error
()
)
);
}
break
;
case
DecryptVerify
:
try
{
DecryptVerifyJob
*
const
job
=
input
->
backend
->
decryptVerifyJob
();
assuan_assert
(
job
);
registerJob
(
i
,
job
);
job
->
start
(
input
->
input
.
io
,
input
->
output
.
io
);
}
catch
(
const
GpgME
::
Exception
&
e
)
{
addResult
(
i
,
DVResult
::
fromDecryptVerifyResult
(
e
.
error
()
)
);
}
break
;
case
VerifyOpaque
:
try
{
VerifyOpaqueJob
*
const
job
=
input
->
backend
->
verifyOpaqueJob
();
assuan_assert
(
job
);
registerJob
(
i
,
job
);
job
->
start
(
input
->
input
.
io
,
input
->
output
.
io
);
}
catch
(
const
GpgME
::
Exception
&
e
)
{
addResult
(
i
,
DVResult
::
fromVerifyOpaqueResult
(
e
.
error
()
)
);
}
break
;
case
VerifyDetached
:
try
{
VerifyDetachedJob
*
const
job
=
input
->
backend
->
verifyDetachedJob
();
assuan_assert
(
job
);
registerJob
(
i
,
job
);
job
->
start
(
input
->
input
.
io
,
input
->
signedData
.
io
);
}
catch
(
const
GpgME
::
Exception
&
e
)
{
addResult
(
i
,
DVResult
::
fromVerifyDetachedResult
(
e
.
error
()
)
);
}
break
;
}
++
i
;
}
}
static
QString
summaryToString
(
const
Signature
::
Summary
summary
)
{
if
(
summary
&
Signature
::
Green
)
return
"GREEN"
;
else
if
(
summary
&
Signature
::
Red
)
return
"RED"
;
else
return
"YELLOW"
;
}
static
QString
keyToString
(
const
Key
&
key
)
{
assuan_assert
(
!
key
.
isNull
()
);
const
QString
email
=
Formatting
::
prettyEMail
(
key
);
const
QString
name
=
Formatting
::
prettyName
(
key
);
if
(
name
.
isEmpty
()
)
return
email
;
else
if
(
email
.
isEmpty
()
)
return
name
;
else
return
QString
::
fromLatin1
(
"%1 <%2>"
).
arg
(
name
,
email
);
}
QString
DecryptVerifyCommand
::
Private
::
signatureToString
(
const
Signature
&
sig
,
const
Key
&
key
)
const
{
if
(
sig
.
isNull
()
)
return
QString
();
const
bool
red
=
(
sig
.
summary
()
&
Signature
::
Red
);
const
bool
green
=
(
sig
.
summary
()
&
Signature
::
Green
);
const
bool
valid
=
(
sig
.
summary
()
&
Signature
::
Valid
);
if
(
red
)
if
(
key
.
isNull
()
)
if
(
const
char
*
fpr
=
sig
.
fingerprint
()
)
return
"RED "
+
i18n
(
"Bad signature by unknown key %1: %2"
,
QString
::
fromLatin1
(
fpr
),
QString
::
fromLocal8Bit
(
sig
.
status
().
asString
()
)
);
else
return
"RED "
+
i18n
(
"Bad signature by an unknown key: %1"
,
QString
::
fromLocal8Bit
(
sig
.
status
().
asString
()
)
);
else
return
"RED "
+
i18n
(
"Bad signature by %1: %2"
,
keyToString
(
key
),
QString
::
fromLocal8Bit
(
sig
.
status
().
asString
()
)
);
else
if
(
valid
)
if
(
key
.
isNull
()
)
if
(
const
char
*
fpr
=
sig
.
fingerprint
()
)
return
(
green
?
"GREEN "
:
"YELLOW "
)
+
i18n
(
"Good signature by unknown key %1."
,
QString
::
fromLatin1
(
fpr
)
);
else
return
(
green
?
"GREEN "
:
"YELLOW "
)
+
i18n
(
"Good signature by an unknown key."
);
else
return
(
green
?
"GREEN "
:
"YELLOW "
)
+
i18n
(
"Good signature by %1."
,
keyToString
(
key
)
);
else
if
(
key
.
isNull
()
)
if
(
const
char
*
fpr
=
sig
.
fingerprint
()
)
return
"YELLOW "
+
i18n
(
"Invalid signature by unknown key %1: %2"
,
QString
::
fromLatin1
(
fpr
),
QString
::
fromLocal8Bit
(
sig
.
status
().
asString
()
)
);
else
return
"YELLOW "
+
i18n
(
"Invalid signature by an unknown key: %1"
,
QString
::
fromLocal8Bit
(
sig
.
status
().
asString
()
)
);
else
return
"YELLOW "
+
i18n
(
"Invalid signature by %1: %2"
,
keyToString
(
key
),
QString
::
fromLocal8Bit
(
sig
.
status
().
asString
()
)
);
}
static
QStringList
labels
(
const
std
::
vector
<
shared_ptr
<
Input
>
>
&
inputList
)
{
QStringList
labels
;
for
(
unsigned
int
i
=
0
,
end
=
inputList
.
size
()
;
i
<
end
;
++
i
)
{
const
shared_ptr
<
Input
>
&
input
=
inputList
[
i
];
switch
(
input
->
type
)
{
case
Decrypt
:
case
DecryptVerify
:
labels
.
push_back
(
input
->
input
.
fileName
.
isEmpty
()
?
i18n
(
"Decrypting message #%1..."
,
i
)
:
i18n
(
"Decrypting file %1..."
,
input
->
input
.
fileName
)
);
break
;
case
VerifyOpaque
:
labels
.
push_back
(
input
->
input
.
fileName
.
isEmpty
()
?
i18n
(
"Verifying message #%1..."
,
i
)
:
i18n
(
"Verifying file %1..."
,
input
->
input
.
fileName
)
);
break
;
case
VerifyDetached
:
labels
.
push_back
(
input
->
input
.
fileName
.
isEmpty
()
?
i18n
(
"Verifying message #%1..."
,
i
)
:
i18n
(
"Verifying signature %1..."
,
input
->
input
.
fileName
)
);
break
;
}
}
return
labels
;
}
void
DecryptVerifyCommand
::
Private
::
slotProgress
(
const
QString
&
what
,
int
current
,
int
total
)
{
// FIXME report progress, via sendStatus()
}
void
DecryptVerifyCommand
::
Private
::
addResult
(
unsigned
int
id
,
const
DVResult
&
res
)
{
assert
(
!
inputList
[
id
]
->
result
);
inputList
[
id
]
->
result
.
reset
(
new
DVResult
(
res
)
);
// send status for all results received so far, but in order of id
while
(
m_statusSent
<
inputList
.
size
()
)
{
const
shared_ptr
<
DVResult
>
result
=
inputList
[
m_statusSent
]
->
result
;
if
(
!
result
)
break
;
const
VerificationResult
&
vResult
=
result
->
verificationResult
;
const
DecryptionResult
&
dResult
=
result
->
decryptionResult
;
if
(
dResult
.
error
().
code
()
)
result
->
error
=
dResult
.
error
();
else
if
(
vResult
.
error
().
code
()
)
result
->
error
=
vResult
.
error
();
if
(
!
result
->
error
)
try
{
try
{
inputList
[
id
]
->
finalizeOutput
(
q
->
hasOption
(
"silent"
)
);
}
catch
(
const
assuan_exception
&
e
)
{
// record these errors, but ignore them:
result
->
error
=
e
.
error_code
();
result
->
errorString
=
e
.
message
();
}
if
(
!
vResult
.
isNull
()
)
{
const
std
::
vector
<
Signature
>
sigs
=
vResult
.
signatures
();
assuan_assert
(
!
sigs
.
empty
()
);
const
std
::
vector
<
Key
>
signers
=
KeyCache
::
instance
()
->
findSigners
(
vResult
);
Q_FOREACH
(
const
Signature
&
sig
,
sigs
)
{
const
QString
s
=
signatureToString
(
sig
,
keyForSignature
(
sig
,
signers
)
);
trySendingStatus
(
"SIGSTATUS"
,
s
);
}
}
}
catch
(
const
assuan_exception
&
e
)
{
result
->
error
=
e
.
error_code
();
result
->
errorString
=
e
.
message
();
// FIXME ask to continue or cancel
}
wizard
->
resultWidget
(
m_statusSent
)
->
setResult
(
result
->
decryptionResult
,
result
->
verificationResult
);
m_statusSent
++
;
if
(
result
->
error
&&
!
m_error
)
m_error
=
result
->
error
;
}
if
(
kdtools
::
all
(
inputList
.
begin
(),
inputList
.
end
(),
bind
(
&
Input
::
result
,
_1
)
)
)
finished
();
}
void
DecryptVerifyCommand
::
Private
::
finished
()
{
if
(
q
->
hasOption
(
"silent"
)
)
//otherwise we'll be ending when the dialog closes
slotDialogClosed
();
}
static
bool
obtainOverwritePermission
(
const
QString
&
fileName
)
{
return
KMessageBox
::
questionYesNo
(
0
,
i18n
(
"The file <b>%1</b> already exists.
\n
"
"Overwrite?"
,
fileName
),
i18n
(
"Overwrite Existing File?"
)
)
==
KMessageBox
::
Yes
;
}
void
Input
::
finalizeOutput
(
bool
silent
)
{
if
(
!
output
.
tmp
)
return
;
assuan_assert
(
output
.
tmp
->
isOpen
()
);
output
.
tmp
->
flush
();
const
QString
tmpFileName
=
output
.
tmp
->
fileName
();
output
.
tmp
->
close
();
bool
overwrite
=
false
;
static
const
int
maxtries
=
5
;
for
(
int
i
=
0
;
i
<
maxtries
;
++
i
)
{
if
(
QFile
::
rename
(
tmpFileName
,
output
.
fileName
)
)
{
output
.
tmp
->
setAutoRemove
(
false
);
return
;
}
const
int
savedErrno
=
errno
;
if
(
overwrite
||
!
silent
&&
(
overwrite
=
obtainOverwritePermission
(
output
.
fileName
)
)
)
QFile
::
remove
(
output
.
fileName
);
else
throw
assuan_exception
(
gpg_error_from_errno
(
savedErrno
),
i18n
(
"Couldn't rename file
\"
%1
\"
to
\"
%2
\"
"
,
tmpFileName
,
output
.
fileName
)
);
}
}
#include
"decryptverifycommand.moc"
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Thu, Mar 19, 6:02 PM (2 h, 15 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ab/cb/b00c04421f0aa4c867393a2c21f1
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment