You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
736 lines
25 KiB
736 lines
25 KiB
/* |
|
* This file is part of KMail. |
|
* Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com> |
|
* |
|
* Parts based on KMail code by: |
|
* Various authors. |
|
* |
|
* This program 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. |
|
* |
|
* This program 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. |
|
*/ |
|
|
|
#include "attachmentcontroller.h" |
|
|
|
#include "attachmentmodel.h" |
|
#include "attachmentview.h" |
|
#include "attachmentfrompublickeyjob.h" |
|
#include "messageviewer/editorwatcher.h" |
|
#include "globalsettings.h" |
|
#include "kmkernel.h" |
|
#include "kmcomposewin.h" |
|
#include "kmcommands.h" |
|
#include "foldercollection.h" |
|
|
|
#include <akonadi/itemfetchjob.h> |
|
#include <kio/jobuidelegate.h> |
|
|
|
#include <QMenu> |
|
#include <QPointer> |
|
|
|
#include <KAction> |
|
#include <KActionCollection> |
|
#include <KDebug> |
|
#include <KEncodingFileDialog> |
|
#include <KFileDialog> |
|
#include <KLocalizedString> |
|
#include <KMessageBox> |
|
#include <KMimeTypeTrader> |
|
#include <KPushButton> |
|
#include <KRun> |
|
#include <KTemporaryFile> |
|
|
|
#include "kmreadermainwin.h" |
|
#include <kpimutils/kfileio.h> |
|
|
|
#include <libkleo/kleo/cryptobackendfactory.h> |
|
#include <libkleo/ui/keyselectiondialog.h> |
|
|
|
#include <messagecore/attachmentcompressjob.h> |
|
#include <messagecore/attachmentfrommimecontentjob.h> |
|
#include <messagecore/attachmentfromurljob.h> |
|
#include <messagecore/attachmentpropertiesdialog.h> |
|
|
|
using namespace KMail; |
|
using namespace KPIM; |
|
|
|
class KMail::AttachmentController::Private |
|
{ |
|
public: |
|
Private( AttachmentController *qq ); |
|
~Private(); |
|
|
|
void identityChanged(); // slot |
|
void selectionChanged(); // slot |
|
void attachmentRemoved( AttachmentPart::Ptr part ); // slot |
|
void compressJobResult( KJob *job ); // slot |
|
void loadJobResult( KJob *job ); // slot |
|
void openSelectedAttachments(); // slot |
|
void viewSelectedAttachments(); // slot |
|
void editSelectedAttachment(); // slot |
|
void editSelectedAttachmentWith(); // slot |
|
void removeSelectedAttachments(); // slot |
|
void saveSelectedAttachmentAs(); // slot |
|
void selectedAttachmentProperties(); // slot |
|
void editDone( MessageViewer::EditorWatcher *watcher ); // slot |
|
void exportPublicKey( const QString &fingerprint ); |
|
void attachPublicKeyJobResult( KJob *job ); // slot |
|
void addAttachmentPart( AttachmentPart::Ptr part ); |
|
|
|
AttachmentController *const q; |
|
bool encryptEnabled; |
|
bool signEnabled; |
|
AttachmentModel *model; |
|
AttachmentView *view; |
|
KMComposeWin *composer; |
|
QHash<MessageViewer::EditorWatcher*,AttachmentPart::Ptr> editorPart; |
|
QHash<MessageViewer::EditorWatcher*,KTemporaryFile*> editorTempFile; |
|
QList<KTemporaryFile*> mAttachmentTempList; |
|
|
|
QMenu *contextMenu; |
|
AttachmentPart::List selectedParts; |
|
QAction *attachPublicKeyAction; |
|
QAction *attachMyPublicKeyAction; |
|
QAction *openContextAction; |
|
QAction *viewContextAction; |
|
QAction *editContextAction; |
|
QAction *editWithContextAction; |
|
QAction *removeAction; |
|
QAction *removeContextAction; |
|
QAction *saveAsAction; |
|
QAction *saveAsContextAction; |
|
QAction *propertiesAction; |
|
QAction *propertiesContextAction; |
|
QAction *addAction; |
|
QAction *addContextAction; |
|
|
|
// If part p is compressed, uncompressedParts[p] is the uncompressed part. |
|
QHash<AttachmentPart::Ptr, AttachmentPart::Ptr> uncompressedParts; |
|
}; |
|
|
|
AttachmentController::Private::Private( AttachmentController *qq ) |
|
: q( qq ) |
|
, encryptEnabled( false ) |
|
, signEnabled( false ) |
|
, model( 0 ) |
|
, view( 0 ) |
|
, composer( 0 ) |
|
, contextMenu( 0 ) |
|
, attachPublicKeyAction( 0 ) |
|
, attachMyPublicKeyAction( 0 ) |
|
, openContextAction( 0 ) |
|
, viewContextAction( 0 ) |
|
, editContextAction( 0 ) |
|
, editWithContextAction( 0 ) |
|
, removeAction( 0 ) |
|
, removeContextAction( 0 ) |
|
, saveAsAction( 0 ) |
|
, saveAsContextAction( 0 ) |
|
, propertiesAction( 0 ) |
|
, propertiesContextAction( 0 ) |
|
, addAction( 0 ) |
|
, addContextAction( 0 ) |
|
{ |
|
} |
|
|
|
AttachmentController::Private::~Private() |
|
{ |
|
qDeleteAll( mAttachmentTempList ); |
|
} |
|
|
|
void AttachmentController::Private::identityChanged() |
|
{ |
|
const KPIMIdentities::Identity &identity = composer->identity(); |
|
|
|
// "Attach public key" is only possible if OpenPGP support is available: |
|
attachPublicKeyAction->setEnabled( |
|
Kleo::CryptoBackendFactory::instance()->openpgp() ); |
|
|
|
// "Attach my public key" is only possible if OpenPGP support is |
|
// available and the user specified his key for the current identity: |
|
attachMyPublicKeyAction->setEnabled( |
|
Kleo::CryptoBackendFactory::instance()->openpgp() && !identity.pgpEncryptionKey().isEmpty() ); |
|
} |
|
|
|
void AttachmentController::Private::selectionChanged() |
|
{ |
|
const QModelIndexList selectedRows = view->selectionModel()->selectedRows(); |
|
selectedParts.clear(); |
|
foreach( const QModelIndex &index, selectedRows ) { |
|
AttachmentPart::Ptr part = view->model()->data( |
|
index, AttachmentModel::AttachmentPartRole ).value<AttachmentPart::Ptr>(); |
|
selectedParts.append( part ); |
|
} |
|
const int selectedCount = selectedParts.count(); |
|
|
|
openContextAction->setEnabled( selectedCount > 0 ); |
|
viewContextAction->setEnabled( selectedCount > 0 ); |
|
editContextAction->setEnabled( selectedCount == 1 ); |
|
editWithContextAction->setEnabled( selectedCount == 1 ); |
|
removeAction->setEnabled( selectedCount > 0 ); |
|
removeContextAction->setEnabled( selectedCount > 0 ); |
|
saveAsAction->setEnabled( selectedCount == 1 ); |
|
saveAsContextAction->setEnabled( selectedCount == 1 ); |
|
propertiesAction->setEnabled( selectedCount == 1 ); |
|
propertiesContextAction->setEnabled( selectedCount == 1 ); |
|
} |
|
|
|
void AttachmentController::Private::attachmentRemoved( AttachmentPart::Ptr part ) |
|
{ |
|
if( uncompressedParts.contains( part ) ) { |
|
uncompressedParts.remove( part ); |
|
} |
|
} |
|
|
|
void AttachmentController::Private::compressJobResult( KJob *job ) |
|
{ |
|
if( job->error() ) { |
|
KMessageBox::sorry( composer, job->errorString(), i18n( "Failed to compress attachment" ) ); |
|
return; |
|
} |
|
|
|
Q_ASSERT( dynamic_cast<AttachmentCompressJob*>( job ) ); |
|
AttachmentCompressJob *ajob = static_cast<AttachmentCompressJob*>( job ); |
|
//AttachmentPart *originalPart = const_cast<AttachmentPart*>( ajob->originalPart() ); |
|
AttachmentPart::Ptr originalPart = ajob->originalPart(); |
|
AttachmentPart::Ptr compressedPart = ajob->compressedPart(); |
|
|
|
if( ajob->isCompressedPartLarger() ) { |
|
const int result = KMessageBox::questionYesNo( composer, |
|
i18n( "The compressed attachment is larger than the original. " |
|
"Do you want to keep the original one?" ), |
|
QString( /*caption*/ ), |
|
KGuiItem( i18nc( "Do not compress", "Keep" ) ), |
|
KGuiItem( i18n( "Compress" ) ) ); |
|
if( result == KMessageBox::Yes ) { |
|
// The user has chosen to keep the uncompressed file. |
|
return; |
|
} |
|
} |
|
|
|
kDebug() << "Replacing uncompressed part in model."; |
|
uncompressedParts[ compressedPart ] = originalPart; |
|
bool ok = model->replaceAttachment( originalPart, compressedPart ); |
|
if( !ok ) { |
|
// The attachment was removed from the model while we were compressing. |
|
kDebug() << "Compressed a zombie."; |
|
} |
|
} |
|
|
|
void AttachmentController::Private::loadJobResult( KJob *job ) |
|
{ |
|
if( job->error() ) { |
|
KMessageBox::sorry( composer, job->errorString(), i18n( "Failed to attach file" ) ); |
|
return; |
|
} |
|
|
|
Q_ASSERT( dynamic_cast<AttachmentFromUrlJob*>( job ) ); |
|
AttachmentFromUrlJob *ajob = static_cast<AttachmentFromUrlJob*>( job ); |
|
AttachmentPart::Ptr part = ajob->attachmentPart(); |
|
q->addAttachment( part ); |
|
} |
|
|
|
void AttachmentController::Private::openSelectedAttachments() |
|
{ |
|
Q_ASSERT( selectedParts.count() >= 1 ); |
|
foreach( AttachmentPart::Ptr part, selectedParts ) { |
|
q->openAttachment( part ); |
|
} |
|
} |
|
|
|
void AttachmentController::Private::viewSelectedAttachments() |
|
{ |
|
Q_ASSERT( selectedParts.count() >= 1 ); |
|
foreach( AttachmentPart::Ptr part, selectedParts ) { |
|
q->viewAttachment( part ); |
|
} |
|
} |
|
|
|
void AttachmentController::Private::editSelectedAttachment() |
|
{ |
|
Q_ASSERT( selectedParts.count() == 1 ); |
|
q->editAttachment( selectedParts.first(), false /*openWith*/ ); |
|
// TODO nicer api would be enum { OpenWithDialog, NoOpenWithDialog } |
|
} |
|
|
|
void AttachmentController::Private::editSelectedAttachmentWith() |
|
{ |
|
Q_ASSERT( selectedParts.count() == 1 ); |
|
q->editAttachment( selectedParts.first(), true /*openWith*/ ); |
|
} |
|
|
|
void AttachmentController::Private::removeSelectedAttachments() |
|
{ |
|
Q_ASSERT( selectedParts.count() >= 1 ); |
|
foreach( AttachmentPart::Ptr part, selectedParts ) { |
|
model->removeAttachment( part ); |
|
} |
|
} |
|
|
|
void AttachmentController::Private::saveSelectedAttachmentAs() |
|
{ |
|
Q_ASSERT( selectedParts.count() == 1 ); |
|
q->saveAttachmentAs( selectedParts.first() ); |
|
} |
|
|
|
void AttachmentController::Private::selectedAttachmentProperties() |
|
{ |
|
Q_ASSERT( selectedParts.count() == 1 ); |
|
q->attachmentProperties( selectedParts.first() ); |
|
} |
|
|
|
void AttachmentController::Private::editDone( MessageViewer::EditorWatcher *watcher ) |
|
{ |
|
AttachmentPart::Ptr part = editorPart.take( watcher ); |
|
Q_ASSERT( part ); |
|
KTemporaryFile *tempFile = editorTempFile.take( watcher ); |
|
Q_ASSERT( tempFile ); |
|
|
|
if( watcher->fileChanged() ) { |
|
kDebug() << "File has changed."; |
|
|
|
// Read the new data and update the part in the model. |
|
tempFile->reset(); |
|
QByteArray data = tempFile->readAll(); |
|
part->setData( data ); |
|
model->updateAttachment( part ); |
|
} |
|
|
|
delete tempFile; |
|
// The watcher deletes itself. |
|
} |
|
|
|
void AttachmentController::Private::exportPublicKey( const QString &fingerprint ) |
|
{ |
|
if( fingerprint.isEmpty() || !Kleo::CryptoBackendFactory::instance()->openpgp() ) { |
|
kWarning() << "Tried to export key with empty fingerprint, or no OpenPGP."; |
|
Q_ASSERT( false ); // Can this happen? |
|
return; |
|
} |
|
|
|
AttachmentFromPublicKeyJob *ajob = new AttachmentFromPublicKeyJob( fingerprint, q ); |
|
connect( ajob, SIGNAL(result(KJob*)), q, SLOT(attachPublicKeyJobResult(KJob*)) ); |
|
ajob->start(); |
|
} |
|
|
|
void AttachmentController::Private::attachPublicKeyJobResult( KJob *job ) |
|
{ |
|
// The only reason we can't use loadJobResult() and need a separate method |
|
// is that we want to show the proper caption ("public key" instead of "file")... |
|
|
|
if( job->error() ) { |
|
KMessageBox::sorry( composer, job->errorString(), i18n( "Failed to attach public key" ) ); |
|
return; |
|
} |
|
|
|
Q_ASSERT( dynamic_cast<AttachmentFromPublicKeyJob*>( job ) ); |
|
AttachmentFromPublicKeyJob *ajob = static_cast<AttachmentFromPublicKeyJob*>( job ); |
|
AttachmentPart::Ptr part = ajob->attachmentPart(); |
|
q->addAttachment( part ); |
|
} |
|
|
|
|
|
|
|
static KTemporaryFile *dumpAttachmentToTempFile( const AttachmentPart::Ptr part ) // local |
|
{ |
|
KTemporaryFile *file = new KTemporaryFile; |
|
if( !file->open() ) { |
|
kError() << "Could not open tempfile" << file->fileName(); |
|
delete file; |
|
return 0; |
|
} |
|
if( file->write( part->data() ) == -1 ) { |
|
kError() << "Could not dump attachment to tempfile."; |
|
delete file; |
|
return 0; |
|
} |
|
file->flush(); |
|
return file; |
|
} |
|
|
|
|
|
|
|
AttachmentController::AttachmentController( AttachmentModel *model, AttachmentView *view, KMComposeWin *composer ) |
|
: QObject( view ) |
|
, d( new Private( this ) ) |
|
{ |
|
d->view = view; |
|
connect( view, SIGNAL(contextMenuRequested()), this, SLOT(showContextMenu()) ); |
|
connect( view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), |
|
this, SLOT(selectionChanged()) ); |
|
connect( view, SIGNAL(doubleClicked(QModelIndex)), |
|
this, SLOT(editSelectedAttachment()) ); |
|
|
|
d->model = model; |
|
connect( model, SIGNAL(attachUrlsRequested(KUrl::List)), this, SLOT(addAttachments(KUrl::List)) ); |
|
connect( model, SIGNAL(attachItemsRequester(Akonadi::Item::List ) ), this, SLOT( addAttachmentItems( Akonadi::Item::List ) ) ); |
|
connect( model, SIGNAL(attachmentRemoved(KPIM::AttachmentPart::Ptr)), |
|
this, SLOT(attachmentRemoved(KPIM::AttachmentPart::Ptr)) ); |
|
connect( model, SIGNAL(attachmentCompressRequested(KPIM::AttachmentPart::Ptr,bool)), |
|
this, SLOT(compressAttachment(KPIM::AttachmentPart::Ptr,bool)) ); |
|
connect( model, SIGNAL(encryptEnabled(bool)), this, SLOT(setEncryptEnabled(bool)) ); |
|
connect( model, SIGNAL(signEnabled(bool)), this, SLOT(setSignEnabled(bool)) ); |
|
|
|
d->composer = composer; |
|
connect( composer, SIGNAL(identityChanged(KPIMIdentities::Identity)), |
|
this, SLOT(identityChanged()) ); |
|
} |
|
|
|
AttachmentController::~AttachmentController() |
|
{ |
|
delete d; |
|
} |
|
|
|
void AttachmentController::createActions() |
|
{ |
|
// Create the actions. |
|
d->attachPublicKeyAction = new KAction( i18n( "Attach &Public Key..." ), this ); |
|
connect( d->attachPublicKeyAction, SIGNAL(triggered(bool)), |
|
this, SLOT(showAttachPublicKeyDialog()) ); |
|
|
|
d->attachMyPublicKeyAction = new KAction( i18n( "Attach &My Public Key" ), this ); |
|
connect( d->attachMyPublicKeyAction, SIGNAL(triggered(bool)), this, SLOT(attachMyPublicKey()) ); |
|
|
|
d->addAction = new KAction( KIcon( "mail-attachment" ), i18n( "&Attach File..." ), this ); |
|
d->addAction->setIconText( i18n( "Attach" ) ); |
|
d->addContextAction = new KAction( KIcon( "mail-attachment" ), |
|
i18n( "Add Attachment..." ), this ); |
|
connect( d->addAction, SIGNAL(triggered(bool)), this, SLOT(showAddAttachmentDialog()) ); |
|
connect( d->addContextAction, SIGNAL(triggered(bool)), this, SLOT(showAddAttachmentDialog()) ); |
|
|
|
d->removeAction = new KAction( i18n( "&Remove Attachment" ), this ); |
|
d->removeContextAction = new KAction( i18n( "Remove" ), this ); // FIXME need two texts. is there a better way? |
|
connect( d->removeAction, SIGNAL(triggered(bool)), this, SLOT(removeSelectedAttachments()) ); |
|
connect( d->removeContextAction, SIGNAL(triggered(bool)), this, SLOT(removeSelectedAttachments()) ); |
|
|
|
d->openContextAction = new KAction( i18nc( "to open", "Open" ), this ); |
|
connect( d->openContextAction, SIGNAL(triggered(bool)), this, SLOT(openSelectedAttachments()) ); |
|
|
|
d->viewContextAction = new KAction( i18nc( "to view", "View" ), this ); |
|
connect( d->viewContextAction, SIGNAL(triggered(bool)), this, SLOT(viewSelectedAttachments()) ); |
|
|
|
d->editContextAction = new KAction( i18nc( "to edit", "Edit" ), this ); |
|
connect( d->editContextAction, SIGNAL(triggered(bool)), this, SLOT(editSelectedAttachment()) ); |
|
|
|
d->editWithContextAction = new KAction( i18n( "Edit With..." ), this ); |
|
connect( d->editWithContextAction, SIGNAL(triggered(bool)), this, SLOT(editSelectedAttachmentWith()) ); |
|
|
|
d->saveAsAction = new KAction( KIcon( "document-save-as"), |
|
i18n( "&Save Attachment As..." ), this ); |
|
d->saveAsContextAction = new KAction( KIcon( "document-save-as"), |
|
i18n( "Save As..." ), this ); |
|
connect( d->saveAsAction, SIGNAL(triggered(bool)), |
|
this, SLOT(saveSelectedAttachmentAs()) ); |
|
connect( d->saveAsContextAction, SIGNAL(triggered(bool)), |
|
this, SLOT(saveSelectedAttachmentAs()) ); |
|
|
|
d->propertiesAction = new KAction( i18n( "Attachment Pr&operties" ), this ); // TODO why no '...'? |
|
d->propertiesContextAction = new KAction( i18n( "Properties" ), this ); |
|
connect( d->propertiesAction, SIGNAL(triggered(bool)), |
|
this, SLOT(selectedAttachmentProperties()) ); |
|
connect( d->propertiesContextAction, SIGNAL(triggered(bool)), |
|
this, SLOT(selectedAttachmentProperties()) ); |
|
|
|
// Create a context menu for the attachment view. |
|
Q_ASSERT( d->contextMenu == 0 ); // Not called twice. |
|
d->contextMenu = new QMenu( d->composer ); |
|
d->contextMenu->addAction( d->openContextAction ); |
|
d->contextMenu->addAction( d->viewContextAction ); |
|
d->contextMenu->addAction( d->editContextAction ); |
|
d->contextMenu->addAction( d->editWithContextAction ); |
|
d->contextMenu->addAction( d->removeContextAction ); |
|
d->contextMenu->addAction( d->saveAsContextAction ); |
|
d->contextMenu->addAction( d->propertiesContextAction ); |
|
d->contextMenu->addSeparator(); |
|
d->contextMenu->addAction( d->addContextAction ); |
|
|
|
// Insert the actions into the composer window's menu. |
|
KActionCollection *collection = d->composer->actionCollection(); |
|
collection->addAction( "attach_public_key", d->attachPublicKeyAction ); |
|
collection->addAction( "attach_my_public_key", d->attachMyPublicKeyAction ); |
|
collection->addAction( "attach", d->addAction ); |
|
collection->addAction( "remove", d->removeAction ); |
|
collection->addAction( "attach_save", d->saveAsAction ); |
|
collection->addAction( "attach_properties", d->propertiesAction ); |
|
|
|
// Disable public key actions if appropriate. |
|
d->identityChanged(); |
|
|
|
// Disable actions like 'Remove', since nothing is currently selected. |
|
d->selectionChanged(); |
|
} |
|
|
|
void AttachmentController::setEncryptEnabled( bool enabled ) |
|
{ |
|
d->encryptEnabled = enabled; |
|
} |
|
|
|
void AttachmentController::setSignEnabled( bool enabled ) |
|
{ |
|
d->signEnabled = enabled; |
|
} |
|
|
|
void AttachmentController::compressAttachment( AttachmentPart::Ptr part, bool compress ) |
|
{ |
|
if( compress ) { |
|
kDebug() << "Compressing part."; |
|
|
|
AttachmentCompressJob *ajob = new AttachmentCompressJob( part, this ); |
|
connect( ajob, SIGNAL(result(KJob*)), this, SLOT( compressJobResult(KJob*)) ); |
|
ajob->start(); |
|
} else { |
|
kDebug() << "Uncompressing part."; |
|
|
|
// Replace the compressed part with the original uncompressed part, and delete |
|
// the compressed part. |
|
AttachmentPart::Ptr originalPart = d->uncompressedParts.take( part ); |
|
Q_ASSERT( originalPart ); // Found in uncompressedParts. |
|
bool ok = d->model->replaceAttachment( part, originalPart ); |
|
Q_ASSERT( ok ); |
|
} |
|
} |
|
|
|
void AttachmentController::showContextMenu() |
|
{ |
|
d->selectionChanged(); |
|
d->contextMenu->popup( QCursor::pos() ); |
|
} |
|
|
|
void AttachmentController::openAttachment( AttachmentPart::Ptr part ) |
|
{ |
|
KTemporaryFile *tempFile = dumpAttachmentToTempFile( part ); |
|
if( !tempFile ) { |
|
KMessageBox::sorry( d->composer, |
|
i18n( "KMail was unable to write the attachment to a temporary file." ), |
|
i18n( "Unable to open attachment" ) ); |
|
return; |
|
} |
|
|
|
bool success = KRun::runUrl( KUrl::fromPath( tempFile->fileName() ), |
|
part->mimeType(), |
|
d->composer, |
|
true /*tempFile*/, |
|
false /*runExecutables*/ ); |
|
if( !success ) { |
|
if( KMimeTypeTrader::self()->preferredService( part->mimeType() ).isNull() ) { |
|
// KRun showed an Open-With dialog, and it was canceled. |
|
} else { |
|
// KRun failed. |
|
KMessageBox::sorry( d->composer, |
|
i18n( "KMail was unable to open the attachment." ), |
|
i18n( "Unable to open attachment" ) ); |
|
} |
|
delete tempFile; |
|
tempFile = 0; |
|
} else { |
|
// The file was opened. Delete it only when the composer is closed |
|
// (and this object is destroyed). |
|
tempFile->setParent( this ); // Manages lifetime. |
|
} |
|
} |
|
|
|
void AttachmentController::viewAttachment( AttachmentPart::Ptr part ) |
|
{ |
|
QString pname; |
|
pname = part->name().trimmed(); |
|
if( pname.isEmpty() ) { |
|
pname = part->description(); |
|
} |
|
if( pname.isEmpty() ) { |
|
pname = QString::fromLatin1( "unnamed" ); |
|
} |
|
|
|
KTemporaryFile *atmTempFile = new KTemporaryFile(); |
|
atmTempFile->open(); |
|
d->mAttachmentTempList.append( atmTempFile ); |
|
KPIMUtils::kByteArrayToFile( part->/*bodyDecodedBinary()*/data(), atmTempFile->fileName(), |
|
false, false, false ); |
|
KMime::Content *content = new KMime::Content; |
|
content->setContent( part->data() ); |
|
KMReaderMainWin *win = |
|
new KMReaderMainWin( content, false, atmTempFile->fileName(), pname, part->charset() ); |
|
win->show(); |
|
} |
|
|
|
void AttachmentController::editAttachment( AttachmentPart::Ptr part, bool openWith ) |
|
{ |
|
KTemporaryFile *tempFile = dumpAttachmentToTempFile( part ); |
|
if( !tempFile ) { |
|
KMessageBox::sorry( d->composer, |
|
i18n( "KMail was unable to write the attachment to a temporary file." ), |
|
i18n( "Unable to edit attachment" ) ); |
|
return; |
|
} |
|
|
|
MessageViewer::EditorWatcher *watcher = new MessageViewer::EditorWatcher( |
|
KUrl::fromPath( tempFile->fileName() ), |
|
part->mimeType(), openWith, |
|
this, d->composer ); |
|
connect( watcher, SIGNAL(editDone(MessageViewer::EditorWatcher*)), |
|
this, SLOT(editDone(MessageViewer::EditorWatcher*)) ); |
|
|
|
if( watcher->start() ) { |
|
// The attachment is being edited. |
|
// We will clean things up in editDone(). |
|
d->editorPart[ watcher ] = part; |
|
d->editorTempFile[ watcher ] = tempFile; |
|
|
|
// Delete the temp file if the composer is closed (and this object is destroyed). |
|
tempFile->setParent( this ); // Manages lifetime. |
|
} else { |
|
kWarning() << "Could not start EditorWatcher."; |
|
delete watcher; |
|
delete tempFile; |
|
} |
|
} |
|
|
|
void AttachmentController::editAttachmentWith( AttachmentPart::Ptr part ) |
|
{ |
|
editAttachment( part, true ); |
|
} |
|
|
|
void AttachmentController::saveAttachmentAs( AttachmentPart::Ptr part ) |
|
{ |
|
QString pname = part->name(); |
|
if( pname.isEmpty() ) { |
|
pname = "unnamed"; |
|
} |
|
|
|
KUrl url = KFileDialog::getSaveUrl( KUrl( /*startDir*/ ), |
|
QString( /*filter*/ ), d->composer, |
|
i18n( "Save Attachment As" ) ); |
|
|
|
if( url.isEmpty() ) { |
|
kDebug() << "Save Attachment As dialog canceled."; |
|
return; |
|
} |
|
|
|
KMKernel::self()->byteArrayToRemoteFile( part->data(), url ); |
|
} |
|
|
|
void AttachmentController::attachmentProperties( AttachmentPart::Ptr part ) |
|
{ |
|
QPointer<AttachmentPropertiesDialog> dialog = new AttachmentPropertiesDialog( |
|
part, d->composer ); |
|
|
|
dialog->setEncryptEnabled( d->encryptEnabled ); |
|
dialog->setSignEnabled( d->signEnabled ); |
|
|
|
if( dialog->exec() ) { |
|
d->model->updateAttachment( part ); |
|
} |
|
delete dialog; |
|
} |
|
|
|
void AttachmentController::showAddAttachmentDialog() |
|
{ |
|
QPointer<KEncodingFileDialog> dialog = new KEncodingFileDialog( |
|
QString( /*startDir*/ ), QString( /*encoding*/ ), QString( /*filter*/ ), |
|
i18n( "Attach File" ), KFileDialog::Other, d->composer ); |
|
|
|
dialog->okButton()->setGuiItem( KGuiItem( i18n("&Attach"), "document-open") ); |
|
dialog->setMode( KFile::Files ); |
|
if( dialog->exec() == KDialog::Accepted ) { |
|
const KUrl::List files = dialog->selectedUrls(); |
|
foreach( const KUrl &url, files ) { |
|
KUrl urlWithEncoding = url; |
|
urlWithEncoding.setFileEncoding( dialog->selectedEncoding() ); |
|
addAttachment( urlWithEncoding ); |
|
} |
|
} |
|
delete dialog; |
|
} |
|
|
|
void AttachmentController::addAttachment( AttachmentPart::Ptr part ) |
|
{ |
|
part->setEncrypted( d->model->isEncryptSelected() ); |
|
part->setSigned( d->model->isSignSelected() ); |
|
d->model->addAttachment( part ); |
|
|
|
// TODO I can't find this setting in the config dialog. Has it been removed? |
|
if( GlobalSettings::self()->showMessagePartDialogOnAttach() ) { |
|
attachmentProperties( part ); |
|
} |
|
} |
|
|
|
void AttachmentController::addAttachment( const KUrl &url ) |
|
{ |
|
AttachmentFromUrlJob *ajob = new AttachmentFromUrlJob( url, this ); |
|
if( GlobalSettings::maximumAttachmentSize() > 0 ) { |
|
ajob->setMaximumAllowedSize( GlobalSettings::maximumAttachmentSize() * 1024 * 1024 ); |
|
} |
|
connect( ajob, SIGNAL(result(KJob*)), this, SLOT(loadJobResult(KJob*)) ); |
|
ajob->start(); |
|
} |
|
|
|
void AttachmentController::addAttachments( const KUrl::List &urls ) |
|
{ |
|
foreach( const KUrl &url, urls ) { |
|
addAttachment( url ); |
|
} |
|
} |
|
|
|
void AttachmentController::addAttachmentItems( const Akonadi::Item::List &items ) |
|
{ |
|
Akonadi::ItemFetchJob *itemFetchJob = new Akonadi::ItemFetchJob( items, this ); |
|
itemFetchJob->fetchScope().fetchFullPayload( true ); |
|
itemFetchJob->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent ); |
|
connect( itemFetchJob, SIGNAL( result( KJob* ) ), this, SLOT( slotFetchJob( KJob* ) ) ); |
|
} |
|
|
|
void AttachmentController::slotFetchJob( KJob *job ) |
|
{ |
|
if ( job->error() ) { |
|
static_cast<KIO::Job*>(job)->ui()->showErrorMessage(); |
|
return; |
|
} |
|
Akonadi::ItemFetchJob *fjob = dynamic_cast<Akonadi::ItemFetchJob*>( job ); |
|
if ( !fjob ) |
|
return; |
|
Akonadi::Item::List items = fjob->items(); |
|
|
|
uint identity = 0; |
|
if ( items.at( 0 ).isValid() && items.at( 0 ).parentCollection().isValid() ) { |
|
QSharedPointer<FolderCollection> fd( FolderCollection::forCollection( items.at( 0 ).parentCollection() ) ); |
|
identity = fd->identity(); |
|
} |
|
KMCommand *command = new KMForwardAttachedCommand( d->composer, items,identity, d->composer ); |
|
command->start(); |
|
} |
|
|
|
void AttachmentController::showAttachPublicKeyDialog() |
|
{ |
|
using Kleo::KeySelectionDialog; |
|
QPointer<KeySelectionDialog> dialog = new KeySelectionDialog( |
|
i18n( "Attach Public OpenPGP Key" ), |
|
i18n( "Select the public key which should be attached." ), |
|
std::vector<GpgME::Key>(), |
|
KeySelectionDialog::PublicKeys|KeySelectionDialog::OpenPGPKeys, |
|
false /* no multi selection */, |
|
false /* no remember choice box */, |
|
d->composer, "attach public key selection dialog" ); |
|
|
|
if( dialog->exec() == KDialog::Accepted ) { |
|
d->exportPublicKey( dialog->fingerprint() ); |
|
} |
|
delete dialog; |
|
} |
|
|
|
void AttachmentController::attachMyPublicKey() |
|
{ |
|
const KPIMIdentities::Identity &identity = d->composer->identity(); |
|
kDebug() << identity.identityName(); |
|
d->exportPublicKey( d->composer->identity().pgpEncryptionKey() ); |
|
} |
|
|
|
#include "attachmentcontroller.moc"
|
|
|