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.
3560 lines
108 KiB
3560 lines
108 KiB
/* -*- mode: C++; c-file-style: "gnu" -*-
|
|
This file is part of KMail, the KDE mail client.
|
|
Copyright (c) 2002 Don Sanders <sanders@kde.org>
|
|
|
|
KMail is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License, version 2, as
|
|
published by the Free Software Foundation.
|
|
|
|
KMail 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
|
|
*/
|
|
|
|
//
|
|
// This file implements various "command" classes. These command classes
|
|
// are based on the command design pattern.
|
|
//
|
|
// Historically various operations were implemented as slots of KMMainWin.
|
|
// This proved inadequate as KMail has multiple top level windows
|
|
// (KMMainWin, KMReaderMainWin, SearchWindow, KMComposeWin) that may
|
|
// benefit from using these operations. It is desirable that these
|
|
// classes can operate without depending on or altering the state of
|
|
// a KMMainWin, in fact it is possible no KMMainWin object even exists.
|
|
//
|
|
// Now these operations have been rewritten as KMCommand based classes,
|
|
// making them independent of KMMainWin.
|
|
//
|
|
// The base command class KMCommand is async, which is a difference
|
|
// from the conventional command pattern. As normal derived classes implement
|
|
// the execute method, but client classes call start() instead of
|
|
// calling execute() directly. start() initiates async operations,
|
|
// and on completion of these operations calls execute() and then deletes
|
|
// the command. (So the client must not construct commands on the stack).
|
|
//
|
|
// The type of async operation supported by KMCommand is retrieval
|
|
// of messages from an IMAP server.
|
|
|
|
#include "kmcommands.h"
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <mimelib/enum.h>
|
|
#include <mimelib/field.h>
|
|
#include <mimelib/mimepp.h>
|
|
#include <mimelib/string.h>
|
|
#include <kapplication.h>
|
|
#include <dcopclient.h>
|
|
|
|
#include <tqtextcodec.h>
|
|
#include <tqpopupmenu.h>
|
|
#include <tqeventloop.h>
|
|
|
|
#include <libemailfunctions/email.h>
|
|
#include <kdcopservicestarter.h>
|
|
#include <kdebug.h>
|
|
#include <kfiledialog.h>
|
|
#include <kabc/stdaddressbook.h>
|
|
#include <kabc/addresseelist.h>
|
|
#include <kdirselectdialog.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include <kparts/browserextension.h>
|
|
#include <kprogress.h>
|
|
#include <krun.h>
|
|
#include <kbookmarkmanager.h>
|
|
#include <kstandarddirs.h>
|
|
#include <ktempfile.h>
|
|
#include <kimproxy.h>
|
|
#include <kuserprofile.h>
|
|
// KIO headers
|
|
#include <kio/job.h>
|
|
#include <kio/netaccess.h>
|
|
|
|
#include <libkpimidentities/identitymanager.h>
|
|
|
|
#include "actionscheduler.h"
|
|
using KMail::ActionScheduler;
|
|
#include "mailinglist-magic.h"
|
|
#include "kmaddrbook.h"
|
|
#include <kaddrbook.h>
|
|
#include "composer.h"
|
|
#include "kmfiltermgr.h"
|
|
#include "kmfoldermbox.h"
|
|
#include "kmfolderimap.h"
|
|
#include "kmfoldermgr.h"
|
|
#include "kmheaders.h"
|
|
#include "headeritem.h"
|
|
#include "kmmainwidget.h"
|
|
#include "kmmsgdict.h"
|
|
#include "messagesender.h"
|
|
#include "kmmsgpartdlg.h"
|
|
#include "undostack.h"
|
|
#include "kcursorsaver.h"
|
|
#include "partNode.h"
|
|
#include "objecttreeparser.h"
|
|
using KMail::ObjectTreeParser;
|
|
using KMail::FolderJob;
|
|
#include "chiasmuskeyselector.h"
|
|
#include "mailsourceviewer.h"
|
|
using KMail::MailSourceViewer;
|
|
#include "kmreadermainwin.h"
|
|
#include "secondarywindow.h"
|
|
using KMail::SecondaryWindow;
|
|
#include "redirectdialog.h"
|
|
using KMail::RedirectDialog;
|
|
#include "util.h"
|
|
#include "templateparser.h"
|
|
#include "editorwatcher.h"
|
|
#include "korghelper.h"
|
|
|
|
#include "broadcaststatus.h"
|
|
#include "globalsettings.h"
|
|
|
|
#include <libkdepim/kfileio.h>
|
|
#include "kcalendariface_stub.h"
|
|
|
|
#include "progressmanager.h"
|
|
using KPIM::ProgressManager;
|
|
using KPIM::ProgressItem;
|
|
#include <kmime_mdn.h>
|
|
using namespace KMime;
|
|
|
|
#include <kleo/specialjob.h>
|
|
#include <kleo/cryptobackend.h>
|
|
#include <kleo/cryptobackendfactory.h>
|
|
|
|
#include <tqclipboard.h>
|
|
|
|
#include <memory>
|
|
|
|
class LaterDeleterWithCommandCompletion : public KMail::Util::LaterDeleter
|
|
{
|
|
public:
|
|
LaterDeleterWithCommandCompletion( KMCommand* command )
|
|
:LaterDeleter( command ), m_result( KMCommand::Failed )
|
|
{
|
|
}
|
|
~LaterDeleterWithCommandCompletion()
|
|
{
|
|
setResult( m_result );
|
|
KMCommand *command = static_cast<KMCommand*>( m_object );
|
|
emit command->completed( command );
|
|
}
|
|
void setResult( KMCommand::Result v ) { m_result = v; }
|
|
private:
|
|
KMCommand::Result m_result;
|
|
};
|
|
|
|
|
|
KMCommand::KMCommand( TQWidget *parent )
|
|
: mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
|
|
mEmitsCompletedItself( false ), mParent( parent )
|
|
{
|
|
}
|
|
|
|
KMCommand::KMCommand( TQWidget *parent, const TQPtrList<KMMsgBase> &msgList )
|
|
: mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
|
|
mEmitsCompletedItself( false ), mParent( parent ), mMsgList( msgList )
|
|
{
|
|
}
|
|
|
|
KMCommand::KMCommand( TQWidget *parent, KMMsgBase *msgBase )
|
|
: mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
|
|
mEmitsCompletedItself( false ), mParent( parent )
|
|
{
|
|
mMsgList.append( msgBase );
|
|
}
|
|
|
|
KMCommand::KMCommand( TQWidget *parent, KMMessage *msg )
|
|
: mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
|
|
mEmitsCompletedItself( false ), mParent( parent )
|
|
{
|
|
if (msg)
|
|
mMsgList.append( &msg->toMsgBase() );
|
|
}
|
|
|
|
KMCommand::~KMCommand()
|
|
{
|
|
TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
|
|
for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
|
|
if (!(*fit))
|
|
continue;
|
|
(*fit)->close("kmcommand");
|
|
}
|
|
}
|
|
|
|
KMCommand::Result KMCommand::result()
|
|
{
|
|
if ( mResult == Undefined )
|
|
kdDebug(5006) << k_funcinfo << "mResult is Undefined" << endl;
|
|
return mResult;
|
|
}
|
|
|
|
void KMCommand::start()
|
|
{
|
|
TQTimer::singleShot( 0, this, TQT_SLOT( slotStart() ) );
|
|
}
|
|
|
|
|
|
const TQPtrList<KMMessage> KMCommand::retrievedMsgs() const
|
|
{
|
|
return mRetrievedMsgs;
|
|
}
|
|
|
|
KMMessage *KMCommand::retrievedMessage() const
|
|
{
|
|
return mRetrievedMsgs.getFirst();
|
|
}
|
|
|
|
TQWidget *KMCommand::parentWidget() const
|
|
{
|
|
return mParent;
|
|
}
|
|
|
|
int KMCommand::mCountJobs = 0;
|
|
|
|
void KMCommand::slotStart()
|
|
{
|
|
connect( this, TQT_SIGNAL( messagesTransfered( KMCommand::Result ) ),
|
|
this, TQT_SLOT( slotPostTransfer( KMCommand::Result ) ) );
|
|
kmkernel->filterMgr()->ref();
|
|
|
|
if (mMsgList.find(0) != -1) {
|
|
emit messagesTransfered( Failed );
|
|
return;
|
|
}
|
|
|
|
if ((mMsgList.count() == 1) &&
|
|
(mMsgList.getFirst()->isMessage()) &&
|
|
(mMsgList.getFirst()->parent() == 0))
|
|
{
|
|
// Special case of operating on message that isn't in a folder
|
|
mRetrievedMsgs.append((KMMessage*)mMsgList.getFirst());
|
|
emit messagesTransfered( OK );
|
|
return;
|
|
}
|
|
|
|
for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
|
|
if (!mb->parent()) {
|
|
emit messagesTransfered( Failed );
|
|
return;
|
|
} else {
|
|
keepFolderOpen( mb->parent() );
|
|
}
|
|
|
|
// transfer the selected messages first
|
|
transferSelectedMsgs();
|
|
}
|
|
|
|
void KMCommand::slotPostTransfer( KMCommand::Result result )
|
|
{
|
|
disconnect( this, TQT_SIGNAL( messagesTransfered( KMCommand::Result ) ),
|
|
this, TQT_SLOT( slotPostTransfer( KMCommand::Result ) ) );
|
|
if ( result == OK )
|
|
result = execute();
|
|
mResult = result;
|
|
TQPtrListIterator<KMMessage> it( mRetrievedMsgs );
|
|
KMMessage* msg;
|
|
while ( (msg = it.current()) != 0 )
|
|
{
|
|
++it;
|
|
if (msg->parent())
|
|
msg->setTransferInProgress(false);
|
|
}
|
|
kmkernel->filterMgr()->deref();
|
|
if ( !emitsCompletedItself() )
|
|
emit completed( this );
|
|
if ( !deletesItself() )
|
|
deleteLater();
|
|
}
|
|
|
|
void KMCommand::transferSelectedMsgs()
|
|
{
|
|
// make sure no other transfer is active
|
|
if (KMCommand::mCountJobs > 0) {
|
|
emit messagesTransfered( Failed );
|
|
return;
|
|
}
|
|
|
|
bool complete = true;
|
|
KMCommand::mCountJobs = 0;
|
|
mCountMsgs = 0;
|
|
mRetrievedMsgs.clear();
|
|
mCountMsgs = mMsgList.count();
|
|
uint totalSize = 0;
|
|
// the KProgressDialog for the user-feedback. Only enable it if it's needed.
|
|
// For some commands like KMSetStatusCommand it's not needed. Note, that
|
|
// for some reason the KProgressDialog eats the MouseReleaseEvent (if a
|
|
// command is executed after the MousePressEvent), cf. bug #71761.
|
|
if ( mCountMsgs > 0 ) {
|
|
mProgressDialog = new KProgressDialog(mParent, "transferProgress",
|
|
i18n("Please wait"),
|
|
i18n("Please wait while the message is transferred",
|
|
"Please wait while the %n messages are transferred", mMsgList.count()),
|
|
true);
|
|
mProgressDialog->setMinimumDuration(1000);
|
|
}
|
|
for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
|
|
{
|
|
// check if all messages are complete
|
|
KMMessage *thisMsg = 0;
|
|
if ( mb->isMessage() )
|
|
thisMsg = static_cast<KMMessage*>(mb);
|
|
else
|
|
{
|
|
KMFolder *folder = mb->parent();
|
|
int idx = folder->find(mb);
|
|
if (idx < 0) continue;
|
|
thisMsg = folder->getMsg(idx);
|
|
}
|
|
if (!thisMsg) continue;
|
|
if ( thisMsg->transferInProgress() &&
|
|
thisMsg->parent()->folderType() == KMFolderTypeImap )
|
|
{
|
|
thisMsg->setTransferInProgress( false, true );
|
|
thisMsg->parent()->ignoreJobsForMessage( thisMsg );
|
|
}
|
|
|
|
if ( thisMsg->parent() && !thisMsg->isComplete() &&
|
|
( !mProgressDialog || !mProgressDialog->wasCancelled() ) )
|
|
{
|
|
kdDebug(5006)<<"### INCOMPLETE\n";
|
|
// the message needs to be transferred first
|
|
complete = false;
|
|
KMCommand::mCountJobs++;
|
|
FolderJob *job = thisMsg->parent()->createJob(thisMsg);
|
|
job->setCancellable( false );
|
|
totalSize += thisMsg->msgSizeServer();
|
|
// emitted when the message was transferred successfully
|
|
connect(job, TQT_SIGNAL(messageRetrieved(KMMessage*)),
|
|
this, TQT_SLOT(slotMsgTransfered(KMMessage*)));
|
|
// emitted when the job is destroyed
|
|
connect(job, TQT_SIGNAL(finished()),
|
|
this, TQT_SLOT(slotJobFinished()));
|
|
connect(job, TQT_SIGNAL(progress(unsigned long, unsigned long)),
|
|
this, TQT_SLOT(slotProgress(unsigned long, unsigned long)));
|
|
// msg musn't be deleted
|
|
thisMsg->setTransferInProgress(true);
|
|
job->start();
|
|
} else {
|
|
thisMsg->setTransferInProgress(true);
|
|
mRetrievedMsgs.append(thisMsg);
|
|
}
|
|
}
|
|
|
|
if (complete)
|
|
{
|
|
delete mProgressDialog;
|
|
mProgressDialog = 0;
|
|
emit messagesTransfered( OK );
|
|
} else {
|
|
// wait for the transfer and tell the progressBar the necessary steps
|
|
if ( mProgressDialog ) {
|
|
connect(mProgressDialog, TQT_SIGNAL(cancelClicked()),
|
|
this, TQT_SLOT(slotTransferCancelled()));
|
|
mProgressDialog->progressBar()->setTotalSteps(totalSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMCommand::slotMsgTransfered(KMMessage* msg)
|
|
{
|
|
if ( mProgressDialog && mProgressDialog->wasCancelled() ) {
|
|
emit messagesTransfered( Canceled );
|
|
return;
|
|
}
|
|
|
|
// save the complete messages
|
|
mRetrievedMsgs.append(msg);
|
|
}
|
|
|
|
void KMCommand::slotProgress( unsigned long done, unsigned long /*total*/ )
|
|
{
|
|
mProgressDialog->progressBar()->setProgress( done );
|
|
}
|
|
|
|
void KMCommand::slotJobFinished()
|
|
{
|
|
// the job is finished (with / without error)
|
|
KMCommand::mCountJobs--;
|
|
|
|
if ( mProgressDialog && mProgressDialog->wasCancelled() ) return;
|
|
|
|
if ( (mCountMsgs - static_cast<int>(mRetrievedMsgs.count())) > KMCommand::mCountJobs )
|
|
{
|
|
// the message wasn't retrieved before => error
|
|
if ( mProgressDialog )
|
|
mProgressDialog->hide();
|
|
slotTransferCancelled();
|
|
return;
|
|
}
|
|
// update the progressbar
|
|
if ( mProgressDialog ) {
|
|
mProgressDialog->setLabel(i18n("Please wait while the message is transferred",
|
|
"Please wait while the %n messages are transferred", KMCommand::mCountJobs));
|
|
}
|
|
if (KMCommand::mCountJobs == 0)
|
|
{
|
|
// all done
|
|
delete mProgressDialog;
|
|
mProgressDialog = 0;
|
|
emit messagesTransfered( OK );
|
|
}
|
|
}
|
|
|
|
void KMCommand::slotTransferCancelled()
|
|
{
|
|
// kill the pending jobs
|
|
TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
|
|
for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
|
|
if (!(*fit))
|
|
continue;
|
|
KMFolder *folder = *fit;
|
|
KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder);
|
|
if (imapFolder && imapFolder->account()) {
|
|
imapFolder->account()->killAllJobs();
|
|
}
|
|
}
|
|
|
|
KMCommand::mCountJobs = 0;
|
|
mCountMsgs = 0;
|
|
// unget the transfered messages
|
|
TQPtrListIterator<KMMessage> it( mRetrievedMsgs );
|
|
KMMessage* msg;
|
|
while ( (msg = it.current()) != 0 )
|
|
{
|
|
KMFolder *folder = msg->parent();
|
|
++it;
|
|
if (!folder)
|
|
continue;
|
|
msg->setTransferInProgress(false);
|
|
int idx = folder->find(msg);
|
|
if (idx > 0) folder->unGetMsg(idx);
|
|
}
|
|
mRetrievedMsgs.clear();
|
|
emit messagesTransfered( Canceled );
|
|
}
|
|
|
|
void KMCommand::keepFolderOpen( KMFolder *folder )
|
|
{
|
|
folder->open("kmcommand");
|
|
mFolders.append( folder );
|
|
}
|
|
|
|
KMMailtoComposeCommand::KMMailtoComposeCommand( const KURL &url,
|
|
KMMessage *msg )
|
|
:mUrl( url ), mMessage( msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMMailtoComposeCommand::execute()
|
|
{
|
|
KMMessage *msg = new KMMessage;
|
|
uint id = 0;
|
|
|
|
if ( mMessage && mMessage->parent() )
|
|
id = mMessage->parent()->identity();
|
|
|
|
msg->initHeader(id);
|
|
msg->setCharset("utf-8");
|
|
msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
|
|
|
|
KMail::Composer * win = KMail::makeComposer( msg, id );
|
|
win->setCharset("", true);
|
|
win->setFocusToSubject();
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMMailtoReplyCommand::KMMailtoReplyCommand( TQWidget *parent,
|
|
const KURL &url, KMMessage *msg, const TQString &selection )
|
|
:KMCommand( parent, msg ), mUrl( url ), mSelection( selection )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMMailtoReplyCommand::execute()
|
|
{
|
|
//TODO : consider factoring createReply into this method.
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *rmsg = msg->createReply( KMail::ReplyNone, mSelection );
|
|
rmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
|
|
|
|
KMail::Composer * win = KMail::makeComposer( rmsg, 0 );
|
|
win->setCharset(msg->codec()->mimeName(), true);
|
|
win->setReplyFocus();
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMMailtoForwardCommand::KMMailtoForwardCommand( TQWidget *parent,
|
|
const KURL &url, KMMessage *msg )
|
|
:KMCommand( parent, msg ), mUrl( url )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMMailtoForwardCommand::execute()
|
|
{
|
|
//TODO : consider factoring createForward into this method.
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *fmsg = msg->createForward();
|
|
fmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
|
|
|
|
KMail::Composer * win = KMail::makeComposer( fmsg );
|
|
win->setCharset(msg->codec()->mimeName(), true);
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMAddBookmarksCommand::KMAddBookmarksCommand( const KURL &url, TQWidget *parent )
|
|
: KMCommand( parent ), mUrl( url )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMAddBookmarksCommand::execute()
|
|
{
|
|
TQString filename = locateLocal( "data", TQString::fromLatin1("konqueror/bookmarks.xml") );
|
|
KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,
|
|
false );
|
|
KBookmarkGroup group = bookManager->root();
|
|
group.addBookmark( bookManager, mUrl.path(), KURL( mUrl ) );
|
|
if( bookManager->save() ) {
|
|
bookManager->emitChanged( group );
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
KMMailtoAddAddrBookCommand::KMMailtoAddAddrBookCommand( const KURL &url,
|
|
TQWidget *parent )
|
|
: KMCommand( parent ), mUrl( url )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMMailtoAddAddrBookCommand::execute()
|
|
{
|
|
KAddrBookExternal::addEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
|
|
parentWidget() );
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMMailtoOpenAddrBookCommand::KMMailtoOpenAddrBookCommand( const KURL &url,
|
|
TQWidget *parent )
|
|
: KMCommand( parent ), mUrl( url )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMMailtoOpenAddrBookCommand::execute()
|
|
{
|
|
KAddrBookExternal::openEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
|
|
parentWidget() );
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMUrlCopyCommand::KMUrlCopyCommand( const KURL &url, KMMainWidget *mainWidget )
|
|
:mUrl( url ), mMainWidget( mainWidget )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMUrlCopyCommand::execute()
|
|
{
|
|
QClipboard* clip = TQApplication::clipboard();
|
|
|
|
if (mUrl.protocol() == "mailto") {
|
|
// put the url into the mouse selection and the clipboard
|
|
TQString address = KMMessage::decodeMailtoUrl( mUrl.path() );
|
|
clip->setSelectionMode( true );
|
|
clip->setText( address );
|
|
clip->setSelectionMode( false );
|
|
clip->setText( address );
|
|
KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "Address copied to clipboard." ));
|
|
} else {
|
|
// put the url into the mouse selection and the clipboard
|
|
clip->setSelectionMode( true );
|
|
clip->setText( mUrl.url() );
|
|
clip->setSelectionMode( false );
|
|
clip->setText( mUrl.url() );
|
|
KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "URL copied to clipboard." ));
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMUrlOpenCommand::KMUrlOpenCommand( const KURL &url, KMReaderWin *readerWin )
|
|
:mUrl( url ), mReaderWin( readerWin )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMUrlOpenCommand::execute()
|
|
{
|
|
if ( !mUrl.isEmpty() )
|
|
mReaderWin->slotUrlOpen( mUrl, KParts::URLArgs() );
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMUrlSaveCommand::KMUrlSaveCommand( const KURL &url, TQWidget *parent )
|
|
: KMCommand( parent ), mUrl( url )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMUrlSaveCommand::execute()
|
|
{
|
|
if ( mUrl.isEmpty() )
|
|
return OK;
|
|
KURL saveUrl = KFileDialog::getSaveURL(mUrl.fileName(), TQString::null,
|
|
parentWidget() );
|
|
if ( saveUrl.isEmpty() )
|
|
return Canceled;
|
|
if ( KIO::NetAccess::exists( saveUrl, false, parentWidget() ) )
|
|
{
|
|
if (KMessageBox::warningContinueCancel(0,
|
|
i18n("<qt>File <b>%1</b> exists.<br>Do you want to replace it?</qt>")
|
|
.arg(saveUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
|
|
!= KMessageBox::Continue)
|
|
return Canceled;
|
|
}
|
|
KIO::Job *job = KIO::file_copy(mUrl, saveUrl, -1, true);
|
|
connect(job, TQT_SIGNAL(result(KIO::Job*)), TQT_SLOT(slotUrlSaveResult(KIO::Job*)));
|
|
setEmitsCompletedItself( true );
|
|
return OK;
|
|
}
|
|
|
|
void KMUrlSaveCommand::slotUrlSaveResult( KIO::Job *job )
|
|
{
|
|
if ( job->error() ) {
|
|
job->showErrorDialog();
|
|
setResult( Failed );
|
|
emit completed( this );
|
|
}
|
|
else {
|
|
setResult( OK );
|
|
emit completed( this );
|
|
}
|
|
}
|
|
|
|
|
|
KMEditMsgCommand::KMEditMsgCommand( TQWidget *parent, KMMessage *msg )
|
|
:KMCommand( parent, msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMEditMsgCommand::execute()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->parent() ||
|
|
( !kmkernel->folderIsDraftOrOutbox( msg->parent() ) &&
|
|
!kmkernel->folderIsTemplates( msg->parent() ) ) )
|
|
return Failed;
|
|
|
|
// Remember the old parent, we need it a bit further down to be able
|
|
// to put the unchanged messsage back in the original folder if the nth
|
|
// edit is discarded, for n > 1.
|
|
KMFolder *parent = msg->parent();
|
|
if ( parent )
|
|
parent->take( parent->find( msg ) );
|
|
|
|
KMail::Composer * win = KMail::makeComposer();
|
|
msg->setTransferInProgress(false); // From here on on, the composer owns the message.
|
|
win->setMsg(msg, false, true);
|
|
win->setFolder( parent );
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
KMUseTemplateCommand::KMUseTemplateCommand( TQWidget *parent, KMMessage *msg )
|
|
:KMCommand( parent, msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMUseTemplateCommand::execute()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->parent() ||
|
|
!kmkernel->folderIsTemplates( msg->parent() ) )
|
|
return Failed;
|
|
|
|
// Take a copy of the original message, which remains unchanged.
|
|
KMMessage *newMsg = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
|
|
newMsg->setComplete( msg->isComplete() );
|
|
|
|
// these fields need to be regenerated for the new message
|
|
newMsg->removeHeaderField("Date");
|
|
newMsg->removeHeaderField("Message-ID");
|
|
|
|
KMail::Composer *win = KMail::makeComposer();
|
|
newMsg->setTransferInProgress( false ); // From here on on, the composer owns the message.
|
|
win->setMsg( newMsg, false, true );
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
KMShowMsgSrcCommand::KMShowMsgSrcCommand( TQWidget *parent,
|
|
KMMessage *msg, bool fixedFont )
|
|
:KMCommand( parent, msg ), mFixedFont( fixedFont )
|
|
{
|
|
// remember complete state
|
|
mMsgWasComplete = msg->isComplete();
|
|
}
|
|
|
|
KMCommand::Result KMShowMsgSrcCommand::execute()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
if ( msg->isComplete() && !mMsgWasComplete )
|
|
msg->notify(); // notify observers as msg was transfered
|
|
TQString str = msg->codec()->toUnicode( msg->asString() );
|
|
|
|
MailSourceViewer *viewer = new MailSourceViewer(); // deletes itself upon close
|
|
viewer->setCaption( i18n("Message as Plain Text") );
|
|
viewer->setText(str);
|
|
if( mFixedFont )
|
|
viewer->setFont(KGlobalSettings::fixedFont());
|
|
|
|
// Well, there is no widget to be seen here, so we have to use TQCursor::pos()
|
|
// Update: (GS) I'm not going to make this code behave according to Xinerama
|
|
// configuration because this is quite the hack.
|
|
if (TQApplication::desktop()->isVirtualDesktop()) {
|
|
int scnum = TQApplication::desktop()->screenNumber(TQCursor::pos());
|
|
viewer->resize(TQApplication::desktop()->screenGeometry(scnum).width()/2,
|
|
2*TQApplication::desktop()->screenGeometry(scnum).height()/3);
|
|
} else {
|
|
viewer->resize(TQApplication::desktop()->geometry().width()/2,
|
|
2*TQApplication::desktop()->geometry().height()/3);
|
|
}
|
|
viewer->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
static KURL subjectToUrl( const TQString & subject ) {
|
|
return KFileDialog::getSaveURL( subject.stripWhiteSpace()
|
|
.replace( TQDir::separator(), '_' ),
|
|
"*.mbox" );
|
|
}
|
|
|
|
KMSaveMsgCommand::KMSaveMsgCommand( TQWidget *parent, KMMessage * msg )
|
|
: KMCommand( parent ),
|
|
mMsgListIndex( 0 ),
|
|
mStandAloneMessage( 0 ),
|
|
mOffset( 0 ),
|
|
mTotalSize( msg ? msg->msgSize() : 0 )
|
|
{
|
|
if ( !msg ) return;
|
|
setDeletesItself( true );
|
|
// If the mail has a serial number, operate on sernums, if it does not
|
|
// we need to work with the pointer, but can be reasonably sure it won't
|
|
// go away, since it'll be an encapsulated message or one that was opened
|
|
// from an .eml file.
|
|
if ( msg->getMsgSerNum() != 0 ) {
|
|
mMsgList.append( msg->getMsgSerNum() );
|
|
if ( msg->parent() ) {
|
|
msg->parent()->open( "kmsavemsgcommand" );
|
|
}
|
|
} else {
|
|
mStandAloneMessage = msg;
|
|
}
|
|
mUrl = subjectToUrl( msg->cleanSubject() );
|
|
}
|
|
|
|
KMSaveMsgCommand::KMSaveMsgCommand( TQWidget *parent,
|
|
const TQPtrList<KMMsgBase> &msgList )
|
|
: KMCommand( parent ),
|
|
mMsgListIndex( 0 ),
|
|
mStandAloneMessage( 0 ),
|
|
mOffset( 0 ),
|
|
mTotalSize( 0 )
|
|
{
|
|
if (!msgList.getFirst())
|
|
return;
|
|
setDeletesItself( true );
|
|
KMMsgBase *msgBase = msgList.getFirst();
|
|
|
|
// We operate on serNums and not the KMMsgBase pointers, as those can
|
|
// change, or become invalid when changing the current message, switching
|
|
// folders, etc.
|
|
TQPtrListIterator<KMMsgBase> it(msgList);
|
|
while ( it.current() ) {
|
|
mMsgList.append( (*it)->getMsgSerNum() );
|
|
mTotalSize += (*it)->msgSize();
|
|
if ((*it)->parent() != 0)
|
|
(*it)->parent()->open("kmcommand");
|
|
++it;
|
|
}
|
|
mMsgListIndex = 0;
|
|
mUrl = subjectToUrl( msgBase->cleanSubject() );
|
|
}
|
|
|
|
KURL KMSaveMsgCommand::url()
|
|
{
|
|
return mUrl;
|
|
}
|
|
|
|
KMCommand::Result KMSaveMsgCommand::execute()
|
|
{
|
|
mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, false, false );
|
|
mJob->slotTotalSize( mTotalSize );
|
|
mJob->setAsyncDataEnabled( true );
|
|
mJob->setReportDataSent( true );
|
|
connect(mJob, TQT_SIGNAL(dataReq(KIO::Job*, TQByteArray &)),
|
|
TQT_SLOT(slotSaveDataReq()));
|
|
connect(mJob, TQT_SIGNAL(result(KIO::Job*)),
|
|
TQT_SLOT(slotSaveResult(KIO::Job*)));
|
|
setEmitsCompletedItself( true );
|
|
return OK;
|
|
}
|
|
|
|
void KMSaveMsgCommand::slotSaveDataReq()
|
|
{
|
|
int remainingBytes = mData.size() - mOffset;
|
|
if ( remainingBytes > 0 ) {
|
|
// eat leftovers first
|
|
if ( remainingBytes > MAX_CHUNK_SIZE )
|
|
remainingBytes = MAX_CHUNK_SIZE;
|
|
|
|
TQByteArray data;
|
|
data.duplicate( mData.data() + mOffset, remainingBytes );
|
|
mJob->sendAsyncData( data );
|
|
mOffset += remainingBytes;
|
|
return;
|
|
}
|
|
// No leftovers, process next message.
|
|
if ( mMsgListIndex < mMsgList.size() ) {
|
|
KMMessage *msg = 0;
|
|
int idx = -1;
|
|
KMFolder * p = 0;
|
|
KMMsgDict::instance()->getLocation( mMsgList[mMsgListIndex], &p, &idx );
|
|
assert( p );
|
|
assert( idx >= 0 );
|
|
//kdDebug() << "SERNUM: " << mMsgList[mMsgListIndex] << " idx: " << idx << " folder: " << p->prettyURL() << endl;
|
|
msg = p->getMsg(idx);
|
|
|
|
if ( msg ) {
|
|
if ( msg->transferInProgress() ) {
|
|
TQByteArray data = TQByteArray();
|
|
mJob->sendAsyncData( data );
|
|
}
|
|
msg->setTransferInProgress( true );
|
|
if (msg->isComplete() ) {
|
|
slotMessageRetrievedForSaving( msg );
|
|
} else {
|
|
// retrieve Message first
|
|
if ( msg->parent() && !msg->isComplete() ) {
|
|
FolderJob *job = msg->parent()->createJob( msg );
|
|
job->setCancellable( false );
|
|
connect(job, TQT_SIGNAL( messageRetrieved( KMMessage* ) ),
|
|
this, TQT_SLOT( slotMessageRetrievedForSaving( KMMessage* ) ) );
|
|
job->start();
|
|
}
|
|
}
|
|
} else {
|
|
mJob->slotError( KIO::ERR_ABORTED,
|
|
i18n("The message was removed while saving it. "
|
|
"It has not been saved.") );
|
|
}
|
|
} else {
|
|
if ( mStandAloneMessage ) {
|
|
// do the special case of a standalone message
|
|
slotMessageRetrievedForSaving( mStandAloneMessage );
|
|
mStandAloneMessage = 0;
|
|
} else {
|
|
// No more messages. Tell the putjob we are done.
|
|
TQByteArray data = TQByteArray();
|
|
mJob->sendAsyncData( data );
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg)
|
|
{
|
|
if ( msg ) {
|
|
mData = KMFolderMbox::escapeFrom( msg->asDwString() );
|
|
KMail::Util::insert( mData, 0, msg->mboxMessageSeparator() );
|
|
KMail::Util::append( mData, "\n" );
|
|
msg->setTransferInProgress(false);
|
|
|
|
mOffset = 0;
|
|
TQByteArray data;
|
|
int size;
|
|
// Unless it is great than 64 k send the whole message. kio buffers for us.
|
|
if( mData.size() > (unsigned int) MAX_CHUNK_SIZE )
|
|
size = MAX_CHUNK_SIZE;
|
|
else
|
|
size = mData.size();
|
|
|
|
data.duplicate( mData, size );
|
|
mJob->sendAsyncData( data );
|
|
mOffset += size;
|
|
}
|
|
++mMsgListIndex;
|
|
// Get rid of the message.
|
|
if ( msg && msg->parent() && msg->getMsgSerNum() ) {
|
|
int idx = -1;
|
|
KMFolder * p = 0;
|
|
KMMsgDict::instance()->getLocation( msg, &p, &idx );
|
|
assert( p == msg->parent() ); assert( idx >= 0 );
|
|
p->unGetMsg( idx );
|
|
p->close("kmcommand");
|
|
}
|
|
}
|
|
|
|
void KMSaveMsgCommand::slotSaveResult(KIO::Job *job)
|
|
{
|
|
if (job->error())
|
|
{
|
|
if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
|
|
{
|
|
if (KMessageBox::warningContinueCancel(0,
|
|
i18n("File %1 exists.\nDo you want to replace it?")
|
|
.arg(mUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
|
|
== KMessageBox::Continue) {
|
|
mOffset = 0;
|
|
|
|
mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, true, false );
|
|
mJob->slotTotalSize( mTotalSize );
|
|
mJob->setAsyncDataEnabled( true );
|
|
mJob->setReportDataSent( true );
|
|
connect(mJob, TQT_SIGNAL(dataReq(KIO::Job*, TQByteArray &)),
|
|
TQT_SLOT(slotSaveDataReq()));
|
|
connect(mJob, TQT_SIGNAL(result(KIO::Job*)),
|
|
TQT_SLOT(slotSaveResult(KIO::Job*)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
job->showErrorDialog();
|
|
setResult( Failed );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
} else {
|
|
setResult( OK );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
KMOpenMsgCommand::KMOpenMsgCommand( TQWidget *parent, const KURL & url,
|
|
const TQString & encoding )
|
|
: KMCommand( parent ),
|
|
mUrl( url ),
|
|
mEncoding( encoding )
|
|
{
|
|
setDeletesItself( true );
|
|
}
|
|
|
|
KMCommand::Result KMOpenMsgCommand::execute()
|
|
{
|
|
if ( mUrl.isEmpty() ) {
|
|
mUrl = KFileDialog::getOpenURL( ":OpenMessage", "message/rfc822 application/mbox",
|
|
parentWidget(), i18n("Open Message") );
|
|
}
|
|
if ( mUrl.isEmpty() ) {
|
|
setDeletesItself( false );
|
|
return Canceled;
|
|
}
|
|
mJob = KIO::get( mUrl, false, false );
|
|
mJob->setReportDataSent( true );
|
|
connect( mJob, TQT_SIGNAL( data( KIO::Job *, const TQByteArray & ) ),
|
|
this, TQT_SLOT( slotDataArrived( KIO::Job*, const TQByteArray & ) ) );
|
|
connect( mJob, TQT_SIGNAL( result( KIO::Job * ) ),
|
|
TQT_SLOT( slotResult( KIO::Job * ) ) );
|
|
setEmitsCompletedItself( true );
|
|
return OK;
|
|
}
|
|
|
|
void KMOpenMsgCommand::slotDataArrived( KIO::Job *, const TQByteArray & data )
|
|
{
|
|
if ( data.isEmpty() )
|
|
return;
|
|
|
|
mMsgString.append( data.data(), data.size() );
|
|
}
|
|
|
|
void KMOpenMsgCommand::slotResult( KIO::Job *job )
|
|
{
|
|
if ( job->error() ) {
|
|
// handle errors
|
|
job->showErrorDialog();
|
|
setResult( Failed );
|
|
emit completed( this );
|
|
}
|
|
else {
|
|
int startOfMessage = 0;
|
|
if ( mMsgString.compare( 0, 5, "From ", 5 ) == 0 ) {
|
|
startOfMessage = mMsgString.find( '\n' );
|
|
if ( startOfMessage == -1 ) {
|
|
KMessageBox::sorry( parentWidget(),
|
|
i18n( "The file does not contain a message." ) );
|
|
setResult( Failed );
|
|
emit completed( this );
|
|
// Emulate closing of a secondary window so that KMail exits in case it
|
|
// was started with the --view command line option. Otherwise an
|
|
// invisible KMail would keep running.
|
|
SecondaryWindow *win = new SecondaryWindow();
|
|
win->close();
|
|
win->deleteLater();
|
|
deleteLater();
|
|
return;
|
|
}
|
|
startOfMessage += 1; // the message starts after the '\n'
|
|
}
|
|
// check for multiple messages in the file
|
|
bool multipleMessages = true;
|
|
int endOfMessage = mMsgString.find( "\nFrom " );
|
|
if ( endOfMessage == -1 ) {
|
|
endOfMessage = mMsgString.length();
|
|
multipleMessages = false;
|
|
}
|
|
DwMessage *dwMsg = new DwMessage;
|
|
dwMsg->FromString( mMsgString.substr( startOfMessage,
|
|
endOfMessage - startOfMessage ) );
|
|
dwMsg->Parse();
|
|
// check whether we have a message ( no headers => this isn't a message )
|
|
if ( dwMsg->Headers().NumFields() == 0 ) {
|
|
KMessageBox::sorry( parentWidget(),
|
|
i18n( "The file does not contain a message." ) );
|
|
delete dwMsg; dwMsg = 0;
|
|
setResult( Failed );
|
|
emit completed( this );
|
|
// Emulate closing of a secondary window (see above).
|
|
SecondaryWindow *win = new SecondaryWindow();
|
|
win->close();
|
|
win->deleteLater();
|
|
deleteLater();
|
|
return;
|
|
}
|
|
KMMessage *msg = new KMMessage( dwMsg );
|
|
msg->setReadyToShow( true );
|
|
KMReaderMainWin *win = new KMReaderMainWin();
|
|
win->showMsg( mEncoding, msg );
|
|
win->show();
|
|
if ( multipleMessages )
|
|
KMessageBox::information( win,
|
|
i18n( "The file contains multiple messages. "
|
|
"Only the first message is shown." ) );
|
|
setResult( OK );
|
|
emit completed( this );
|
|
}
|
|
deleteLater();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//TODO: ReplyTo, NoQuoteReplyTo, ReplyList, ReplyToAll, ReplyAuthor
|
|
// are all similar and should be factored
|
|
KMReplyToCommand::KMReplyToCommand( TQWidget *parent, KMMessage *msg,
|
|
const TQString &selection )
|
|
: KMCommand( parent, msg ), mSelection( selection )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMReplyToCommand::execute()
|
|
{
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection );
|
|
KMail::Composer * win = KMail::makeComposer( reply );
|
|
win->setCharset( msg->codec()->mimeName(), true );
|
|
win->setReplyFocus();
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMNoQuoteReplyToCommand::KMNoQuoteReplyToCommand( TQWidget *parent,
|
|
KMMessage *msg )
|
|
: KMCommand( parent, msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMNoQuoteReplyToCommand::execute()
|
|
{
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *reply = msg->createReply( KMail::ReplySmart, "", true);
|
|
KMail::Composer * win = KMail::makeComposer( reply );
|
|
win->setCharset(msg->codec()->mimeName(), true);
|
|
win->setReplyFocus(false);
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMReplyListCommand::KMReplyListCommand( TQWidget *parent,
|
|
KMMessage *msg, const TQString &selection )
|
|
: KMCommand( parent, msg ), mSelection( selection )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMReplyListCommand::execute()
|
|
{
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *reply = msg->createReply( KMail::ReplyList, mSelection);
|
|
KMail::Composer * win = KMail::makeComposer( reply );
|
|
win->setCharset(msg->codec()->mimeName(), true);
|
|
win->setReplyFocus(false);
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMReplyToAllCommand::KMReplyToAllCommand( TQWidget *parent,
|
|
KMMessage *msg, const TQString &selection )
|
|
:KMCommand( parent, msg ), mSelection( selection )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMReplyToAllCommand::execute()
|
|
{
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection );
|
|
KMail::Composer * win = KMail::makeComposer( reply );
|
|
win->setCharset( msg->codec()->mimeName(), true );
|
|
win->setReplyFocus();
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMReplyAuthorCommand::KMReplyAuthorCommand( TQWidget *parent, KMMessage *msg,
|
|
const TQString &selection )
|
|
: KMCommand( parent, msg ), mSelection( selection )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMReplyAuthorCommand::execute()
|
|
{
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *reply = msg->createReply( KMail::ReplyAuthor, mSelection );
|
|
KMail::Composer * win = KMail::makeComposer( reply );
|
|
win->setCharset( msg->codec()->mimeName(), true );
|
|
win->setReplyFocus();
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMForwardInlineCommand::KMForwardInlineCommand( TQWidget *parent,
|
|
const TQPtrList<KMMsgBase> &msgList, uint identity )
|
|
: KMCommand( parent, msgList ),
|
|
mIdentity( identity )
|
|
{
|
|
}
|
|
|
|
KMForwardInlineCommand::KMForwardInlineCommand( TQWidget *parent,
|
|
KMMessage *msg, uint identity )
|
|
: KMCommand( parent, msg ),
|
|
mIdentity( identity )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMForwardInlineCommand::execute()
|
|
{
|
|
TQPtrList<KMMessage> msgList = retrievedMsgs();
|
|
|
|
if (msgList.count() >= 2) { // Multiple forward
|
|
|
|
uint id = 0;
|
|
TQPtrList<KMMessage> linklist;
|
|
for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
|
|
// set the identity
|
|
if (id == 0)
|
|
id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
|
|
|
|
// msgText += msg->createForwardBody();
|
|
linklist.append( msg );
|
|
}
|
|
if ( id == 0 )
|
|
id = mIdentity; // use folder identity if no message had an id set
|
|
KMMessage *fwdMsg = new KMMessage;
|
|
fwdMsg->initHeader( id );
|
|
fwdMsg->setAutomaticFields( true );
|
|
fwdMsg->setCharset( "utf-8" );
|
|
// fwdMsg->setBody( msgText );
|
|
|
|
for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
|
|
TemplateParser parser( fwdMsg, TemplateParser::Forward,
|
|
msg->body(), false, false, false, false);
|
|
parser.process( msg, 0, true );
|
|
|
|
fwdMsg->link( msg, KMMsgStatusForwarded );
|
|
}
|
|
|
|
KCursorSaver busy( KBusyPtr::busy() );
|
|
KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
|
|
win->setCharset("");
|
|
win->show();
|
|
|
|
} else { // forward a single message at most
|
|
|
|
KMMessage *msg = msgList.getFirst();
|
|
if ( !msg || !msg->codec() )
|
|
return Failed;
|
|
|
|
KCursorSaver busy( KBusyPtr::busy() );
|
|
KMMessage *fwdMsg = msg->createForward();
|
|
|
|
uint id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
|
|
if ( id == 0 )
|
|
id = mIdentity;
|
|
{
|
|
KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
|
|
win->setCharset( fwdMsg->codec()->mimeName(), true );
|
|
win->setBody( fwdMsg->bodyToUnicode() );
|
|
win->show();
|
|
}
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMForwardAttachedCommand::KMForwardAttachedCommand( TQWidget *parent,
|
|
const TQPtrList<KMMsgBase> &msgList, uint identity, KMail::Composer *win )
|
|
: KMCommand( parent, msgList ), mIdentity( identity ),
|
|
mWin( TQGuardedPtr<KMail::Composer>( win ))
|
|
{
|
|
}
|
|
|
|
KMForwardAttachedCommand::KMForwardAttachedCommand( TQWidget *parent,
|
|
KMMessage * msg, uint identity, KMail::Composer *win )
|
|
: KMCommand( parent, msg ), mIdentity( identity ),
|
|
mWin( TQGuardedPtr< KMail::Composer >( win ))
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMForwardAttachedCommand::execute()
|
|
{
|
|
TQPtrList<KMMessage> msgList = retrievedMsgs();
|
|
KMMessage *fwdMsg = new KMMessage;
|
|
|
|
if (msgList.count() >= 2) {
|
|
// don't respect X-KMail-Identity headers because they might differ for
|
|
// the selected mails
|
|
fwdMsg->initHeader(mIdentity);
|
|
}
|
|
else if (msgList.count() == 1) {
|
|
KMMessage *msg = msgList.getFirst();
|
|
fwdMsg->initFromMessage(msg);
|
|
fwdMsg->setSubject( msg->forwardSubject() );
|
|
}
|
|
|
|
fwdMsg->setAutomaticFields(true);
|
|
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
if (!mWin)
|
|
mWin = KMail::makeComposer(fwdMsg, mIdentity);
|
|
|
|
// iterate through all the messages to be forwarded
|
|
for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
|
|
// remove headers that shouldn't be forwarded
|
|
msg->removePrivateHeaderFields();
|
|
msg->removeHeaderField("BCC");
|
|
// set the part
|
|
KMMessagePart *msgPart = new KMMessagePart;
|
|
msgPart->setTypeStr("message");
|
|
msgPart->setSubtypeStr("rfc822");
|
|
msgPart->setCharset(msg->charset());
|
|
msgPart->setName("forwarded message");
|
|
msgPart->setContentDescription(msg->from()+": "+msg->subject());
|
|
msgPart->setContentDisposition( "inline" );
|
|
// THIS HAS TO BE AFTER setCte()!!!!
|
|
msgPart->setMessageBody( KMail::Util::ByteArray( msg->asDwString() ) );
|
|
msgPart->setCharset("");
|
|
|
|
fwdMsg->link(msg, KMMsgStatusForwarded);
|
|
mWin->addAttach(msgPart);
|
|
}
|
|
|
|
mWin->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMForwardDigestCommand::KMForwardDigestCommand( TQWidget *parent,
|
|
const TQPtrList<KMMsgBase> &msgList, uint identity, KMail::Composer *win )
|
|
: KMCommand( parent, msgList ), mIdentity( identity ),
|
|
mWin( TQGuardedPtr<KMail::Composer>( win ))
|
|
{
|
|
}
|
|
|
|
KMForwardDigestCommand::KMForwardDigestCommand( TQWidget *parent,
|
|
KMMessage * msg, uint identity, KMail::Composer *win )
|
|
: KMCommand( parent, msg ), mIdentity( identity ),
|
|
mWin( TQGuardedPtr< KMail::Composer >( win ))
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMForwardDigestCommand::execute()
|
|
{
|
|
TQPtrList<KMMessage> msgList = retrievedMsgs();
|
|
|
|
if ( msgList.count() < 2 )
|
|
return Undefined; // must have more than 1 for a digest
|
|
|
|
uint id = 0;
|
|
KMMessage *fwdMsg = new KMMessage;
|
|
KMMessagePart *msgPart = new KMMessagePart;
|
|
TQString msgPartText;
|
|
int msgCnt = 0; // incase there are some we can't forward for some reason
|
|
|
|
// dummy header initialization; initialization with the correct identity
|
|
// is done below
|
|
fwdMsg->initHeader( id );
|
|
fwdMsg->setAutomaticFields( true );
|
|
fwdMsg->mMsg->Headers().ContentType().CreateBoundary( 1 );
|
|
TQCString boundary( fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() );
|
|
msgPartText = i18n("\nThis is a MIME digest forward. The content of the"
|
|
" message is contained in the attachment(s).\n\n\n");
|
|
// iterate through all the messages to be forwarded
|
|
for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
|
|
// set the identity
|
|
if ( id == 0 )
|
|
id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
|
|
// set the part header
|
|
msgPartText += "--";
|
|
msgPartText += TQString::fromLatin1( boundary );
|
|
msgPartText += "\nContent-Type: MESSAGE/RFC822";
|
|
msgPartText += TQString( "; CHARSET=%1" ).arg( msg->charset() );
|
|
msgPartText += '\n';
|
|
DwHeaders dwh;
|
|
dwh.MessageId().CreateDefault();
|
|
msgPartText += TQString( "Content-ID: %1\n" ).arg( dwh.MessageId().AsString().c_str() );
|
|
msgPartText += TQString( "Content-Description: %1" ).arg( msg->subject() );
|
|
if ( !msg->subject().contains( "(fwd)" ) )
|
|
msgPartText += " (fwd)";
|
|
msgPartText += "\n\n";
|
|
// remove headers that shouldn't be forwarded
|
|
msg->removePrivateHeaderFields();
|
|
msg->removeHeaderField( "BCC" );
|
|
// set the part
|
|
msgPartText += msg->headerAsString();
|
|
msgPartText += '\n';
|
|
msgPartText += msg->body();
|
|
msgPartText += '\n'; // eot
|
|
msgCnt++;
|
|
fwdMsg->link( msg, KMMsgStatusForwarded );
|
|
}
|
|
|
|
if ( id == 0 )
|
|
id = mIdentity; // use folder identity if no message had an id set
|
|
fwdMsg->initHeader( id );
|
|
msgPartText += "--";
|
|
msgPartText += TQString::fromLatin1( boundary );
|
|
msgPartText += "--\n";
|
|
TQCString tmp;
|
|
msgPart->setTypeStr( "MULTIPART" );
|
|
tmp.sprintf( "Digest; boundary=\"%s\"", boundary.data() );
|
|
msgPart->setSubtypeStr( tmp );
|
|
msgPart->setName( "unnamed" );
|
|
msgPart->setCte( DwMime::kCte7bit ); // does it have to be 7bit?
|
|
msgPart->setContentDescription( TQString( "Digest of %1 messages." ).arg( msgCnt ) );
|
|
// THIS HAS TO BE AFTER setCte()!!!!
|
|
msgPart->setBodyEncoded( TQCString( msgPartText.ascii() ) );
|
|
KCursorSaver busy( KBusyPtr::busy() );
|
|
KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
|
|
win->addAttach( msgPart );
|
|
win->show();
|
|
return OK;
|
|
}
|
|
|
|
KMRedirectCommand::KMRedirectCommand( TQWidget *parent,
|
|
KMMessage *msg )
|
|
: KMCommand( parent, msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMRedirectCommand::execute()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() )
|
|
return Failed;
|
|
|
|
RedirectDialog dlg( parentWidget(), "redirect", true,
|
|
kmkernel->msgSender()->sendImmediate() );
|
|
if (dlg.exec()==TQDialog::Rejected) return Failed;
|
|
|
|
KMMessage *newMsg = msg->createRedirect( dlg.to() );
|
|
KMFilterAction::sendMDN( msg, KMime::MDN::Dispatched );
|
|
|
|
const KMail::MessageSender::SendMethod method = dlg.sendImmediate()
|
|
? KMail::MessageSender::SendImmediate
|
|
: KMail::MessageSender::SendLater;
|
|
if ( !kmkernel->msgSender()->send( newMsg, method ) ) {
|
|
kdDebug(5006) << "KMRedirectCommand: could not redirect message (sending failed)" << endl;
|
|
return Failed; // error: couldn't send
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMCustomReplyToCommand::KMCustomReplyToCommand( TQWidget *parent, KMMessage *msg,
|
|
const TQString &selection,
|
|
const TQString &tmpl )
|
|
: KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMCustomReplyToCommand::execute()
|
|
{
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection,
|
|
false, true, false, mTemplate );
|
|
KMail::Composer * win = KMail::makeComposer( reply );
|
|
win->setCharset( msg->codec()->mimeName(), true );
|
|
win->setReplyFocus();
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMCustomReplyAllToCommand::KMCustomReplyAllToCommand( TQWidget *parent, KMMessage *msg,
|
|
const TQString &selection,
|
|
const TQString &tmpl )
|
|
: KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMCustomReplyAllToCommand::execute()
|
|
{
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection,
|
|
false, true, false, mTemplate );
|
|
KMail::Composer * win = KMail::makeComposer( reply );
|
|
win->setCharset( msg->codec()->mimeName(), true );
|
|
win->setReplyFocus();
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
|
|
const TQPtrList<KMMsgBase> &msgList, uint identity, const TQString &tmpl )
|
|
: KMCommand( parent, msgList ),
|
|
mIdentity( identity ), mTemplate( tmpl )
|
|
{
|
|
}
|
|
|
|
KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
|
|
KMMessage *msg, uint identity, const TQString &tmpl )
|
|
: KMCommand( parent, msg ),
|
|
mIdentity( identity ), mTemplate( tmpl )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMCustomForwardCommand::execute()
|
|
{
|
|
TQPtrList<KMMessage> msgList = retrievedMsgs();
|
|
|
|
if (msgList.count() >= 2) { // Multiple forward
|
|
|
|
uint id = 0;
|
|
TQPtrList<KMMessage> linklist;
|
|
for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
|
|
// set the identity
|
|
if (id == 0)
|
|
id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
|
|
|
|
// msgText += msg->createForwardBody();
|
|
linklist.append( msg );
|
|
}
|
|
if ( id == 0 )
|
|
id = mIdentity; // use folder identity if no message had an id set
|
|
KMMessage *fwdMsg = new KMMessage;
|
|
fwdMsg->initHeader( id );
|
|
fwdMsg->setAutomaticFields( true );
|
|
fwdMsg->setCharset( "utf-8" );
|
|
// fwdMsg->setBody( msgText );
|
|
|
|
for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
|
|
TemplateParser parser( fwdMsg, TemplateParser::Forward,
|
|
msg->body(), false, false, false, false);
|
|
parser.process( msg, 0, true );
|
|
|
|
fwdMsg->link( msg, KMMsgStatusForwarded );
|
|
}
|
|
|
|
KCursorSaver busy( KBusyPtr::busy() );
|
|
KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
|
|
win->setCharset("");
|
|
win->show();
|
|
|
|
} else { // forward a single message at most
|
|
|
|
KMMessage *msg = msgList.getFirst();
|
|
if ( !msg || !msg->codec() )
|
|
return Failed;
|
|
|
|
KCursorSaver busy( KBusyPtr::busy() );
|
|
KMMessage *fwdMsg = msg->createForward( mTemplate );
|
|
|
|
uint id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
|
|
if ( id == 0 )
|
|
id = mIdentity;
|
|
{
|
|
KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
|
|
win->setCharset( fwdMsg->codec()->mimeName(), true );
|
|
win->show();
|
|
}
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMPrintCommand::KMPrintCommand( TQWidget *parent,
|
|
KMMessage *msg, bool htmlOverride, bool htmlLoadExtOverride,
|
|
bool useFixedFont, const TQString & encoding )
|
|
: KMCommand( parent, msg ), mHtmlOverride( htmlOverride ),
|
|
mHtmlLoadExtOverride( htmlLoadExtOverride ),
|
|
mUseFixedFont( useFixedFont ), mEncoding( encoding )
|
|
{
|
|
mOverrideFont = KGlobalSettings::generalFont();
|
|
}
|
|
|
|
|
|
void KMPrintCommand::setOverrideFont( const TQFont& font )
|
|
{
|
|
mOverrideFont = font;
|
|
}
|
|
|
|
KMCommand::Result KMPrintCommand::execute()
|
|
{
|
|
KMReaderWin printWin( 0, 0, 0 );
|
|
printWin.setPrinting( true );
|
|
printWin.readConfig();
|
|
printWin.setHtmlOverride( mHtmlOverride );
|
|
printWin.setHtmlLoadExtOverride( mHtmlLoadExtOverride );
|
|
printWin.setUseFixedFont( mUseFixedFont );
|
|
printWin.setOverrideEncoding( mEncoding );
|
|
printWin.setPrintFont( mOverrideFont );
|
|
printWin.setDecryptMessageOverwrite( true );
|
|
printWin.setMsg( retrievedMessage(), true );
|
|
printWin.printMsg();
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMSetStatusCommand::KMSetStatusCommand( KMMsgStatus status,
|
|
const TQValueList<Q_UINT32> &serNums, bool toggle )
|
|
: mStatus( status ), mSerNums( serNums ), mToggle( toggle )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMSetStatusCommand::execute()
|
|
{
|
|
TQValueListIterator<Q_UINT32> it;
|
|
int idx = -1;
|
|
KMFolder *folder = 0;
|
|
bool parentStatus = false;
|
|
|
|
// Toggle actions on threads toggle the whole thread
|
|
// depending on the state of the parent.
|
|
if (mToggle) {
|
|
KMMsgBase *msg;
|
|
KMMsgDict::instance()->getLocation( *mSerNums.begin(), &folder, &idx );
|
|
if (folder) {
|
|
msg = folder->getMsgBase(idx);
|
|
if (msg && (msg->status()&mStatus))
|
|
parentStatus = true;
|
|
else
|
|
parentStatus = false;
|
|
}
|
|
}
|
|
TQMap< KMFolder*, TQValueList<int> > folderMap;
|
|
for ( it = mSerNums.begin(); it != mSerNums.end(); ++it ) {
|
|
KMMsgDict::instance()->getLocation( *it, &folder, &idx );
|
|
if (folder) {
|
|
if (mToggle) {
|
|
KMMsgBase *msg = folder->getMsgBase(idx);
|
|
// check if we are already at the target toggle state
|
|
if (msg) {
|
|
bool myStatus;
|
|
if (msg->status()&mStatus)
|
|
myStatus = true;
|
|
else
|
|
myStatus = false;
|
|
if (myStatus != parentStatus)
|
|
continue;
|
|
}
|
|
}
|
|
/* Collect the ids for each folder in a separate list and
|
|
send them off in one go at the end. */
|
|
folderMap[folder].append(idx);
|
|
}
|
|
}
|
|
TQMapIterator< KMFolder*, TQValueList<int> > it2 = folderMap.begin();
|
|
while ( it2 != folderMap.end() ) {
|
|
KMFolder *f = it2.key();
|
|
f->setStatus( (*it2), mStatus, mToggle );
|
|
++it2;
|
|
}
|
|
//kapp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", TQByteArray() );
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMFilterCommand::KMFilterCommand( const TQCString &field, const TQString &value )
|
|
: mField( field ), mValue( value )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMFilterCommand::execute()
|
|
{
|
|
kmkernel->filterMgr()->createFilter( mField, mValue );
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMFilterActionCommand::KMFilterActionCommand( TQWidget *parent,
|
|
const TQPtrList<KMMsgBase> &msgList,
|
|
KMFilter *filter )
|
|
: KMCommand( parent, msgList ), mFilter( filter )
|
|
{
|
|
TQPtrListIterator<KMMsgBase> it(msgList);
|
|
while ( it.current() ) {
|
|
serNumList.append( (*it)->getMsgSerNum() );
|
|
++it;
|
|
}
|
|
}
|
|
|
|
KMCommand::Result KMFilterActionCommand::execute()
|
|
{
|
|
KCursorSaver busy( KBusyPtr::busy() );
|
|
|
|
int msgCount = 0;
|
|
int msgCountToFilter = serNumList.count();
|
|
ProgressItem* progressItem =
|
|
ProgressManager::createProgressItem ( "filter"+ProgressManager::getUniqueID(),
|
|
i18n( "Filtering messages" ) );
|
|
progressItem->setTotalItems( msgCountToFilter );
|
|
TQValueList<Q_UINT32>::const_iterator it;
|
|
for ( it = serNumList.begin(); it != serNumList.end(); it++ ) {
|
|
Q_UINT32 serNum = *it;
|
|
int diff = msgCountToFilter - ++msgCount;
|
|
if ( diff < 10 || !( msgCount % 20 ) || msgCount <= 10 ) {
|
|
progressItem->updateProgress();
|
|
TQString statusMsg = i18n("Filtering message %1 of %2");
|
|
statusMsg = statusMsg.arg( msgCount ).arg( msgCountToFilter );
|
|
KPIM::BroadcastStatus::instance()->setStatusMsg( statusMsg );
|
|
KApplication::kApplication()->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput, 50 );
|
|
}
|
|
|
|
int filterResult = kmkernel->filterMgr()->process( serNum, mFilter );
|
|
if (filterResult == 2) {
|
|
// something went horribly wrong (out of space?)
|
|
perror("Critical error");
|
|
kmkernel->emergencyExit( i18n("Not enough free disk space?" ));
|
|
}
|
|
progressItem->incCompletedItems();
|
|
}
|
|
|
|
progressItem->setComplete();
|
|
progressItem = 0;
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter,
|
|
KMHeaders *headers,
|
|
KMMainWidget *main )
|
|
: TQObject( main ),
|
|
mFilter( filter ), mHeaders( headers ), mMainWidget( main )
|
|
{
|
|
}
|
|
|
|
void KMMetaFilterActionCommand::start()
|
|
{
|
|
if (ActionScheduler::isEnabled() ) {
|
|
// use action scheduler
|
|
KMFilterMgr::FilterSet set = KMFilterMgr::All;
|
|
TQValueList<KMFilter*> filters;
|
|
filters.append( mFilter );
|
|
ActionScheduler *scheduler = new ActionScheduler( set, filters, mHeaders );
|
|
scheduler->setAlwaysMatch( true );
|
|
scheduler->setAutoDestruct( true );
|
|
|
|
int contentX, contentY;
|
|
HeaderItem *nextItem = mHeaders->prepareMove( &contentX, &contentY );
|
|
TQPtrList<KMMsgBase> msgList = *mHeaders->selectedMsgs(true);
|
|
mHeaders->finalizeMove( nextItem, contentX, contentY );
|
|
|
|
for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
|
|
scheduler->execFilters( msg );
|
|
} else {
|
|
KMCommand *filterCommand =
|
|
new KMFilterActionCommand( mMainWidget,
|
|
*mHeaders->selectedMsgs(), mFilter );
|
|
filterCommand->start();
|
|
int contentX, contentY;
|
|
HeaderItem *item = mHeaders->prepareMove( &contentX, &contentY );
|
|
mHeaders->finalizeMove( item, contentX, contentY );
|
|
}
|
|
}
|
|
|
|
FolderShortcutCommand::FolderShortcutCommand( KMMainWidget *mainwidget,
|
|
KMFolder *folder )
|
|
: mMainWidget( mainwidget ), mFolder( folder ), mAction( 0 )
|
|
{
|
|
}
|
|
|
|
|
|
FolderShortcutCommand::~FolderShortcutCommand()
|
|
{
|
|
if ( mAction ) mAction->unplugAll();
|
|
delete mAction;
|
|
}
|
|
|
|
void FolderShortcutCommand::start()
|
|
{
|
|
mMainWidget->slotSelectFolder( mFolder );
|
|
}
|
|
|
|
void FolderShortcutCommand::setAction( KAction* action )
|
|
{
|
|
mAction = action;
|
|
}
|
|
|
|
KMMailingListFilterCommand::KMMailingListFilterCommand( TQWidget *parent,
|
|
KMMessage *msg )
|
|
: KMCommand( parent, msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMMailingListFilterCommand::execute()
|
|
{
|
|
TQCString name;
|
|
TQString value;
|
|
KMMessage *msg = retrievedMessage();
|
|
if (!msg)
|
|
return Failed;
|
|
|
|
if ( !MailingList::name( msg, name, value ).isEmpty() ) {
|
|
kmkernel->filterMgr()->createFilter( name, value );
|
|
return OK;
|
|
}
|
|
else
|
|
return Failed;
|
|
}
|
|
|
|
|
|
void KMMenuCommand::folderToPopupMenu(bool move,
|
|
TQObject *receiver, KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu )
|
|
{
|
|
while ( menu->count() )
|
|
{
|
|
TQPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
|
|
if (popup)
|
|
delete popup;
|
|
else
|
|
menu->removeItemAt( 0 );
|
|
}
|
|
|
|
if (!kmkernel->imapFolderMgr()->dir().first() &&
|
|
!kmkernel->dimapFolderMgr()->dir().first())
|
|
{ // only local folders
|
|
makeFolderMenu( &kmkernel->folderMgr()->dir(), move,
|
|
receiver, aMenuToFolder, menu );
|
|
} else {
|
|
// operate on top-level items
|
|
TQPopupMenu* subMenu = new TQPopupMenu(menu);
|
|
makeFolderMenu( &kmkernel->folderMgr()->dir(),
|
|
move, receiver, aMenuToFolder, subMenu );
|
|
menu->insertItem( i18n( "Local Folders" ), subMenu );
|
|
KMFolderDir* fdir = &kmkernel->imapFolderMgr()->dir();
|
|
for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
|
|
if (node->isDir())
|
|
continue;
|
|
subMenu = new TQPopupMenu(menu);
|
|
makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
|
|
menu->insertItem( node->label(), subMenu );
|
|
}
|
|
fdir = &kmkernel->dimapFolderMgr()->dir();
|
|
for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
|
|
if (node->isDir())
|
|
continue;
|
|
subMenu = new TQPopupMenu(menu);
|
|
makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
|
|
menu->insertItem( node->label(), subMenu );
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMMenuCommand::makeFolderMenu(KMFolderNode* node, bool move,
|
|
TQObject *receiver, KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu )
|
|
{
|
|
// connect the signals
|
|
if (move)
|
|
{
|
|
disconnect(menu, TQT_SIGNAL(activated(int)), receiver,
|
|
TQT_SLOT(moveSelectedToFolder(int)));
|
|
connect(menu, TQT_SIGNAL(activated(int)), receiver,
|
|
TQT_SLOT(moveSelectedToFolder(int)));
|
|
} else {
|
|
disconnect(menu, TQT_SIGNAL(activated(int)), receiver,
|
|
TQT_SLOT(copySelectedToFolder(int)));
|
|
connect(menu, TQT_SIGNAL(activated(int)), receiver,
|
|
TQT_SLOT(copySelectedToFolder(int)));
|
|
}
|
|
|
|
KMFolder *folder = 0;
|
|
KMFolderDir *folderDir = 0;
|
|
if (node->isDir()) {
|
|
folderDir = static_cast<KMFolderDir*>(node);
|
|
} else {
|
|
folder = static_cast<KMFolder*>(node);
|
|
folderDir = folder->child();
|
|
}
|
|
|
|
if (folder && !folder->noContent())
|
|
{
|
|
int menuId;
|
|
if (move)
|
|
menuId = menu->insertItem(i18n("Move to This Folder"));
|
|
else
|
|
menuId = menu->insertItem(i18n("Copy to This Folder"));
|
|
aMenuToFolder->insert( menuId, folder );
|
|
menu->setItemEnabled( menuId, !folder->isReadOnly() );
|
|
menu->insertSeparator();
|
|
}
|
|
|
|
if (!folderDir)
|
|
return;
|
|
|
|
for (KMFolderNode *it = folderDir->first(); it; it = folderDir->next() ) {
|
|
if (it->isDir())
|
|
continue;
|
|
KMFolder *child = static_cast<KMFolder*>(it);
|
|
TQString label = child->label();
|
|
label.replace("&","&&");
|
|
if (child->child() && child->child()->first()) {
|
|
// descend
|
|
TQPopupMenu *subMenu = new TQPopupMenu(menu, "subMenu");
|
|
makeFolderMenu( child, move, receiver,
|
|
aMenuToFolder, subMenu );
|
|
menu->insertItem( label, subMenu );
|
|
} else {
|
|
// insert an item
|
|
int menuId = menu->insertItem( label );
|
|
aMenuToFolder->insert( menuId, child );
|
|
menu->setItemEnabled( menuId, !child->isReadOnly() );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
KMCopyCommand::KMCopyCommand( KMFolder* destFolder,
|
|
const TQPtrList<KMMsgBase> &msgList )
|
|
:mDestFolder( destFolder ), mMsgList( msgList )
|
|
{
|
|
setDeletesItself( true );
|
|
}
|
|
|
|
KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg )
|
|
:mDestFolder( destFolder )
|
|
{
|
|
setDeletesItself( true );
|
|
mMsgList.append( &msg->toMsgBase() );
|
|
}
|
|
|
|
KMCommand::Result KMCopyCommand::execute()
|
|
{
|
|
KMMsgBase *msgBase;
|
|
KMMessage *msg, *newMsg;
|
|
int idx = -1;
|
|
bool isMessage;
|
|
TQPtrList<KMMessage> list;
|
|
TQPtrList<KMMessage> localList;
|
|
|
|
if (mDestFolder && mDestFolder->open("kmcommand") != 0)
|
|
{
|
|
deleteLater();
|
|
return Failed;
|
|
}
|
|
|
|
setEmitsCompletedItself( true );
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
|
|
for (msgBase = mMsgList.first(); msgBase; msgBase = mMsgList.next() )
|
|
{
|
|
KMFolder *srcFolder = msgBase->parent();
|
|
if (( isMessage = msgBase->isMessage() ))
|
|
{
|
|
msg = static_cast<KMMessage*>(msgBase);
|
|
} else {
|
|
idx = srcFolder->find(msgBase);
|
|
assert(idx != -1);
|
|
msg = srcFolder->getMsg(idx);
|
|
// corrupt IMAP cache, see FolderStorage::getMsg()
|
|
if ( msg == 0 ) {
|
|
KMessageBox::error( parentWidget(), i18n("Corrupt IMAP cache detected in folder %1. "
|
|
"Copying of messages aborted.").arg( srcFolder->prettyURL() ) );
|
|
deleteLater();
|
|
return Failed;
|
|
}
|
|
}
|
|
|
|
if (srcFolder && mDestFolder &&
|
|
(srcFolder->folderType()== KMFolderTypeImap) &&
|
|
(mDestFolder->folderType() == KMFolderTypeImap) &&
|
|
(static_cast<KMFolderImap*>(srcFolder->storage())->account() ==
|
|
static_cast<KMFolderImap*>(mDestFolder->storage())->account()))
|
|
{
|
|
// imap => imap with same account
|
|
list.append(msg);
|
|
} else {
|
|
newMsg = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
|
|
newMsg->setComplete(msg->isComplete());
|
|
// make sure the attachment state is only calculated when it's complete
|
|
if (!newMsg->isComplete())
|
|
newMsg->setReadyToShow(false);
|
|
newMsg->setStatus(msg->status());
|
|
|
|
if (srcFolder && !newMsg->isComplete())
|
|
{
|
|
// imap => others
|
|
newMsg->setParent(msg->parent());
|
|
FolderJob *job = srcFolder->createJob(newMsg);
|
|
job->setCancellable( false );
|
|
mPendingJobs << job;
|
|
connect(job, TQT_SIGNAL(messageRetrieved(KMMessage*)),
|
|
mDestFolder, TQT_SLOT(reallyAddCopyOfMsg(KMMessage*)));
|
|
connect( job, TQT_SIGNAL(result(KMail::FolderJob*)),
|
|
this, TQT_SLOT(slotJobFinished(KMail::FolderJob*)) );
|
|
job->start();
|
|
} else {
|
|
// local => others
|
|
localList.append(newMsg);
|
|
}
|
|
}
|
|
|
|
if (srcFolder && !isMessage && list.isEmpty())
|
|
{
|
|
assert(idx != -1);
|
|
srcFolder->unGetMsg( idx );
|
|
}
|
|
|
|
} // end for
|
|
|
|
bool deleteNow = false;
|
|
if (!localList.isEmpty())
|
|
{
|
|
TQValueList<int> index;
|
|
mDestFolder->addMsg( localList, index );
|
|
for ( TQValueListIterator<int> it = index.begin(); it != index.end(); ++it ) {
|
|
mDestFolder->unGetMsg( *it );
|
|
}
|
|
if ( mDestFolder->folderType() == KMFolderTypeImap ) {
|
|
if ( mPendingJobs.isEmpty() ) {
|
|
// wait for the end of the copy before closing the folder
|
|
KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
|
|
connect( imapDestFolder, TQT_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
|
|
this, TQT_SLOT( slotFolderComplete( KMFolderImap*, bool ) ) );
|
|
}
|
|
} else {
|
|
deleteNow = list.isEmpty() && mPendingJobs.isEmpty(); // we're done if there are no other mails we need to fetch
|
|
}
|
|
}
|
|
|
|
//TODO: Get rid of the other cases just use this one for all types of folder
|
|
//TODO: requires adding copyMsg and getFolder methods to KMFolder.h
|
|
if (!list.isEmpty())
|
|
{
|
|
// copy the message(s); note: the list is empty afterwards!
|
|
KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
|
|
connect( imapDestFolder, TQT_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
|
|
this, TQT_SLOT( slotFolderComplete( KMFolderImap*, bool ) ) );
|
|
imapDestFolder->copyMsg(list);
|
|
imapDestFolder->getFolder();
|
|
}
|
|
|
|
// only close the folder and delete the job if we're done
|
|
// otherwise this is done in slotMsgAdded or slotFolderComplete
|
|
if ( deleteNow )
|
|
{
|
|
mDestFolder->close("kmcommand");
|
|
setResult( OK );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
void KMCopyCommand::slotJobFinished(KMail::FolderJob * job)
|
|
{
|
|
mPendingJobs.remove( job );
|
|
if ( job->error() ) {
|
|
kdDebug(5006) << k_funcinfo << "folder job failed: " << job->error() << endl;
|
|
// kill all pending jobs
|
|
for ( TQValueList<KMail::FolderJob*>::Iterator it = mPendingJobs.begin(); it != mPendingJobs.end(); ++it ) {
|
|
disconnect( (*it), TQT_SIGNAL(result(KMail::FolderJob*)),
|
|
this, TQT_SLOT(slotJobFinished(KMail::FolderJob*)) );
|
|
(*it)->kill();
|
|
}
|
|
mPendingJobs.clear();
|
|
setResult( Failed );
|
|
}
|
|
|
|
if ( mPendingJobs.isEmpty() )
|
|
{
|
|
mDestFolder->close("kmcommand");
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
}
|
|
|
|
void KMCopyCommand::slotFolderComplete( KMFolderImap*, bool success )
|
|
{
|
|
kdDebug(5006) << k_funcinfo << success << endl;
|
|
if ( !success )
|
|
setResult( Failed );
|
|
mDestFolder->close( "kmcommand" );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
|
|
|
|
KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
|
|
const TQPtrList<KMMsgBase> &msgList)
|
|
: mDestFolder( destFolder ), mProgressItem( 0 )
|
|
{
|
|
TQPtrList<KMMsgBase> tmp = msgList;
|
|
for ( KMMsgBase *msgBase = tmp.first(); msgBase; msgBase = tmp.next() )
|
|
mSerNumList.append( msgBase->getMsgSerNum() );
|
|
}
|
|
|
|
KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
|
|
KMMessage *msg )
|
|
: mDestFolder( destFolder ), mProgressItem( 0 )
|
|
{
|
|
mSerNumList.append( msg->getMsgSerNum() );
|
|
}
|
|
|
|
KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
|
|
KMMsgBase *msgBase )
|
|
: mDestFolder( destFolder ), mProgressItem( 0 )
|
|
{
|
|
mSerNumList.append( msgBase->getMsgSerNum() );
|
|
}
|
|
|
|
KMMoveCommand::KMMoveCommand( Q_UINT32 )
|
|
: mProgressItem( 0 )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMMoveCommand::execute()
|
|
{
|
|
setEmitsCompletedItself( true );
|
|
setDeletesItself( true );
|
|
typedef TQMap< KMFolder*, TQPtrList<KMMessage>* > FolderToMessageListMap;
|
|
FolderToMessageListMap folderDeleteList;
|
|
|
|
if (mDestFolder && mDestFolder->open("kmcommand") != 0) {
|
|
completeMove( Failed );
|
|
return Failed;
|
|
}
|
|
KCursorSaver busy(KBusyPtr::busy());
|
|
|
|
// TODO set SSL state according to source and destfolder connection?
|
|
Q_ASSERT( !mProgressItem );
|
|
mProgressItem =
|
|
ProgressManager::createProgressItem (
|
|
"move"+ProgressManager::getUniqueID(),
|
|
mDestFolder ? i18n( "Moving messages" ) : i18n( "Deleting messages" ) );
|
|
connect( mProgressItem, TQT_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
|
|
this, TQT_SLOT( slotMoveCanceled() ) );
|
|
|
|
KMMessage *msg;
|
|
int rc = 0;
|
|
int index;
|
|
TQPtrList<KMMessage> list;
|
|
int undoId = -1;
|
|
mCompleteWithAddedMsg = false;
|
|
|
|
if (mDestFolder) {
|
|
connect (mDestFolder, TQT_SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
|
|
this, TQT_SLOT(slotMsgAddedToDestFolder(KMFolder*, Q_UINT32)));
|
|
mLostBoys = mSerNumList;
|
|
}
|
|
mProgressItem->setTotalItems( mSerNumList.count() );
|
|
|
|
for ( TQValueList<Q_UINT32>::ConstIterator it = mSerNumList.constBegin(); it != mSerNumList.constEnd(); ++it ) {
|
|
KMFolder *srcFolder;
|
|
int idx = -1;
|
|
KMMsgDict::instance()->getLocation( *it, &srcFolder, &idx );
|
|
if (srcFolder == mDestFolder)
|
|
continue;
|
|
assert(idx != -1);
|
|
srcFolder->open( "kmmovecommand" );
|
|
mOpenedFolders.append( srcFolder );
|
|
msg = srcFolder->getMsg(idx);
|
|
if ( !msg ) {
|
|
kdDebug(5006) << k_funcinfo << "No message found for serial number " << *it << endl;
|
|
continue;
|
|
}
|
|
bool undo = msg->enableUndo();
|
|
|
|
if ( msg && msg->transferInProgress() &&
|
|
srcFolder->folderType() == KMFolderTypeImap )
|
|
{
|
|
// cancel the download
|
|
msg->setTransferInProgress( false, true );
|
|
static_cast<KMFolderImap*>(srcFolder->storage())->ignoreJobsForMessage( msg );
|
|
}
|
|
|
|
if (mDestFolder) {
|
|
if (mDestFolder->folderType() == KMFolderTypeImap) {
|
|
/* If we are moving to an imap folder, connect to it's completed
|
|
* signal so we notice when all the mails should have showed up in it
|
|
* but haven't for some reason. */
|
|
KMFolderImap *imapFolder = static_cast<KMFolderImap*> ( mDestFolder->storage() );
|
|
disconnect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
|
|
this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
|
|
|
|
connect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
|
|
this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
|
|
list.append(msg);
|
|
} else {
|
|
// We are moving to a local folder.
|
|
if ( srcFolder->folderType() == KMFolderTypeImap )
|
|
{
|
|
// do not complete here but wait until all messages are transferred
|
|
mCompleteWithAddedMsg = true;
|
|
}
|
|
rc = mDestFolder->moveMsg(msg, &index);
|
|
if (rc == 0 && index != -1) {
|
|
KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 );
|
|
if (undo && mb)
|
|
{
|
|
if ( undoId == -1 )
|
|
undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder );
|
|
kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() );
|
|
}
|
|
} else if (rc != 0) {
|
|
// Something went wrong. Stop processing here, it is likely that the
|
|
// other moves would fail as well.
|
|
completeMove( Failed );
|
|
return Failed;
|
|
}
|
|
}
|
|
} else {
|
|
// really delete messages that are already in the trash folder or if
|
|
// we are really, really deleting, not just moving to trash
|
|
if (srcFolder->folderType() == KMFolderTypeImap) {
|
|
if (!folderDeleteList[srcFolder])
|
|
folderDeleteList[srcFolder] = new TQPtrList<KMMessage>;
|
|
folderDeleteList[srcFolder]->append( msg );
|
|
} else {
|
|
srcFolder->removeMsg(idx);
|
|
delete msg;
|
|
}
|
|
}
|
|
}
|
|
if (!list.isEmpty() && mDestFolder) {
|
|
// will be completed with folderComplete signal
|
|
mDestFolder->moveMsg(list, &index);
|
|
} else {
|
|
FolderToMessageListMap::Iterator it;
|
|
for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
|
|
it.key()->removeMsg(*it.data());
|
|
delete it.data();
|
|
}
|
|
if ( !mCompleteWithAddedMsg ) {
|
|
// imap folders will be completed in slotMsgAddedToDestFolder
|
|
completeMove( OK );
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
void KMMoveCommand::slotImapFolderCompleted(KMFolderImap* imapFolder, bool success)
|
|
{
|
|
disconnect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
|
|
this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
|
|
if ( success ) {
|
|
// the folder was checked successfully but we were still called, so check
|
|
// if we are still waiting for messages to show up. If so, uidValidity
|
|
// changed, or something else went wrong. Clean up.
|
|
|
|
/* Unfortunately older UW imap servers change uid validity for each put job.
|
|
* Yes, it is really that broken. *sigh* So we cannot report error here, I guess. */
|
|
if ( !mLostBoys.isEmpty() ) {
|
|
kdDebug(5006) << "### Not all moved messages reported back that they were " << endl
|
|
<< "### added to the target folder. Did uidValidity change? " << endl;
|
|
}
|
|
completeMove( OK );
|
|
} else {
|
|
// Should we inform the user here or leave that to the caller?
|
|
completeMove( Failed );
|
|
}
|
|
}
|
|
|
|
void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, Q_UINT32 serNum)
|
|
{
|
|
if ( folder != mDestFolder || mLostBoys.find( serNum ) == mLostBoys.end() ) {
|
|
//kdDebug(5006) << "KMMoveCommand::msgAddedToDestFolder different "
|
|
// "folder or invalid serial number." << endl;
|
|
return;
|
|
}
|
|
mLostBoys.remove(serNum);
|
|
if ( mLostBoys.isEmpty() ) {
|
|
// we are done. All messages transferred to the host succesfully
|
|
disconnect (mDestFolder, TQT_SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
|
|
this, TQT_SLOT(slotMsgAddedToDestFolder(KMFolder*, Q_UINT32)));
|
|
if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) {
|
|
mDestFolder->sync();
|
|
}
|
|
if ( mCompleteWithAddedMsg ) {
|
|
completeMove( OK );
|
|
}
|
|
} else {
|
|
if ( mProgressItem ) {
|
|
mProgressItem->incCompletedItems();
|
|
mProgressItem->updateProgress();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMMoveCommand::completeMove( Result result )
|
|
{
|
|
if ( mDestFolder )
|
|
mDestFolder->close("kmcommand");
|
|
while ( !mOpenedFolders.empty() ) {
|
|
KMFolder *folder = mOpenedFolders.back();
|
|
mOpenedFolders.pop_back();
|
|
folder->close("kmcommand");
|
|
}
|
|
if ( mProgressItem ) {
|
|
mProgressItem->setComplete();
|
|
mProgressItem = 0;
|
|
}
|
|
setResult( result );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
|
|
void KMMoveCommand::slotMoveCanceled()
|
|
{
|
|
completeMove( Canceled );
|
|
}
|
|
|
|
// srcFolder doesn't make much sense for searchFolders
|
|
KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder,
|
|
const TQPtrList<KMMsgBase> &msgList )
|
|
:KMMoveCommand( findTrashFolder( srcFolder ), msgList)
|
|
{
|
|
srcFolder->open("kmcommand");
|
|
mOpenedFolders.push_back( srcFolder );
|
|
}
|
|
|
|
KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
|
|
:KMMoveCommand( findTrashFolder( srcFolder ), msg)
|
|
{
|
|
srcFolder->open("kmcommand");
|
|
mOpenedFolders.push_back( srcFolder );
|
|
}
|
|
|
|
KMDeleteMsgCommand::KMDeleteMsgCommand( Q_UINT32 sernum )
|
|
:KMMoveCommand( sernum )
|
|
{
|
|
KMFolder *srcFolder = 0;
|
|
int idx;
|
|
KMMsgDict::instance()->getLocation( sernum, &srcFolder, &idx );
|
|
if ( srcFolder ) {
|
|
KMMsgBase *msg = srcFolder->getMsgBase( idx );
|
|
srcFolder->open("kmcommand");
|
|
mOpenedFolders.push_back( srcFolder );
|
|
addMsg( msg );
|
|
}
|
|
setDestFolder( findTrashFolder( srcFolder ) );
|
|
}
|
|
|
|
KMFolder * KMDeleteMsgCommand::findTrashFolder( KMFolder * folder )
|
|
{
|
|
KMFolder* trash = folder->trashFolder();
|
|
if( !trash )
|
|
trash = kmkernel->trashFolder();
|
|
if( trash != folder )
|
|
return trash;
|
|
return 0;
|
|
}
|
|
|
|
|
|
KMUrlClickedCommand::KMUrlClickedCommand( const KURL &url, uint identity,
|
|
KMReaderWin *readerWin, bool htmlPref, KMMainWidget *mainWidget )
|
|
:mUrl( url ), mIdentity( identity ), mReaderWin( readerWin ),
|
|
mHtmlPref( htmlPref ), mMainWidget( mainWidget )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMUrlClickedCommand::execute()
|
|
{
|
|
KMMessage* msg;
|
|
|
|
if (mUrl.protocol() == "mailto")
|
|
{
|
|
msg = new KMMessage;
|
|
msg->initHeader(mIdentity);
|
|
msg->setCharset("utf-8");
|
|
msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
|
|
TQString query=mUrl.query();
|
|
while (!query.isEmpty()) {
|
|
TQString queryPart;
|
|
int secondQuery = query.find('?',1);
|
|
if (secondQuery != -1)
|
|
queryPart = query.left(secondQuery);
|
|
else
|
|
queryPart = query;
|
|
query = query.mid(queryPart.length());
|
|
|
|
if (queryPart.left(9) == "?subject=")
|
|
msg->setSubject( KURL::decode_string(queryPart.mid(9)) );
|
|
else if (queryPart.left(6) == "?body=")
|
|
// It is correct to convert to latin1() as URL should not contain
|
|
// anything except ascii.
|
|
msg->setBody( KURL::decode_string(queryPart.mid(6)).latin1() );
|
|
else if (queryPart.left(4) == "?cc=")
|
|
msg->setCc( KURL::decode_string(queryPart.mid(4)) );
|
|
}
|
|
|
|
KMail::Composer * win = KMail::makeComposer( msg, mIdentity );
|
|
win->setCharset("", true);
|
|
win->show();
|
|
}
|
|
else if ( mUrl.protocol() == "im" )
|
|
{
|
|
kmkernel->imProxy()->chatWithContact( mUrl.path() );
|
|
}
|
|
else if ((mUrl.protocol() == "http") || (mUrl.protocol() == "https") ||
|
|
(mUrl.protocol() == "ftp") || (mUrl.protocol() == "file") ||
|
|
(mUrl.protocol() == "ftps") || (mUrl.protocol() == "sftp" ) ||
|
|
(mUrl.protocol() == "help") || (mUrl.protocol() == "vnc") ||
|
|
(mUrl.protocol() == "smb") || (mUrl.protocol() == "fish") ||
|
|
(mUrl.protocol() == "news"))
|
|
{
|
|
KPIM::BroadcastStatus::instance()->setStatusMsg( i18n("Opening URL..."));
|
|
KMimeType::Ptr mime = KMimeType::findByURL( mUrl );
|
|
if (mime->name() == "application/x-desktop" ||
|
|
mime->name() == "application/x-executable" ||
|
|
mime->name() == "application/x-msdos-program" ||
|
|
mime->name() == "application/x-shellscript" )
|
|
{
|
|
if (KMessageBox::warningYesNo( 0, i18n( "<qt>Do you really want to execute <b>%1</b>?</qt>" )
|
|
.arg( mUrl.prettyURL() ), TQString::null, i18n("Execute"), KStdGuiItem::cancel() ) != KMessageBox::Yes)
|
|
return Canceled;
|
|
}
|
|
KRun * runner = new KRun( mUrl );
|
|
runner->setRunExecutables( false );
|
|
}
|
|
else
|
|
return Failed;
|
|
|
|
return OK;
|
|
}
|
|
|
|
KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, KMMessage *msg )
|
|
: KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
|
|
{
|
|
}
|
|
|
|
KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, const TQPtrList<KMMsgBase>& msgs )
|
|
: KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
|
|
{
|
|
}
|
|
|
|
KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, TQPtrList<partNode>& attachments,
|
|
KMMessage *msg, bool encoded )
|
|
: KMCommand( parent ), mImplicitAttachments( false ), mEncoded( encoded )
|
|
{
|
|
for ( TQPtrListIterator<partNode> it( attachments ); it.current(); ++it ) {
|
|
mAttachmentMap.insert( it.current(), msg );
|
|
}
|
|
}
|
|
|
|
KMCommand::Result KMSaveAttachmentsCommand::execute()
|
|
{
|
|
setEmitsCompletedItself( true );
|
|
if ( mImplicitAttachments ) {
|
|
TQPtrList<KMMessage> msgList = retrievedMsgs();
|
|
KMMessage *msg;
|
|
for ( TQPtrListIterator<KMMessage> itr( msgList );
|
|
( msg = itr.current() );
|
|
++itr ) {
|
|
partNode *rootNode = partNode::fromMessage( msg );
|
|
for ( partNode *child = rootNode; child;
|
|
child = child->firstChild() ) {
|
|
for ( partNode *node = child; node; node = node->nextSibling() ) {
|
|
if ( node->type() != DwMime::kTypeMultipart )
|
|
mAttachmentMap.insert( node, msg );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
setDeletesItself( true );
|
|
// load all parts
|
|
KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachmentMap );
|
|
connect( command, TQT_SIGNAL( partsRetrieved() ),
|
|
this, TQT_SLOT( slotSaveAll() ) );
|
|
command->start();
|
|
|
|
return OK;
|
|
}
|
|
|
|
void KMSaveAttachmentsCommand::slotSaveAll()
|
|
{
|
|
// now that all message parts have been retrieved, remove all parts which
|
|
// don't represent an attachment if they were not explicitely passed in the
|
|
// c'tor
|
|
if ( mImplicitAttachments ) {
|
|
for ( PartNodeMessageMap::iterator it = mAttachmentMap.begin();
|
|
it != mAttachmentMap.end(); ) {
|
|
// only body parts which have a filename or a name parameter (except for
|
|
// the root node for which name is set to the message's subject) are
|
|
// considered attachments
|
|
if ( it.key()->msgPart().fileName().stripWhiteSpace().isEmpty() &&
|
|
( it.key()->msgPart().name().stripWhiteSpace().isEmpty() ||
|
|
!it.key()->parentNode() ) ) {
|
|
PartNodeMessageMap::iterator delIt = it;
|
|
++it;
|
|
mAttachmentMap.remove( delIt );
|
|
}
|
|
else
|
|
++it;
|
|
}
|
|
if ( mAttachmentMap.isEmpty() ) {
|
|
KMessageBox::information( 0, i18n("Found no attachments to save.") );
|
|
setResult( OK ); // The user has already been informed.
|
|
emit completed( this );
|
|
deleteLater();
|
|
return;
|
|
}
|
|
}
|
|
|
|
KURL url, dirUrl;
|
|
if ( mAttachmentMap.count() > 1 ) {
|
|
// get the dir
|
|
dirUrl = KDirSelectDialog::selectDirectory( TQString::null, false,
|
|
parentWidget(),
|
|
i18n("Save Attachments To") );
|
|
if ( !dirUrl.isValid() ) {
|
|
setResult( Canceled );
|
|
emit completed( this );
|
|
deleteLater();
|
|
return;
|
|
}
|
|
|
|
// we may not get a slash-terminated url out of KDirSelectDialog
|
|
dirUrl.adjustPath( 1 );
|
|
}
|
|
else {
|
|
// only one item, get the desired filename
|
|
partNode *node = mAttachmentMap.begin().key();
|
|
// replace all ':' with '_' because ':' isn't allowed on FAT volumes
|
|
TQString s =
|
|
node->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
|
|
if ( s.isEmpty() )
|
|
s = node->msgPart().name().stripWhiteSpace().replace( ':', '_' );
|
|
if ( s.isEmpty() )
|
|
s = i18n("filename for an unnamed attachment", "attachment.1");
|
|
url = KFileDialog::getSaveURL( s, TQString::null, parentWidget(),
|
|
TQString::null );
|
|
if ( url.isEmpty() ) {
|
|
setResult( Canceled );
|
|
emit completed( this );
|
|
deleteLater();
|
|
return;
|
|
}
|
|
}
|
|
|
|
TQMap< TQString, int > renameNumbering;
|
|
|
|
Result globalResult = OK;
|
|
int unnamedAtmCount = 0;
|
|
for ( PartNodeMessageMap::const_iterator it = mAttachmentMap.begin();
|
|
it != mAttachmentMap.end();
|
|
++it ) {
|
|
KURL curUrl;
|
|
if ( !dirUrl.isEmpty() ) {
|
|
curUrl = dirUrl;
|
|
TQString s =
|
|
it.key()->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
|
|
if ( s.isEmpty() )
|
|
s = it.key()->msgPart().name().stripWhiteSpace().replace( ':', '_' );
|
|
if ( s.isEmpty() ) {
|
|
++unnamedAtmCount;
|
|
s = i18n("filename for the %1-th unnamed attachment",
|
|
"attachment.%1")
|
|
.arg( unnamedAtmCount );
|
|
}
|
|
curUrl.setFileName( s );
|
|
} else {
|
|
curUrl = url;
|
|
}
|
|
|
|
if ( !curUrl.isEmpty() ) {
|
|
|
|
// Rename the file if we have already saved one with the same name:
|
|
// try appending a number before extension (e.g. "pic.jpg" => "pic_2.jpg")
|
|
TQString origFile = curUrl.fileName();
|
|
TQString file = origFile;
|
|
|
|
while ( renameNumbering.contains(file) ) {
|
|
file = origFile;
|
|
int num = renameNumbering[file] + 1;
|
|
int dotIdx = file.findRev('.');
|
|
file = file.insert( (dotIdx>=0) ? dotIdx : file.length(), TQString("_") + TQString::number(num) );
|
|
}
|
|
curUrl.setFileName(file);
|
|
|
|
// Increment the counter for both the old and the new filename
|
|
if ( !renameNumbering.contains(origFile))
|
|
renameNumbering[origFile] = 1;
|
|
else
|
|
renameNumbering[origFile]++;
|
|
|
|
if ( file != origFile ) {
|
|
if ( !renameNumbering.contains(file))
|
|
renameNumbering[file] = 1;
|
|
else
|
|
renameNumbering[file]++;
|
|
}
|
|
|
|
|
|
if ( KIO::NetAccess::exists( curUrl, false, parentWidget() ) ) {
|
|
if ( KMessageBox::warningContinueCancel( parentWidget(),
|
|
i18n( "A file named %1 already exists. Do you want to overwrite it?" )
|
|
.arg( curUrl.fileName() ),
|
|
i18n( "File Already Exists" ), i18n("&Overwrite") ) == KMessageBox::Cancel) {
|
|
continue;
|
|
}
|
|
}
|
|
// save
|
|
const Result result = saveItem( it.key(), curUrl );
|
|
if ( result != OK )
|
|
globalResult = result;
|
|
}
|
|
}
|
|
setResult( globalResult );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
|
|
KMCommand::Result KMSaveAttachmentsCommand::saveItem( partNode *node,
|
|
const KURL& url )
|
|
{
|
|
bool bSaveEncrypted = false;
|
|
bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted;
|
|
if( bEncryptedParts )
|
|
if( KMessageBox::questionYesNo( parentWidget(),
|
|
i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?" ).
|
|
arg( url.fileName() ),
|
|
i18n( "KMail Question" ), i18n("Keep Encryption"), i18n("Do Not Keep") ) ==
|
|
KMessageBox::Yes )
|
|
bSaveEncrypted = true;
|
|
|
|
bool bSaveWithSig = true;
|
|
if( node->signatureState() != KMMsgNotSigned )
|
|
if( KMessageBox::questionYesNo( parentWidget(),
|
|
i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?" ).
|
|
arg( url.fileName() ),
|
|
i18n( "KMail Question" ), i18n("Keep Signature"), i18n("Do Not Keep") ) !=
|
|
KMessageBox::Yes )
|
|
bSaveWithSig = false;
|
|
|
|
TQByteArray data;
|
|
if ( mEncoded )
|
|
{
|
|
// This does not decode the Message Content-Transfer-Encoding
|
|
// but saves the _original_ content of the message part
|
|
data = KMail::Util::ByteArray( node->msgPart().dwBody() );
|
|
}
|
|
else
|
|
{
|
|
if( bSaveEncrypted || !bEncryptedParts) {
|
|
partNode *dataNode = node;
|
|
TQCString rawReplyString;
|
|
bool gotRawReplyString = false;
|
|
if( !bSaveWithSig ) {
|
|
if( DwMime::kTypeMultipart == node->type() &&
|
|
DwMime::kSubtypeSigned == node->subType() ){
|
|
// carefully look for the part that is *not* the signature part:
|
|
if( node->findType( DwMime::kTypeApplication,
|
|
DwMime::kSubtypePgpSignature,
|
|
true, false ) ){
|
|
dataNode = node->findTypeNot( DwMime::kTypeApplication,
|
|
DwMime::kSubtypePgpSignature,
|
|
true, false );
|
|
}else if( node->findType( DwMime::kTypeApplication,
|
|
DwMime::kSubtypePkcs7Mime,
|
|
true, false ) ){
|
|
dataNode = node->findTypeNot( DwMime::kTypeApplication,
|
|
DwMime::kSubtypePkcs7Mime,
|
|
true, false );
|
|
}else{
|
|
dataNode = node->findTypeNot( DwMime::kTypeMultipart,
|
|
DwMime::kSubtypeUnknown,
|
|
true, false );
|
|
}
|
|
}else{
|
|
ObjectTreeParser otp( 0, 0, false, false, false );
|
|
|
|
// process this node and all it's siblings and descendants
|
|
dataNode->setProcessed( false, true );
|
|
otp.parseObjectTree( dataNode );
|
|
|
|
rawReplyString = otp.rawReplyString();
|
|
gotRawReplyString = true;
|
|
}
|
|
}
|
|
TQByteArray cstr = gotRawReplyString
|
|
? rawReplyString
|
|
: dataNode->msgPart().bodyDecodedBinary();
|
|
data = cstr;
|
|
size_t size = cstr.size();
|
|
if ( dataNode->msgPart().type() == DwMime::kTypeText ) {
|
|
// convert CRLF to LF before writing text attachments to disk
|
|
size = KMail::Util::crlf2lf( cstr.data(), size );
|
|
}
|
|
data.resize( size );
|
|
}
|
|
}
|
|
TQDataStream ds;
|
|
TQFile file;
|
|
KTempFile tf;
|
|
tf.setAutoDelete( true );
|
|
if ( url.isLocalFile() )
|
|
{
|
|
// save directly
|
|
file.setName( url.path() );
|
|
if ( !file.open( IO_WriteOnly ) )
|
|
{
|
|
KMessageBox::error( parentWidget(),
|
|
i18n( "%2 is detailed error description",
|
|
"Could not write the file %1:\n%2" )
|
|
.arg( file.name() )
|
|
.arg( TQString::fromLocal8Bit( strerror( errno ) ) ),
|
|
i18n( "KMail Error" ) );
|
|
return Failed;
|
|
}
|
|
|
|
// #79685 by default use the umask the user defined, but let it be configurable
|
|
if ( GlobalSettings::self()->disregardUmask() )
|
|
fchmod( file.handle(), S_IRUSR | S_IWUSR );
|
|
|
|
ds.setDevice( &file );
|
|
} else
|
|
{
|
|
// tmp file for upload
|
|
ds.setDevice( tf.file() );
|
|
}
|
|
|
|
ds.writeRawBytes( data.data(), data.size() );
|
|
if ( !url.isLocalFile() )
|
|
{
|
|
tf.close();
|
|
if ( !KIO::NetAccess::upload( tf.name(), url, parentWidget() ) )
|
|
{
|
|
KMessageBox::error( parentWidget(),
|
|
i18n( "Could not write the file %1." )
|
|
.arg( url.path() ),
|
|
i18n( "KMail Error" ) );
|
|
return Failed;
|
|
}
|
|
} else
|
|
file.close();
|
|
return OK;
|
|
}
|
|
|
|
KMLoadPartsCommand::KMLoadPartsCommand( TQPtrList<partNode>& parts, KMMessage *msg )
|
|
: mNeedsRetrieval( 0 )
|
|
{
|
|
for ( TQPtrListIterator<partNode> it( parts ); it.current(); ++it ) {
|
|
mPartMap.insert( it.current(), msg );
|
|
}
|
|
}
|
|
|
|
KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
|
|
: mNeedsRetrieval( 0 )
|
|
{
|
|
mPartMap.insert( node, msg );
|
|
}
|
|
|
|
KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
|
|
: mNeedsRetrieval( 0 ), mPartMap( partMap )
|
|
{
|
|
}
|
|
|
|
void KMLoadPartsCommand::slotStart()
|
|
{
|
|
for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
|
|
it != mPartMap.end();
|
|
++it ) {
|
|
if ( !it.key()->msgPart().isComplete() &&
|
|
!it.key()->msgPart().partSpecifier().isEmpty() ) {
|
|
// incomplete part, so retrieve it first
|
|
++mNeedsRetrieval;
|
|
KMFolder* curFolder = it.data()->parent();
|
|
if ( curFolder ) {
|
|
FolderJob *job =
|
|
curFolder->createJob( it.data(), FolderJob::tGetMessage,
|
|
0, it.key()->msgPart().partSpecifier() );
|
|
job->setCancellable( false );
|
|
connect( job, TQT_SIGNAL(messageUpdated(KMMessage*, TQString)),
|
|
this, TQT_SLOT(slotPartRetrieved(KMMessage*, TQString)) );
|
|
job->start();
|
|
} else
|
|
kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl;
|
|
}
|
|
}
|
|
if ( mNeedsRetrieval == 0 )
|
|
execute();
|
|
}
|
|
|
|
void KMLoadPartsCommand::slotPartRetrieved( KMMessage *msg,
|
|
TQString partSpecifier )
|
|
{
|
|
DwBodyPart *part =
|
|
msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier );
|
|
if ( part ) {
|
|
// update the DwBodyPart in the partNode
|
|
for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
|
|
it != mPartMap.end();
|
|
++it ) {
|
|
if ( it.key()->dwPart()->partId() == part->partId() )
|
|
it.key()->setDwPart( part );
|
|
}
|
|
} else
|
|
kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl;
|
|
--mNeedsRetrieval;
|
|
if ( mNeedsRetrieval == 0 )
|
|
execute();
|
|
}
|
|
|
|
KMCommand::Result KMLoadPartsCommand::execute()
|
|
{
|
|
emit partsRetrieved();
|
|
setResult( OK );
|
|
emit completed( this );
|
|
deleteLater();
|
|
return OK;
|
|
}
|
|
|
|
KMResendMessageCommand::KMResendMessageCommand( TQWidget *parent,
|
|
KMMessage *msg )
|
|
:KMCommand( parent, msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMResendMessageCommand::execute()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
KMMessage *newMsg = new KMMessage(*msg);
|
|
|
|
TQStringList whiteList;
|
|
whiteList << "To" << "Cc" << "Bcc" << "Subject";
|
|
newMsg->sanitizeHeaders( whiteList );
|
|
|
|
newMsg->setCharset(msg->codec()->mimeName());
|
|
newMsg->setParent( 0 );
|
|
|
|
// make sure we have an identity set, default, if necessary
|
|
newMsg->setHeaderField("X-KMail-Identity", TQString::number( newMsg->identityUoid() ));
|
|
newMsg->applyIdentity( newMsg->identityUoid() );
|
|
|
|
KMail::Composer * win = KMail::makeComposer();
|
|
win->setMsg(newMsg, false, true);
|
|
win->show();
|
|
|
|
return OK;
|
|
}
|
|
|
|
KMMailingListCommand::KMMailingListCommand( TQWidget *parent, KMFolder *folder )
|
|
: KMCommand( parent ), mFolder( folder )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMMailingListCommand::execute()
|
|
{
|
|
KURL::List lst = urls();
|
|
TQString handler = ( mFolder->mailingList().handler() == MailingList::KMail )
|
|
? "mailto" : "https";
|
|
|
|
KMCommand *command = 0;
|
|
for ( KURL::List::Iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
|
|
if ( handler == (*itr).protocol() ) {
|
|
command = new KMUrlClickedCommand( *itr, mFolder->identity(), 0, false );
|
|
}
|
|
}
|
|
if ( !command && !lst.empty() ) {
|
|
command =
|
|
new KMUrlClickedCommand( lst.first(), mFolder->identity(), 0, false );
|
|
}
|
|
if ( command ) {
|
|
connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
|
|
this, TQT_SLOT( commandCompleted( KMCommand * ) ) );
|
|
setDeletesItself( true );
|
|
setEmitsCompletedItself( true );
|
|
command->start();
|
|
return OK;
|
|
}
|
|
return Failed;
|
|
}
|
|
|
|
void KMMailingListCommand::commandCompleted( KMCommand *command )
|
|
{
|
|
setResult( command->result() );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
|
|
KMMailingListPostCommand::KMMailingListPostCommand( TQWidget *parent, KMFolder *folder )
|
|
: KMMailingListCommand( parent, folder )
|
|
{
|
|
}
|
|
KURL::List KMMailingListPostCommand::urls() const
|
|
{
|
|
return mFolder->mailingList().postURLS();
|
|
}
|
|
|
|
KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( TQWidget *parent, KMFolder *folder )
|
|
: KMMailingListCommand( parent, folder )
|
|
{
|
|
}
|
|
KURL::List KMMailingListSubscribeCommand::urls() const
|
|
{
|
|
return mFolder->mailingList().subscribeURLS();
|
|
}
|
|
|
|
KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( TQWidget *parent, KMFolder *folder )
|
|
: KMMailingListCommand( parent, folder )
|
|
{
|
|
}
|
|
KURL::List KMMailingListUnsubscribeCommand::urls() const
|
|
{
|
|
return mFolder->mailingList().unsubscribeURLS();
|
|
}
|
|
|
|
KMMailingListArchivesCommand::KMMailingListArchivesCommand( TQWidget *parent, KMFolder *folder )
|
|
: KMMailingListCommand( parent, folder )
|
|
{
|
|
}
|
|
KURL::List KMMailingListArchivesCommand::urls() const
|
|
{
|
|
return mFolder->mailingList().archiveURLS();
|
|
}
|
|
|
|
KMMailingListHelpCommand::KMMailingListHelpCommand( TQWidget *parent, KMFolder *folder )
|
|
: KMMailingListCommand( parent, folder )
|
|
{
|
|
}
|
|
KURL::List KMMailingListHelpCommand::urls() const
|
|
{
|
|
return mFolder->mailingList().helpURLS();
|
|
}
|
|
|
|
KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
|
|
:mUrl( url ), mMessage( msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMIMChatCommand::execute()
|
|
{
|
|
kdDebug( 5006 ) << k_funcinfo << " URL is: " << mUrl << endl;
|
|
TQString addr = KMMessage::decodeMailtoUrl( mUrl.path() );
|
|
// find UID for mail address
|
|
KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
|
|
KABC::AddresseeList addressees = addressBook->findByEmail( KPIM::getEmailAddress( addr ) ) ;
|
|
|
|
// start chat
|
|
if( addressees.count() == 1 ) {
|
|
kmkernel->imProxy()->chatWithContact( addressees[0].uid() );
|
|
return OK;
|
|
}
|
|
else
|
|
{
|
|
kdDebug( 5006 ) << "Didn't find exactly one addressee, couldn't tell who to chat to for that email address. Count = " << addressees.count() << endl;
|
|
|
|
TQString apology;
|
|
if ( addressees.isEmpty() )
|
|
apology = i18n( "There is no Address Book entry for this email address. Add them to the Address Book and then add instant messaging addresses using your preferred messaging client." );
|
|
else
|
|
{
|
|
apology = i18n( "More than one Address Book entry uses this email address:\n %1\n it is not possible to determine who to chat with." );
|
|
TQStringList nameList;
|
|
KABC::AddresseeList::const_iterator it = addressees.begin();
|
|
KABC::AddresseeList::const_iterator end = addressees.end();
|
|
for ( ; it != end; ++it )
|
|
{
|
|
nameList.append( (*it).realName() );
|
|
}
|
|
TQString names = nameList.join( TQString::fromLatin1( ",\n" ) );
|
|
apology = apology.arg( names );
|
|
}
|
|
|
|
KMessageBox::sorry( parentWidget(), apology );
|
|
return Failed;
|
|
}
|
|
}
|
|
|
|
KMHandleAttachmentCommand::KMHandleAttachmentCommand( partNode* node,
|
|
KMMessage* msg, int atmId, const TQString& atmName,
|
|
AttachmentAction action, KService::Ptr offer, TQWidget* parent )
|
|
: KMCommand( parent ), mNode( node ), mMsg( msg ), mAtmId( atmId ), mAtmName( atmName ),
|
|
mAction( action ), mOffer( offer ), mJob( 0 )
|
|
{
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::slotStart()
|
|
{
|
|
if ( !mNode->msgPart().isComplete() )
|
|
{
|
|
// load the part
|
|
kdDebug(5006) << "load part" << endl;
|
|
KMLoadPartsCommand *command = new KMLoadPartsCommand( mNode, mMsg );
|
|
connect( command, TQT_SIGNAL( partsRetrieved() ),
|
|
this, TQT_SLOT( slotPartComplete() ) );
|
|
command->start();
|
|
} else
|
|
{
|
|
execute();
|
|
}
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::slotPartComplete()
|
|
{
|
|
execute();
|
|
}
|
|
|
|
KMCommand::Result KMHandleAttachmentCommand::execute()
|
|
{
|
|
switch( mAction )
|
|
{
|
|
case Open:
|
|
atmOpen();
|
|
break;
|
|
case OpenWith:
|
|
atmOpenWith();
|
|
break;
|
|
case View:
|
|
atmView();
|
|
break;
|
|
case Save:
|
|
atmSave();
|
|
break;
|
|
case Properties:
|
|
atmProperties();
|
|
break;
|
|
case ChiasmusEncrypt:
|
|
atmEncryptWithChiasmus();
|
|
return Undefined;
|
|
break;
|
|
default:
|
|
kdDebug(5006) << "unknown action " << mAction << endl;
|
|
break;
|
|
}
|
|
setResult( OK );
|
|
emit completed( this );
|
|
deleteLater();
|
|
return OK;
|
|
}
|
|
|
|
TQString KMHandleAttachmentCommand::createAtmFileLink() const
|
|
{
|
|
TQFileInfo atmFileInfo( mAtmName );
|
|
|
|
if ( atmFileInfo.size() == 0 )
|
|
{
|
|
kdDebug(5006) << k_funcinfo << "rewriting attachment" << endl;
|
|
// there is something wrong so write the file again
|
|
TQByteArray data = mNode->msgPart().bodyDecodedBinary();
|
|
size_t size = data.size();
|
|
if ( mNode->msgPart().type() == DwMime::kTypeText && size) {
|
|
// convert CRLF to LF before writing text attachments to disk
|
|
size = KMail::Util::crlf2lf( data.data(), size );
|
|
}
|
|
KPIM::kBytesToFile( data.data(), size, mAtmName, false, false, false );
|
|
}
|
|
|
|
KTempFile *linkFile = new KTempFile( locateLocal("tmp", atmFileInfo.fileName() +"_["),
|
|
"]."+ atmFileInfo.extension() );
|
|
|
|
linkFile->setAutoDelete(true);
|
|
TQString linkName = linkFile->name();
|
|
delete linkFile;
|
|
|
|
if ( ::link(TQFile::encodeName( mAtmName ), TQFile::encodeName( linkName )) == 0 ) {
|
|
return linkName; // success
|
|
}
|
|
return TQString::null;
|
|
}
|
|
|
|
KService::Ptr KMHandleAttachmentCommand::getServiceOffer()
|
|
{
|
|
KMMessagePart& msgPart = mNode->msgPart();
|
|
const TQString contentTypeStr =
|
|
( msgPart.typeStr() + '/' + msgPart.subtypeStr() ).lower();
|
|
|
|
if ( contentTypeStr == "text/x-vcard" ) {
|
|
atmView();
|
|
return 0;
|
|
}
|
|
// determine the MIME type of the attachment
|
|
KMimeType::Ptr mimetype;
|
|
// prefer the value of the Content-Type header
|
|
mimetype = KMimeType::mimeType( contentTypeStr );
|
|
if ( mimetype->name() == "application/octet-stream" ) {
|
|
// consider the filename if Content-Type is application/octet-stream
|
|
mimetype = KMimeType::findByPath( mAtmName, 0, true /* no disk access */ );
|
|
}
|
|
if ( ( mimetype->name() == "application/octet-stream" )
|
|
&& msgPart.isComplete() ) {
|
|
// consider the attachment's contents if neither the Content-Type header
|
|
// nor the filename give us a clue
|
|
mimetype = KMimeType::findByFileContent( mAtmName );
|
|
}
|
|
return KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::atmOpen()
|
|
{
|
|
if ( !mOffer )
|
|
mOffer = getServiceOffer();
|
|
if ( !mOffer ) {
|
|
kdDebug(5006) << k_funcinfo << "got no offer" << endl;
|
|
return;
|
|
}
|
|
|
|
KURL::List lst;
|
|
KURL url;
|
|
bool autoDelete = true;
|
|
TQString fname = createAtmFileLink();
|
|
|
|
if ( fname.isNull() ) {
|
|
autoDelete = false;
|
|
fname = mAtmName;
|
|
}
|
|
|
|
url.setPath( fname );
|
|
lst.append( url );
|
|
if ( (KRun::run( *mOffer, lst, autoDelete ) <= 0) && autoDelete ) {
|
|
TQFile::remove(url.path());
|
|
}
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::atmOpenWith()
|
|
{
|
|
KURL::List lst;
|
|
KURL url;
|
|
bool autoDelete = true;
|
|
TQString fname = createAtmFileLink();
|
|
|
|
if ( fname.isNull() ) {
|
|
autoDelete = false;
|
|
fname = mAtmName;
|
|
}
|
|
|
|
url.setPath( fname );
|
|
lst.append( url );
|
|
if ( (! KRun::displayOpenWithDialog(lst, autoDelete)) && autoDelete ) {
|
|
TQFile::remove( url.path() );
|
|
}
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::atmView()
|
|
{
|
|
// we do not handle this ourself
|
|
emit showAttachment( mAtmId, mAtmName );
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::atmSave()
|
|
{
|
|
TQPtrList<partNode> parts;
|
|
parts.append( mNode );
|
|
// save, do not leave encoded
|
|
KMSaveAttachmentsCommand *command =
|
|
new KMSaveAttachmentsCommand( 0, parts, mMsg, false );
|
|
command->start();
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::atmProperties()
|
|
{
|
|
KMMsgPartDialogCompat dlg( parentWidget() , 0, true );
|
|
KMMessagePart& msgPart = mNode->msgPart();
|
|
dlg.setMsgPart( &msgPart );
|
|
dlg.exec();
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::atmEncryptWithChiasmus()
|
|
{
|
|
const partNode * node = mNode;
|
|
Q_ASSERT( node );
|
|
if ( !node )
|
|
return;
|
|
|
|
// FIXME: better detection of mimetype??
|
|
if ( !mAtmName.endsWith( ".xia", false ) )
|
|
return;
|
|
|
|
const Kleo::CryptoBackend::Protocol * chiasmus =
|
|
Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
|
|
Q_ASSERT( chiasmus );
|
|
if ( !chiasmus )
|
|
return;
|
|
|
|
const STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> listjob( chiasmus->specialJob( "x-obtain-keys", TQMap<TQString,TQVariant>() ) );
|
|
if ( !listjob.get() ) {
|
|
const TQString msg = i18n( "Chiasmus backend does not offer the "
|
|
"\"x-obtain-keys\" function. Please report this bug." );
|
|
KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
|
|
return;
|
|
}
|
|
|
|
if ( listjob->exec() ) {
|
|
listjob->showErrorDialog( parentWidget(), i18n( "Chiasmus Backend Error" ) );
|
|
return;
|
|
}
|
|
|
|
const TQVariant result = listjob->property( "result" );
|
|
if ( result.type() != TQVariant::StringList ) {
|
|
const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
|
|
"The \"x-obtain-keys\" function did not return a "
|
|
"string list. Please report this bug." );
|
|
KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
|
|
return;
|
|
}
|
|
|
|
const TQStringList keys = result.toStringList();
|
|
if ( keys.empty() ) {
|
|
const TQString msg = i18n( "No keys have been found. Please check that a "
|
|
"valid key path has been set in the Chiasmus "
|
|
"configuration." );
|
|
KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
|
|
return;
|
|
}
|
|
|
|
ChiasmusKeySelector selectorDlg( parentWidget(), i18n( "Chiasmus Decryption Key Selection" ),
|
|
keys, GlobalSettings::chiasmusDecryptionKey(),
|
|
GlobalSettings::chiasmusDecryptionOptions() );
|
|
if ( selectorDlg.exec() != TQDialog::Accepted )
|
|
return;
|
|
|
|
GlobalSettings::setChiasmusDecryptionOptions( selectorDlg.options() );
|
|
GlobalSettings::setChiasmusDecryptionKey( selectorDlg.key() );
|
|
assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() );
|
|
|
|
Kleo::SpecialJob * job = chiasmus->specialJob( "x-decrypt", TQMap<TQString,TQVariant>() );
|
|
if ( !job ) {
|
|
const TQString msg = i18n( "Chiasmus backend does not offer the "
|
|
"\"x-decrypt\" function. Please report this bug." );
|
|
KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
|
|
return;
|
|
}
|
|
|
|
const TQByteArray input = node->msgPart().bodyDecodedBinary();
|
|
|
|
if ( !job->setProperty( "key", GlobalSettings::chiasmusDecryptionKey() ) ||
|
|
!job->setProperty( "options", GlobalSettings::chiasmusDecryptionOptions() ) ||
|
|
!job->setProperty( "input", input ) ) {
|
|
const TQString msg = i18n( "The \"x-decrypt\" function does not accept "
|
|
"the expected parameters. Please report this bug." );
|
|
KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
|
|
return;
|
|
}
|
|
|
|
setDeletesItself( true ); // the job below is async, we have to cleanup ourselves
|
|
if ( job->start() ) {
|
|
job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
|
|
return;
|
|
}
|
|
|
|
mJob = job;
|
|
connect( job, TQT_SIGNAL(result(const GpgME::Error&,const TQVariant&)),
|
|
this, TQT_SLOT(slotAtmDecryptWithChiasmusResult(const GpgME::Error&,const TQVariant&)) );
|
|
}
|
|
|
|
static const TQString chomp( const TQString & base, const TQString & suffix, bool cs ) {
|
|
return base.endsWith( suffix, cs ) ? base.left( base.length() - suffix.length() ) : base ;
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusResult( const GpgME::Error & err, const TQVariant & result )
|
|
{
|
|
LaterDeleterWithCommandCompletion d( this );
|
|
if ( !mJob )
|
|
return;
|
|
Q_ASSERT( mJob == sender() );
|
|
if ( mJob != sender() )
|
|
return;
|
|
Kleo::Job * job = mJob;
|
|
mJob = 0;
|
|
if ( err.isCanceled() )
|
|
return;
|
|
if ( err ) {
|
|
job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
|
|
return;
|
|
}
|
|
|
|
if ( result.type() != TQVariant::ByteArray ) {
|
|
const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
|
|
"The \"x-decrypt\" function did not return a "
|
|
"byte array. Please report this bug." );
|
|
KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
|
|
return;
|
|
}
|
|
|
|
const KURL url = KFileDialog::getSaveURL( chomp( mAtmName, ".xia", false ), TQString::null, parentWidget() );
|
|
if ( url.isEmpty() )
|
|
return;
|
|
|
|
bool overwrite = KMail::Util::checkOverwrite( url, parentWidget() );
|
|
if ( !overwrite )
|
|
return;
|
|
|
|
d.setDisabled( true ); // we got this far, don't delete yet
|
|
KIO::Job * uploadJob = KIO::storedPut( result.toByteArray(), url, -1, overwrite, false /*resume*/ );
|
|
uploadJob->setWindow( parentWidget() );
|
|
connect( uploadJob, TQT_SIGNAL(result(KIO::Job*)),
|
|
this, TQT_SLOT(slotAtmDecryptWithChiasmusUploadResult(KIO::Job*)) );
|
|
}
|
|
|
|
void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusUploadResult( KIO::Job * job )
|
|
{
|
|
if ( job->error() )
|
|
job->showErrorDialog();
|
|
LaterDeleterWithCommandCompletion d( this );
|
|
d.setResult( OK );
|
|
}
|
|
|
|
|
|
AttachmentModifyCommand::AttachmentModifyCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
|
|
KMCommand( parent, msg ),
|
|
mPartIndex( node->nodeId() ),
|
|
mSernum( 0 )
|
|
{
|
|
}
|
|
|
|
AttachmentModifyCommand::~ AttachmentModifyCommand()
|
|
{
|
|
}
|
|
|
|
KMCommand::Result AttachmentModifyCommand::execute()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg )
|
|
return Failed;
|
|
mSernum = msg->getMsgSerNum();
|
|
|
|
mFolder = msg->parent();
|
|
if ( !mFolder || !mFolder->storage() )
|
|
return Failed;
|
|
|
|
Result res = doAttachmentModify();
|
|
if ( res != OK )
|
|
return res;
|
|
|
|
setEmitsCompletedItself( true );
|
|
setDeletesItself( true );
|
|
return OK;
|
|
}
|
|
|
|
void AttachmentModifyCommand::storeChangedMessage(KMMessage * msg)
|
|
{
|
|
if ( !mFolder || !mFolder->storage() ) {
|
|
kdWarning(5006) << k_funcinfo << "We lost the folder!" << endl;
|
|
setResult( Failed );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
int res = mFolder->addMsg( msg ) != 0;
|
|
if ( mFolder->folderType() == KMFolderTypeImap ) {
|
|
KMFolderImap *f = static_cast<KMFolderImap*>( mFolder->storage() );
|
|
connect( f, TQT_SIGNAL(folderComplete(KMFolderImap*,bool)),
|
|
TQT_SLOT(messageStoreResult(KMFolderImap*,bool)) );
|
|
} else {
|
|
messageStoreResult( 0, res == 0 );
|
|
}
|
|
}
|
|
|
|
void AttachmentModifyCommand::messageStoreResult(KMFolderImap* folder, bool success )
|
|
{
|
|
Q_UNUSED( folder );
|
|
if ( success ) {
|
|
KMCommand *delCmd = new KMDeleteMsgCommand( mSernum );
|
|
connect( delCmd, TQT_SIGNAL(completed(KMCommand*)), TQT_SLOT(messageDeleteResult(KMCommand*)) );
|
|
delCmd->start();
|
|
return;
|
|
}
|
|
kdWarning(5006) << k_funcinfo << "Adding modified message failed." << endl;
|
|
setResult( Failed );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
|
|
void AttachmentModifyCommand::messageDeleteResult(KMCommand * cmd)
|
|
{
|
|
setResult( cmd->result() );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
|
|
DwBodyPart * AttachmentModifyCommand::findPart(KMMessage* msg, int index)
|
|
{
|
|
int accu = 0;
|
|
return findPartInternal( msg->getTopLevelPart(), index, accu );
|
|
}
|
|
|
|
DwBodyPart * AttachmentModifyCommand::findPartInternal(DwEntity * root, int index, int & accu)
|
|
{
|
|
accu++;
|
|
if ( index < accu ) // should not happen
|
|
return 0;
|
|
DwBodyPart *current = dynamic_cast<DwBodyPart*>( root );
|
|
if ( index == accu )
|
|
return current;
|
|
DwBodyPart *rv = 0;
|
|
if ( root->Body().FirstBodyPart() )
|
|
rv = findPartInternal( root->Body().FirstBodyPart(), index, accu );
|
|
if ( !rv && current && current->Next() )
|
|
rv = findPartInternal( current->Next(), index, accu );
|
|
return rv;
|
|
}
|
|
|
|
|
|
KMDeleteAttachmentCommand::KMDeleteAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
|
|
AttachmentModifyCommand( node, msg, parent )
|
|
{
|
|
kdDebug(5006) << k_funcinfo << endl;
|
|
}
|
|
|
|
KMDeleteAttachmentCommand::~KMDeleteAttachmentCommand()
|
|
{
|
|
kdDebug(5006) << k_funcinfo << endl;
|
|
}
|
|
|
|
KMCommand::Result KMDeleteAttachmentCommand::doAttachmentModify()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
KMMessagePart part;
|
|
DwBodyPart *dwpart = findPart( msg, mPartIndex );
|
|
if ( !dwpart )
|
|
return Failed;
|
|
KMMessage::bodyPart( dwpart, &part, true );
|
|
if ( !part.isComplete() )
|
|
return Failed;
|
|
|
|
DwBody *parentNode = dynamic_cast<DwBody*>( dwpart->Parent() );
|
|
if ( !parentNode )
|
|
return Failed;
|
|
parentNode->RemoveBodyPart( dwpart );
|
|
|
|
// add dummy part to show that a attachment has been deleted
|
|
KMMessagePart dummyPart;
|
|
dummyPart.duplicate( part );
|
|
TQString comment = i18n("This attachment has been deleted.");
|
|
if ( !part.fileName().isEmpty() )
|
|
comment = i18n( "The attachment '%1' has been deleted." ).arg( part.fileName() );
|
|
dummyPart.setContentDescription( comment );
|
|
dummyPart.setBodyEncodedBinary( TQByteArray() );
|
|
TQCString cd = dummyPart.contentDisposition();
|
|
if ( cd.find( "inline", 0, false ) == 0 ) {
|
|
cd.replace( 0, 10, "attachment" );
|
|
dummyPart.setContentDisposition( cd );
|
|
} else if ( cd.isEmpty() ) {
|
|
dummyPart.setContentDisposition( "attachment" );
|
|
}
|
|
DwBodyPart* newDwPart = msg->createDWBodyPart( &dummyPart );
|
|
parentNode->AddBodyPart( newDwPart );
|
|
msg->getTopLevelPart()->Assemble();
|
|
|
|
KMMessage *newMsg = new KMMessage();
|
|
newMsg->fromDwString( msg->asDwString() );
|
|
newMsg->setStatus( msg->status() );
|
|
|
|
storeChangedMessage( newMsg );
|
|
return OK;
|
|
}
|
|
|
|
|
|
KMEditAttachmentCommand::KMEditAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
|
|
AttachmentModifyCommand( node, msg, parent )
|
|
{
|
|
kdDebug(5006) << k_funcinfo << endl;
|
|
mTempFile.setAutoDelete( true );
|
|
}
|
|
|
|
KMEditAttachmentCommand::~ KMEditAttachmentCommand()
|
|
{
|
|
}
|
|
|
|
KMCommand::Result KMEditAttachmentCommand::doAttachmentModify()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
KMMessagePart part;
|
|
DwBodyPart *dwpart = findPart( msg, mPartIndex );
|
|
if ( !dwpart )
|
|
return Failed;
|
|
KMMessage::bodyPart( dwpart, &part, true );
|
|
if ( !part.isComplete() )
|
|
return Failed;
|
|
|
|
if( !dynamic_cast<DwBody*>( dwpart->Parent() ) )
|
|
return Failed;
|
|
|
|
mTempFile.file()->writeBlock( part.bodyDecodedBinary() );
|
|
mTempFile.file()->flush();
|
|
|
|
KMail::EditorWatcher *watcher = new KMail::EditorWatcher( KURL(mTempFile.file()->name()), part.typeStr() + "/" + part.subtypeStr(), false, this );
|
|
connect( watcher, TQT_SIGNAL(editDone(KMail::EditorWatcher*)), TQT_SLOT(editDone(KMail::EditorWatcher*)) );
|
|
if ( !watcher->start() )
|
|
return Failed;
|
|
setEmitsCompletedItself( true );
|
|
setDeletesItself( true );
|
|
return OK;
|
|
}
|
|
|
|
void KMEditAttachmentCommand::editDone(KMail::EditorWatcher * watcher)
|
|
{
|
|
kdDebug(5006) << k_funcinfo << endl;
|
|
// anything changed?
|
|
if ( !watcher->fileChanged() ) {
|
|
kdDebug(5006) << k_funcinfo << "File has not been changed" << endl;
|
|
setResult( Canceled );
|
|
emit completed( this );
|
|
deleteLater();
|
|
}
|
|
|
|
mTempFile.file()->reset();
|
|
TQByteArray data = mTempFile.file()->readAll();
|
|
|
|
// build the new message
|
|
KMMessage *msg = retrievedMessage();
|
|
KMMessagePart part;
|
|
DwBodyPart *dwpart = findPart( msg, mPartIndex );
|
|
KMMessage::bodyPart( dwpart, &part, true );
|
|
|
|
DwBody *parentNode = dynamic_cast<DwBody*>( dwpart->Parent() );
|
|
assert( parentNode );
|
|
parentNode->RemoveBodyPart( dwpart );
|
|
|
|
KMMessagePart att;
|
|
att.duplicate( part );
|
|
att.setBodyEncodedBinary( data );
|
|
|
|
DwBodyPart* newDwPart = msg->createDWBodyPart( &att );
|
|
parentNode->AddBodyPart( newDwPart );
|
|
msg->getTopLevelPart()->Assemble();
|
|
|
|
KMMessage *newMsg = new KMMessage();
|
|
newMsg->fromDwString( msg->asDwString() );
|
|
newMsg->setStatus( msg->status() );
|
|
|
|
storeChangedMessage( newMsg );
|
|
}
|
|
|
|
|
|
CreateTodoCommand::CreateTodoCommand(TQWidget * parent, KMMessage * msg)
|
|
: KMCommand( parent, msg )
|
|
{
|
|
}
|
|
|
|
KMCommand::Result CreateTodoCommand::execute()
|
|
{
|
|
KMMessage *msg = retrievedMessage();
|
|
if ( !msg || !msg->codec() ) {
|
|
return Failed;
|
|
}
|
|
|
|
KMail::KorgHelper::ensureRunning();
|
|
|
|
TQString txt = i18n("From: %1\nTo: %2\nSubject: %3").arg( msg->from() )
|
|
.arg( msg->to() ).arg( msg->subject() );
|
|
|
|
KTempFile tf;
|
|
tf.setAutoDelete( true );
|
|
TQString uri = "kmail:" + TQString::number( msg->getMsgSerNum() ) + "/" + msg->msgId();
|
|
tf.file()->writeBlock( msg->asDwString().c_str(), msg->asDwString().length() );
|
|
tf.close();
|
|
|
|
KCalendarIface_stub *iface = new KCalendarIface_stub( kapp->dcopClient(), "korganizer", "CalendarIface" );
|
|
iface->openTodoEditor( i18n("Mail: %1").arg( msg->subject() ), txt,
|
|
uri, tf.name(), TQStringList(), "message/rfc822" );
|
|
delete iface;
|
|
|
|
return OK;
|
|
}
|
|
|
|
#include "kmcommands.moc"
|