00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "kmcommands.h"
00044
00045 #ifdef HAVE_CONFIG_H
00046 #include <config.h>
00047 #endif
00048
00049 #include <errno.h>
00050 #include <mimelib/enum.h>
00051 #include <mimelib/field.h>
00052 #include <mimelib/mimepp.h>
00053 #include <mimelib/string.h>
00054 #include <kapplication.h>
00055 #include <dcopclient.h>
00056
00057 #include <qtextcodec.h>
00058 #include <qpopupmenu.h>
00059
00060 #include <libemailfunctions/email.h>
00061 #include <kdebug.h>
00062 #include <kfiledialog.h>
00063 #include <kabc/stdaddressbook.h>
00064 #include <kabc/addresseelist.h>
00065 #include <kdirselectdialog.h>
00066 #include <klocale.h>
00067 #include <kmessagebox.h>
00068 #include <kparts/browserextension.h>
00069 #include <kprogress.h>
00070 #include <krun.h>
00071 #include <kbookmarkmanager.h>
00072 #include <kstandarddirs.h>
00073 #include <ktempfile.h>
00074 #include <kimproxy.h>
00075 #include <kuserprofile.h>
00076
00077 #include <kio/job.h>
00078 #include <kio/netaccess.h>
00079
00080 #include "actionscheduler.h"
00081 using KMail::ActionScheduler;
00082 #include "mailinglist-magic.h"
00083 #include "kmaddrbook.h"
00084 #include <kaddrbook.h>
00085 #include "composer.h"
00086 #include "kmfiltermgr.h"
00087 #include "kmfoldermbox.h"
00088 #include "kmfolderimap.h"
00089 #include "kmfoldermgr.h"
00090 #include "kmheaders.h"
00091 #include "headeritem.h"
00092 #include "kmmainwidget.h"
00093 #include "kmmsgdict.h"
00094 #include "messagesender.h"
00095 #include "kmmsgpartdlg.h"
00096 #include "undostack.h"
00097 #include "kcursorsaver.h"
00098 #include "partNode.h"
00099 #include "objecttreeparser.h"
00100 using KMail::ObjectTreeParser;
00101 using KMail::FolderJob;
00102 #include "chiasmuskeyselector.h"
00103 #include "mailsourceviewer.h"
00104 using KMail::MailSourceViewer;
00105 #include "kmreadermainwin.h"
00106 #include "secondarywindow.h"
00107 using KMail::SecondaryWindow;
00108 #include "redirectdialog.h"
00109 using KMail::RedirectDialog;
00110 #include "util.h"
00111
00112 #include "broadcaststatus.h"
00113 #include "globalsettings.h"
00114
00115 #include <libkdepim/kfileio.h>
00116
00117 #include "progressmanager.h"
00118 using KPIM::ProgressManager;
00119 using KPIM::ProgressItem;
00120 #include <kmime_mdn.h>
00121 using namespace KMime;
00122
00123 #include <kleo/specialjob.h>
00124 #include <kleo/cryptobackend.h>
00125 #include <kleo/cryptobackendfactory.h>
00126
00127 #include <qclipboard.h>
00128
00129 #include <memory>
00130
00131 class LaterDeleterWithCommandCompletion : public KMail::Util::LaterDeleter
00132 {
00133 public:
00134 LaterDeleterWithCommandCompletion( KMCommand* command )
00135 :LaterDeleter( command ), m_result( KMCommand::Failed )
00136 {
00137 }
00138 ~LaterDeleterWithCommandCompletion()
00139 {
00140 setResult( m_result );
00141 KMCommand *command = static_cast<KMCommand*>( m_object );
00142 emit command->completed( command );
00143 }
00144 void setResult( KMCommand::Result v ) { m_result = v; }
00145 private:
00146 KMCommand::Result m_result;
00147 };
00148
00149
00150 KMCommand::KMCommand( QWidget *parent )
00151 : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
00152 mEmitsCompletedItself( false ), mParent( parent )
00153 {
00154 }
00155
00156 KMCommand::KMCommand( QWidget *parent, const QPtrList<KMMsgBase> &msgList )
00157 : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
00158 mEmitsCompletedItself( false ), mParent( parent ), mMsgList( msgList )
00159 {
00160 }
00161
00162 KMCommand::KMCommand( QWidget *parent, KMMsgBase *msgBase )
00163 : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
00164 mEmitsCompletedItself( false ), mParent( parent )
00165 {
00166 mMsgList.append( msgBase );
00167 }
00168
00169 KMCommand::KMCommand( QWidget *parent, KMMessage *msg )
00170 : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
00171 mEmitsCompletedItself( false ), mParent( parent )
00172 {
00173 mMsgList.append( &msg->toMsgBase() );
00174 }
00175
00176 KMCommand::~KMCommand()
00177 {
00178 QValueListIterator<QGuardedPtr<KMFolder> > fit;
00179 for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
00180 if (!(*fit))
00181 continue;
00182 (*fit)->close();
00183 }
00184 }
00185
00186 KMCommand::Result KMCommand::result()
00187 {
00188 if ( mResult == Undefined )
00189 kdDebug(5006) << k_funcinfo << "mResult is Undefined" << endl;
00190 return mResult;
00191 }
00192
00193 void KMCommand::start()
00194 {
00195 QTimer::singleShot( 0, this, SLOT( slotStart() ) );
00196 }
00197
00198
00199 const QPtrList<KMMessage> KMCommand::retrievedMsgs() const
00200 {
00201 return mRetrievedMsgs;
00202 }
00203
00204 KMMessage *KMCommand::retrievedMessage() const
00205 {
00206 return mRetrievedMsgs.getFirst();
00207 }
00208
00209 QWidget *KMCommand::parentWidget() const
00210 {
00211 return mParent;
00212 }
00213
00214 int KMCommand::mCountJobs = 0;
00215
00216 void KMCommand::slotStart()
00217 {
00218 connect( this, SIGNAL( messagesTransfered( KMCommand::Result ) ),
00219 this, SLOT( slotPostTransfer( KMCommand::Result ) ) );
00220 kmkernel->filterMgr()->ref();
00221
00222 if (mMsgList.find(0) != -1) {
00223 emit messagesTransfered( Failed );
00224 return;
00225 }
00226
00227 if ((mMsgList.count() == 1) &&
00228 (mMsgList.getFirst()->isMessage()) &&
00229 (mMsgList.getFirst()->parent() == 0))
00230 {
00231
00232 mRetrievedMsgs.append((KMMessage*)mMsgList.getFirst());
00233 emit messagesTransfered( OK );
00234 return;
00235 }
00236
00237 for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
00238 if (!mb->parent()) {
00239 emit messagesTransfered( Failed );
00240 return;
00241 } else {
00242 keepFolderOpen( mb->parent() );
00243 }
00244
00245
00246 transferSelectedMsgs();
00247 }
00248
00249 void KMCommand::slotPostTransfer( KMCommand::Result result )
00250 {
00251 disconnect( this, SIGNAL( messagesTransfered( KMCommand::Result ) ),
00252 this, SLOT( slotPostTransfer( KMCommand::Result ) ) );
00253 if ( result == OK )
00254 result = execute();
00255 mResult = result;
00256 QPtrListIterator<KMMessage> it( mRetrievedMsgs );
00257 KMMessage* msg;
00258 while ( (msg = it.current()) != 0 )
00259 {
00260 ++it;
00261 if (msg->parent())
00262 msg->setTransferInProgress(false);
00263 }
00264 kmkernel->filterMgr()->deref();
00265 if ( !emitsCompletedItself() )
00266 emit completed( this );
00267 if ( !deletesItself() )
00268 deleteLater();
00269 }
00270
00271 void KMCommand::transferSelectedMsgs()
00272 {
00273
00274 if (KMCommand::mCountJobs > 0) {
00275 emit messagesTransfered( Failed );
00276 return;
00277 }
00278
00279 bool complete = true;
00280 KMCommand::mCountJobs = 0;
00281 mCountMsgs = 0;
00282 mRetrievedMsgs.clear();
00283 mCountMsgs = mMsgList.count();
00284 uint totalSize = 0;
00285
00286
00287
00288
00289 if ( mCountMsgs > 0 ) {
00290 mProgressDialog = new KProgressDialog(mParent, "transferProgress",
00291 i18n("Please wait"),
00292 i18n("Please wait while the message is transferred",
00293 "Please wait while the %n messages are transferred", mMsgList.count()),
00294 true);
00295 mProgressDialog->setMinimumDuration(1000);
00296 }
00297 for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
00298 {
00299
00300 KMMessage *thisMsg = 0;
00301 if ( mb->isMessage() )
00302 thisMsg = static_cast<KMMessage*>(mb);
00303 else
00304 {
00305 KMFolder *folder = mb->parent();
00306 int idx = folder->find(mb);
00307 if (idx < 0) continue;
00308 thisMsg = folder->getMsg(idx);
00309 }
00310 if (!thisMsg) continue;
00311 if ( thisMsg->transferInProgress() &&
00312 thisMsg->parent()->folderType() == KMFolderTypeImap )
00313 {
00314 thisMsg->setTransferInProgress( false, true );
00315 thisMsg->parent()->ignoreJobsForMessage( thisMsg );
00316 }
00317
00318 if ( thisMsg->parent() && !thisMsg->isComplete() &&
00319 ( !mProgressDialog || !mProgressDialog->wasCancelled() ) )
00320 {
00321 kdDebug(5006)<<"### INCOMPLETE\n";
00322
00323 complete = false;
00324 KMCommand::mCountJobs++;
00325 FolderJob *job = thisMsg->parent()->createJob(thisMsg);
00326 job->setCancellable( false );
00327 totalSize += thisMsg->msgSizeServer();
00328
00329 connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00330 this, SLOT(slotMsgTransfered(KMMessage*)));
00331
00332 connect(job, SIGNAL(finished()),
00333 this, SLOT(slotJobFinished()));
00334 connect(job, SIGNAL(progress(unsigned long, unsigned long)),
00335 this, SLOT(slotProgress(unsigned long, unsigned long)));
00336
00337 thisMsg->setTransferInProgress(true);
00338 job->start();
00339 } else {
00340 thisMsg->setTransferInProgress(true);
00341 mRetrievedMsgs.append(thisMsg);
00342 }
00343 }
00344
00345 if (complete)
00346 {
00347 delete mProgressDialog;
00348 mProgressDialog = 0;
00349 emit messagesTransfered( OK );
00350 } else {
00351
00352 if ( mProgressDialog ) {
00353 connect(mProgressDialog, SIGNAL(cancelClicked()),
00354 this, SLOT(slotTransferCancelled()));
00355 mProgressDialog->progressBar()->setTotalSteps(totalSize);
00356 }
00357 }
00358 }
00359
00360 void KMCommand::slotMsgTransfered(KMMessage* msg)
00361 {
00362 if ( mProgressDialog && mProgressDialog->wasCancelled() ) {
00363 emit messagesTransfered( Canceled );
00364 return;
00365 }
00366
00367
00368 mRetrievedMsgs.append(msg);
00369 }
00370
00371 void KMCommand::slotProgress( unsigned long done, unsigned long )
00372 {
00373 mProgressDialog->progressBar()->setProgress( done );
00374 }
00375
00376 void KMCommand::slotJobFinished()
00377 {
00378
00379 KMCommand::mCountJobs--;
00380
00381 if ( mProgressDialog && mProgressDialog->wasCancelled() ) return;
00382
00383 if ( (mCountMsgs - static_cast<int>(mRetrievedMsgs.count())) > KMCommand::mCountJobs )
00384 {
00385
00386 if ( mProgressDialog )
00387 mProgressDialog->hide();
00388 slotTransferCancelled();
00389 return;
00390 }
00391
00392 if ( mProgressDialog ) {
00393 mProgressDialog->setLabel(i18n("Please wait while the message is transferred",
00394 "Please wait while the %n messages are transferred", KMCommand::mCountJobs));
00395 }
00396 if (KMCommand::mCountJobs == 0)
00397 {
00398
00399 delete mProgressDialog;
00400 mProgressDialog = 0;
00401 emit messagesTransfered( OK );
00402 }
00403 }
00404
00405 void KMCommand::slotTransferCancelled()
00406 {
00407
00408 QValueListIterator<QGuardedPtr<KMFolder> > fit;
00409 for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
00410 if (!(*fit))
00411 continue;
00412 KMFolder *folder = *fit;
00413 KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder);
00414 if (imapFolder && imapFolder->account()) {
00415 imapFolder->account()->killAllJobs();
00416 }
00417 }
00418
00419 KMCommand::mCountJobs = 0;
00420 mCountMsgs = 0;
00421
00422 QPtrListIterator<KMMessage> it( mRetrievedMsgs );
00423 KMMessage* msg;
00424 while ( (msg = it.current()) != 0 )
00425 {
00426 KMFolder *folder = msg->parent();
00427 ++it;
00428 if (!folder)
00429 continue;
00430 msg->setTransferInProgress(false);
00431 int idx = folder->find(msg);
00432 if (idx > 0) folder->unGetMsg(idx);
00433 }
00434 mRetrievedMsgs.clear();
00435 emit messagesTransfered( Canceled );
00436 }
00437
00438 void KMCommand::keepFolderOpen( KMFolder *folder )
00439 {
00440 folder->open();
00441 mFolders.append( folder );
00442 }
00443
00444 KMMailtoComposeCommand::KMMailtoComposeCommand( const KURL &url,
00445 KMMessage *msg )
00446 :mUrl( url ), mMessage( msg )
00447 {
00448 }
00449
00450 KMCommand::Result KMMailtoComposeCommand::execute()
00451 {
00452 KMMessage *msg = new KMMessage;
00453 uint id = 0;
00454
00455 if ( mMessage && mMessage->parent() )
00456 id = mMessage->parent()->identity();
00457
00458 msg->initHeader(id);
00459 msg->setCharset("utf-8");
00460 msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
00461
00462 KMail::Composer * win = KMail::makeComposer( msg, id );
00463 win->setCharset("", TRUE);
00464 win->setFocusToSubject();
00465 win->show();
00466
00467 return OK;
00468 }
00469
00470
00471 KMMailtoReplyCommand::KMMailtoReplyCommand( QWidget *parent,
00472 const KURL &url, KMMessage *msg, const QString &selection )
00473 :KMCommand( parent, msg ), mUrl( url ), mSelection( selection )
00474 {
00475 }
00476
00477 KMCommand::Result KMMailtoReplyCommand::execute()
00478 {
00479
00480 KMMessage *msg = retrievedMessage();
00481 KMMessage *rmsg = msg->createReply( KMail::ReplyNone, mSelection );
00482 rmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
00483
00484 KMail::Composer * win = KMail::makeComposer( rmsg, 0 );
00485 win->setCharset(msg->codec()->mimeName(), TRUE);
00486 win->setReplyFocus();
00487 win->show();
00488
00489 return OK;
00490 }
00491
00492
00493 KMMailtoForwardCommand::KMMailtoForwardCommand( QWidget *parent,
00494 const KURL &url, KMMessage *msg )
00495 :KMCommand( parent, msg ), mUrl( url )
00496 {
00497 }
00498
00499 KMCommand::Result KMMailtoForwardCommand::execute()
00500 {
00501
00502 KMMessage *msg = retrievedMessage();
00503 KMMessage *fmsg = msg->createForward();
00504 fmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
00505
00506 KMail::Composer * win = KMail::makeComposer( fmsg );
00507 win->setCharset(msg->codec()->mimeName(), TRUE);
00508 win->show();
00509
00510 return OK;
00511 }
00512
00513
00514 KMAddBookmarksCommand::KMAddBookmarksCommand( const KURL &url, QWidget *parent )
00515 : KMCommand( parent ), mUrl( url )
00516 {
00517 }
00518
00519 KMCommand::Result KMAddBookmarksCommand::execute()
00520 {
00521 QString filename = locateLocal( "data", QString::fromLatin1("konqueror/bookmarks.xml") );
00522 KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,
00523 false );
00524 KBookmarkGroup group = bookManager->root();
00525 group.addBookmark( bookManager, mUrl.path(), KURL( mUrl ) );
00526 if( bookManager->save() ) {
00527 bookManager->emitChanged( group );
00528 }
00529
00530 return OK;
00531 }
00532
00533 KMMailtoAddAddrBookCommand::KMMailtoAddAddrBookCommand( const KURL &url,
00534 QWidget *parent )
00535 : KMCommand( parent ), mUrl( url )
00536 {
00537 }
00538
00539 KMCommand::Result KMMailtoAddAddrBookCommand::execute()
00540 {
00541 KAddrBookExternal::addEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
00542 parentWidget() );
00543
00544 return OK;
00545 }
00546
00547
00548 KMMailtoOpenAddrBookCommand::KMMailtoOpenAddrBookCommand( const KURL &url,
00549 QWidget *parent )
00550 : KMCommand( parent ), mUrl( url )
00551 {
00552 }
00553
00554 KMCommand::Result KMMailtoOpenAddrBookCommand::execute()
00555 {
00556 QString addr = KMMessage::decodeMailtoUrl( mUrl.path() );
00557 KAddrBookExternal::openEmail( KPIM::getEmailAddress(addr), addr ,
00558 parentWidget() );
00559
00560 return OK;
00561 }
00562
00563
00564 KMUrlCopyCommand::KMUrlCopyCommand( const KURL &url, KMMainWidget *mainWidget )
00565 :mUrl( url ), mMainWidget( mainWidget )
00566 {
00567 }
00568
00569 KMCommand::Result KMUrlCopyCommand::execute()
00570 {
00571 QClipboard* clip = QApplication::clipboard();
00572
00573 if (mUrl.protocol() == "mailto") {
00574
00575 QString address = KMMessage::decodeMailtoUrl( mUrl.path() );
00576 clip->setSelectionMode( true );
00577 clip->setText( address );
00578 clip->setSelectionMode( false );
00579 clip->setText( address );
00580 KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "Address copied to clipboard." ));
00581 } else {
00582
00583 clip->setSelectionMode( true );
00584 clip->setText( mUrl.url() );
00585 clip->setSelectionMode( false );
00586 clip->setText( mUrl.url() );
00587 KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "URL copied to clipboard." ));
00588 }
00589
00590 return OK;
00591 }
00592
00593
00594 KMUrlOpenCommand::KMUrlOpenCommand( const KURL &url, KMReaderWin *readerWin )
00595 :mUrl( url ), mReaderWin( readerWin )
00596 {
00597 }
00598
00599 KMCommand::Result KMUrlOpenCommand::execute()
00600 {
00601 if ( !mUrl.isEmpty() )
00602 mReaderWin->slotUrlOpen( mUrl, KParts::URLArgs() );
00603
00604 return OK;
00605 }
00606
00607
00608 KMUrlSaveCommand::KMUrlSaveCommand( const KURL &url, QWidget *parent )
00609 : KMCommand( parent ), mUrl( url )
00610 {
00611 }
00612
00613 KMCommand::Result KMUrlSaveCommand::execute()
00614 {
00615 if ( mUrl.isEmpty() )
00616 return OK;
00617 KURL saveUrl = KFileDialog::getSaveURL(mUrl.fileName(), QString::null,
00618 parentWidget() );
00619 if ( saveUrl.isEmpty() )
00620 return Canceled;
00621 if ( KIO::NetAccess::exists( saveUrl, false, parentWidget() ) )
00622 {
00623 if (KMessageBox::warningContinueCancel(0,
00624 i18n("<qt>File <b>%1</b> exists.<br>Do you want to replace it?</qt>")
00625 .arg(saveUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
00626 != KMessageBox::Continue)
00627 return Canceled;
00628 }
00629 KIO::Job *job = KIO::file_copy(mUrl, saveUrl, -1, true);
00630 connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotUrlSaveResult(KIO::Job*)));
00631 setEmitsCompletedItself( true );
00632 return OK;
00633 }
00634
00635 void KMUrlSaveCommand::slotUrlSaveResult( KIO::Job *job )
00636 {
00637 if ( job->error() ) {
00638 job->showErrorDialog();
00639 setResult( Failed );
00640 emit completed( this );
00641 }
00642 else {
00643 setResult( OK );
00644 emit completed( this );
00645 }
00646 }
00647
00648
00649 KMEditMsgCommand::KMEditMsgCommand( QWidget *parent, KMMessage *msg )
00650 :KMCommand( parent, msg )
00651 {
00652 }
00653
00654 KMCommand::Result KMEditMsgCommand::execute()
00655 {
00656 KMMessage *msg = retrievedMessage();
00657 if (!msg || !msg->parent() ||
00658 !kmkernel->folderIsDraftOrOutbox( msg->parent() ))
00659 return Failed;
00660
00661
00662
00663
00664 KMFolder *parent = msg->parent();
00665 if ( parent )
00666 parent->take( parent->find( msg ) );
00667
00668 KMail::Composer * win = KMail::makeComposer();
00669 msg->setTransferInProgress(false);
00670 win->setMsg(msg, FALSE, TRUE);
00671 win->setFolder( parent );
00672 win->show();
00673
00674 return OK;
00675 }
00676
00677
00678 KMShowMsgSrcCommand::KMShowMsgSrcCommand( QWidget *parent,
00679 KMMessage *msg, bool fixedFont )
00680 :KMCommand( parent, msg ), mFixedFont( fixedFont )
00681 {
00682
00683 mMsgWasComplete = msg->isComplete();
00684 }
00685
00686 KMCommand::Result KMShowMsgSrcCommand::execute()
00687 {
00688 KMMessage *msg = retrievedMessage();
00689 if ( msg->isComplete() && !mMsgWasComplete )
00690 msg->notify();
00691 QString str = msg->codec()->toUnicode( msg->asString() );
00692
00693 MailSourceViewer *viewer = new MailSourceViewer();
00694 viewer->setCaption( i18n("Message as Plain Text") );
00695 viewer->setText(str);
00696 if( mFixedFont )
00697 viewer->setFont(KGlobalSettings::fixedFont());
00698
00699
00700
00701
00702 if (QApplication::desktop()->isVirtualDesktop()) {
00703 int scnum = QApplication::desktop()->screenNumber(QCursor::pos());
00704 viewer->resize(QApplication::desktop()->screenGeometry(scnum).width()/2,
00705 2*QApplication::desktop()->screenGeometry(scnum).height()/3);
00706 } else {
00707 viewer->resize(QApplication::desktop()->geometry().width()/2,
00708 2*QApplication::desktop()->geometry().height()/3);
00709 }
00710 viewer->show();
00711
00712 return OK;
00713 }
00714
00715 static KURL subjectToUrl( const QString & subject ) {
00716 return KFileDialog::getSaveURL( subject.stripWhiteSpace()
00717 .replace( QDir::separator(), '_' ),
00718 QString::null );
00719 }
00720
00721 KMSaveMsgCommand::KMSaveMsgCommand( QWidget *parent, KMMessage * msg )
00722 : KMCommand( parent ),
00723 mMsgListIndex( 0 ),
00724 mStandAloneMessage( 0 ),
00725 mOffset( 0 ),
00726 mTotalSize( msg ? msg->msgSize() : 0 )
00727 {
00728 if ( !msg ) return;
00729 setDeletesItself( true );
00730
00731
00732
00733
00734 if ( msg->getMsgSerNum() != 0 ) {
00735 mMsgList.append( msg->getMsgSerNum() );
00736 } else {
00737 mStandAloneMessage = msg;
00738 }
00739 mUrl = subjectToUrl( msg->cleanSubject() );
00740 }
00741
00742 KMSaveMsgCommand::KMSaveMsgCommand( QWidget *parent,
00743 const QPtrList<KMMsgBase> &msgList )
00744 : KMCommand( parent ),
00745 mMsgListIndex( 0 ),
00746 mStandAloneMessage( 0 ),
00747 mOffset( 0 ),
00748 mTotalSize( 0 )
00749 {
00750 if (!msgList.getFirst())
00751 return;
00752 setDeletesItself( true );
00753 KMMsgBase *msgBase = msgList.getFirst();
00754
00755
00756
00757
00758 QPtrListIterator<KMMsgBase> it(msgList);
00759 while ( it.current() ) {
00760 mMsgList.append( (*it)->getMsgSerNum() );
00761 mTotalSize += (*it)->msgSize();
00762 if ((*it)->parent() != 0)
00763 (*it)->parent()->open();
00764 ++it;
00765 }
00766 mMsgListIndex = 0;
00767 mUrl = subjectToUrl( msgBase->cleanSubject() );
00768 }
00769
00770 KURL KMSaveMsgCommand::url()
00771 {
00772 return mUrl;
00773 }
00774
00775 KMCommand::Result KMSaveMsgCommand::execute()
00776 {
00777 mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, false, false );
00778 mJob->slotTotalSize( mTotalSize );
00779 mJob->setAsyncDataEnabled( true );
00780 mJob->setReportDataSent( true );
00781 connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)),
00782 SLOT(slotSaveDataReq()));
00783 connect(mJob, SIGNAL(result(KIO::Job*)),
00784 SLOT(slotSaveResult(KIO::Job*)));
00785 setEmitsCompletedItself( true );
00786 return OK;
00787 }
00788
00789 void KMSaveMsgCommand::slotSaveDataReq()
00790 {
00791 int remainingBytes = mData.size() - mOffset;
00792 if ( remainingBytes > 0 ) {
00793
00794 if ( remainingBytes > MAX_CHUNK_SIZE )
00795 remainingBytes = MAX_CHUNK_SIZE;
00796
00797 QByteArray data;
00798 data.duplicate( mData.data() + mOffset, remainingBytes );
00799 mJob->sendAsyncData( data );
00800 mOffset += remainingBytes;
00801 return;
00802 }
00803
00804 if ( mMsgListIndex < mMsgList.size() ) {
00805 KMMessage *msg = 0;
00806 int idx = -1;
00807 KMFolder * p = 0;
00808 KMMsgDict::instance()->getLocation( mMsgList[mMsgListIndex], &p, &idx );
00809 assert( p );
00810 assert( idx >= 0 );
00811 msg = p->getMsg(idx);
00812
00813 if (msg->transferInProgress()) {
00814 QByteArray data = QByteArray();
00815 mJob->sendAsyncData( data );
00816 }
00817 msg->setTransferInProgress( true );
00818 if (msg->isComplete() ) {
00819 slotMessageRetrievedForSaving(msg);
00820 } else {
00821
00822 if (msg->parent() && !msg->isComplete() ) {
00823 FolderJob *job = msg->parent()->createJob(msg);
00824 job->setCancellable( false );
00825 connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00826 this, SLOT(slotMessageRetrievedForSaving(KMMessage*)));
00827 job->start();
00828 }
00829 }
00830 } else {
00831 if ( mStandAloneMessage ) {
00832
00833 slotMessageRetrievedForSaving( mStandAloneMessage );
00834 mStandAloneMessage = 0;
00835 } else {
00836
00837 QByteArray data = QByteArray();
00838 mJob->sendAsyncData( data );
00839 }
00840 }
00841 }
00842
00843 void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg)
00844 {
00845 if ( msg ) {
00846 QCString str( msg->mboxMessageSeparator() );
00847 str += KMFolderMbox::escapeFrom( msg->asString() );
00848 str += "\n";
00849 msg->setTransferInProgress(false);
00850
00851 mData = str;
00852 mData.resize(mData.size() - 1);
00853 mOffset = 0;
00854 QByteArray data;
00855 int size;
00856
00857 if( mData.size() > (unsigned int) MAX_CHUNK_SIZE )
00858 size = MAX_CHUNK_SIZE;
00859 else
00860 size = mData.size();
00861
00862 data.duplicate( mData, size );
00863 mJob->sendAsyncData( data );
00864 mOffset += size;
00865 }
00866 ++mMsgListIndex;
00867
00868 if ( msg && msg->parent() && msg->getMsgSerNum() ) {
00869 int idx = -1;
00870 KMFolder * p = 0;
00871 KMMsgDict::instance()->getLocation( msg, &p, &idx );
00872 assert( p == msg->parent() ); assert( idx >= 0 );
00873 p->unGetMsg( idx );
00874 p->close();
00875 }
00876 }
00877
00878 void KMSaveMsgCommand::slotSaveResult(KIO::Job *job)
00879 {
00880 if (job->error())
00881 {
00882 if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
00883 {
00884 if (KMessageBox::warningContinueCancel(0,
00885 i18n("File %1 exists.\nDo you want to replace it?")
00886 .arg(mUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
00887 == KMessageBox::Continue) {
00888 mOffset = 0;
00889
00890 mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, true, false );
00891 mJob->slotTotalSize( mTotalSize );
00892 mJob->setAsyncDataEnabled( true );
00893 mJob->setReportDataSent( true );
00894 connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)),
00895 SLOT(slotSaveDataReq()));
00896 connect(mJob, SIGNAL(result(KIO::Job*)),
00897 SLOT(slotSaveResult(KIO::Job*)));
00898 }
00899 }
00900 else
00901 {
00902 job->showErrorDialog();
00903 setResult( Failed );
00904 emit completed( this );
00905 deleteLater();
00906 }
00907 } else {
00908 setResult( OK );
00909 emit completed( this );
00910 deleteLater();
00911 }
00912 }
00913
00914
00915
00916 KMOpenMsgCommand::KMOpenMsgCommand( QWidget *parent, const KURL & url,
00917 const QString & encoding )
00918 : KMCommand( parent ),
00919 mUrl( url ),
00920 mEncoding( encoding )
00921 {
00922 setDeletesItself( true );
00923 }
00924
00925 KMCommand::Result KMOpenMsgCommand::execute()
00926 {
00927 if ( mUrl.isEmpty() ) {
00928 mUrl = KFileDialog::getOpenURL( ":OpenMessage", "message/rfc822",
00929 parentWidget(), i18n("Open Message") );
00930 }
00931 if ( mUrl.isEmpty() ) {
00932 setDeletesItself( false );
00933 return Canceled;
00934 }
00935 mJob = KIO::get( mUrl, false, false );
00936 mJob->setReportDataSent( true );
00937 connect( mJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
00938 this, SLOT( slotDataArrived( KIO::Job*, const QByteArray & ) ) );
00939 connect( mJob, SIGNAL( result( KIO::Job * ) ),
00940 SLOT( slotResult( KIO::Job * ) ) );
00941 setEmitsCompletedItself( true );
00942 return OK;
00943 }
00944
00945 void KMOpenMsgCommand::slotDataArrived( KIO::Job *, const QByteArray & data )
00946 {
00947 if ( data.isEmpty() )
00948 return;
00949
00950 mMsgString.append( data.data(), data.size() );
00951 }
00952
00953 void KMOpenMsgCommand::slotResult( KIO::Job *job )
00954 {
00955 if ( job->error() ) {
00956
00957 job->showErrorDialog();
00958 setResult( Failed );
00959 emit completed( this );
00960 }
00961 else {
00962 int startOfMessage = 0;
00963 if ( mMsgString.compare( 0, 5, "From ", 5 ) == 0 ) {
00964 startOfMessage = mMsgString.find( '\n' );
00965 if ( startOfMessage == -1 ) {
00966 KMessageBox::sorry( parentWidget(),
00967 i18n( "The file does not contain a message." ) );
00968 setResult( Failed );
00969 emit completed( this );
00970
00971
00972
00973 SecondaryWindow *win = new SecondaryWindow();
00974 win->close();
00975 win->deleteLater();
00976 deleteLater();
00977 return;
00978 }
00979 startOfMessage += 1;
00980 }
00981
00982 bool multipleMessages = true;
00983 int endOfMessage = mMsgString.find( "\nFrom " );
00984 if ( endOfMessage == -1 ) {
00985 endOfMessage = mMsgString.length();
00986 multipleMessages = false;
00987 }
00988 DwMessage *dwMsg = new DwMessage;
00989 dwMsg->FromString( mMsgString.substr( startOfMessage,
00990 endOfMessage - startOfMessage ) );
00991 dwMsg->Parse();
00992
00993 if ( dwMsg->Headers().NumFields() == 0 ) {
00994 KMessageBox::sorry( parentWidget(),
00995 i18n( "The file does not contain a message." ) );
00996 delete dwMsg; dwMsg = 0;
00997 setResult( Failed );
00998 emit completed( this );
00999
01000 SecondaryWindow *win = new SecondaryWindow();
01001 win->close();
01002 win->deleteLater();
01003 deleteLater();
01004 return;
01005 }
01006 KMMessage *msg = new KMMessage( dwMsg );
01007 msg->setReadyToShow( true );
01008 KMReaderMainWin *win = new KMReaderMainWin();
01009 win->showMsg( mEncoding, msg );
01010 win->show();
01011 if ( multipleMessages )
01012 KMessageBox::information( win,
01013 i18n( "The file contains multiple messages. "
01014 "Only the first message is shown." ) );
01015 setResult( OK );
01016 emit completed( this );
01017 }
01018 deleteLater();
01019 }
01020
01021
01022
01023
01024
01025 KMReplyToCommand::KMReplyToCommand( QWidget *parent, KMMessage *msg,
01026 const QString &selection )
01027 : KMCommand( parent, msg ), mSelection( selection )
01028 {
01029 }
01030
01031 KMCommand::Result KMReplyToCommand::execute()
01032 {
01033 KCursorSaver busy(KBusyPtr::busy());
01034 KMMessage *msg = retrievedMessage();
01035 KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection );
01036 KMail::Composer * win = KMail::makeComposer( reply );
01037 win->setCharset( msg->codec()->mimeName(), TRUE );
01038 win->setReplyFocus();
01039 win->show();
01040
01041 return OK;
01042 }
01043
01044
01045 KMNoQuoteReplyToCommand::KMNoQuoteReplyToCommand( QWidget *parent,
01046 KMMessage *msg )
01047 : KMCommand( parent, msg )
01048 {
01049 }
01050
01051 KMCommand::Result KMNoQuoteReplyToCommand::execute()
01052 {
01053 KCursorSaver busy(KBusyPtr::busy());
01054 KMMessage *msg = retrievedMessage();
01055 KMMessage *reply = msg->createReply( KMail::ReplySmart, "", TRUE);
01056 KMail::Composer * win = KMail::makeComposer( reply );
01057 win->setCharset(msg->codec()->mimeName(), TRUE);
01058 win->setReplyFocus(false);
01059 win->show();
01060
01061 return OK;
01062 }
01063
01064
01065 KMReplyListCommand::KMReplyListCommand( QWidget *parent,
01066 KMMessage *msg, const QString &selection )
01067 : KMCommand( parent, msg ), mSelection( selection )
01068 {
01069 }
01070
01071 KMCommand::Result KMReplyListCommand::execute()
01072 {
01073 KCursorSaver busy(KBusyPtr::busy());
01074 KMMessage *msg = retrievedMessage();
01075 KMMessage *reply = msg->createReply( KMail::ReplyList, mSelection);
01076 KMail::Composer * win = KMail::makeComposer( reply );
01077 win->setCharset(msg->codec()->mimeName(), TRUE);
01078 win->setReplyFocus(false);
01079 win->show();
01080
01081 return OK;
01082 }
01083
01084
01085 KMReplyToAllCommand::KMReplyToAllCommand( QWidget *parent,
01086 KMMessage *msg, const QString &selection )
01087 :KMCommand( parent, msg ), mSelection( selection )
01088 {
01089 }
01090
01091 KMCommand::Result KMReplyToAllCommand::execute()
01092 {
01093 KCursorSaver busy(KBusyPtr::busy());
01094 KMMessage *msg = retrievedMessage();
01095 KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection );
01096 KMail::Composer * win = KMail::makeComposer( reply );
01097 win->setCharset( msg->codec()->mimeName(), TRUE );
01098 win->setReplyFocus();
01099 win->show();
01100
01101 return OK;
01102 }
01103
01104
01105 KMReplyAuthorCommand::KMReplyAuthorCommand( QWidget *parent, KMMessage *msg,
01106 const QString &selection )
01107 : KMCommand( parent, msg ), mSelection( selection )
01108 {
01109 }
01110
01111 KMCommand::Result KMReplyAuthorCommand::execute()
01112 {
01113 KCursorSaver busy(KBusyPtr::busy());
01114 KMMessage *msg = retrievedMessage();
01115 KMMessage *reply = msg->createReply( KMail::ReplyAuthor, mSelection );
01116 KMail::Composer * win = KMail::makeComposer( reply );
01117 win->setCharset( msg->codec()->mimeName(), TRUE );
01118 win->setReplyFocus();
01119 win->show();
01120
01121 return OK;
01122 }
01123
01124
01125 KMForwardCommand::KMForwardCommand( QWidget *parent,
01126 const QPtrList<KMMsgBase> &msgList, uint identity )
01127 : KMCommand( parent, msgList ),
01128 mIdentity( identity )
01129 {
01130 }
01131
01132 KMForwardCommand::KMForwardCommand( QWidget *parent, KMMessage *msg,
01133 uint identity )
01134 : KMCommand( parent, msg ),
01135 mIdentity( identity )
01136 {
01137 }
01138
01139 KMCommand::Result KMForwardCommand::execute()
01140 {
01141 QPtrList<KMMessage> msgList = retrievedMsgs();
01142
01143 if (msgList.count() >= 2) {
01144
01145
01146 if (KMessageBox::questionYesNo( parentWidget(),
01147 i18n("Forward selected messages as "
01148 "a MIME digest?"), QString::null, i18n("Send Digest"), i18n("Send") )
01149 == KMessageBox::Yes) {
01150 uint id = 0;
01151 KMMessage *fwdMsg = new KMMessage;
01152 KMMessagePart *msgPart = new KMMessagePart;
01153 QString msgPartText;
01154 int msgCnt = 0;
01155
01156
01157
01158 fwdMsg->initHeader(id);
01159 fwdMsg->setAutomaticFields(true);
01160 fwdMsg->mMsg->Headers().ContentType().CreateBoundary(1);
01161 QCString boundary( fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() );
01162 msgPartText = i18n("\nThis is a MIME digest forward. The content of the"
01163 " message is contained in the attachment(s).\n\n\n");
01164
01165 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01166
01167 if (id == 0)
01168 id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01169
01170 msgPartText += "--";
01171 msgPartText += QString::fromLatin1( boundary );
01172 msgPartText += "\nContent-Type: MESSAGE/RFC822";
01173 msgPartText += QString("; CHARSET=%1").arg(msg->charset());
01174 msgPartText += "\n";
01175 DwHeaders dwh;
01176 dwh.MessageId().CreateDefault();
01177 msgPartText += QString("Content-ID: %1\n").arg(dwh.MessageId().AsString().c_str());
01178 msgPartText += QString("Content-Description: %1").arg(msg->subject());
01179 if (!msg->subject().contains("(fwd)"))
01180 msgPartText += " (fwd)";
01181 msgPartText += "\n\n";
01182
01183 msg->removePrivateHeaderFields();
01184 msg->removeHeaderField("BCC");
01185
01186 msgPartText += msg->headerAsString();
01187 msgPartText += "\n";
01188 msgPartText += msg->body();
01189 msgPartText += "\n";
01190 msgCnt++;
01191 fwdMsg->link(msg, KMMsgStatusForwarded);
01192 }
01193 if ( id == 0 )
01194 id = mIdentity;
01195 fwdMsg->initHeader(id);
01196 msgPartText += "--";
01197 msgPartText += QString::fromLatin1( boundary );
01198 msgPartText += "--\n";
01199 QCString tmp;
01200 msgPart->setTypeStr("MULTIPART");
01201 tmp.sprintf( "Digest; boundary=\"%s\"", boundary.data() );
01202 msgPart->setSubtypeStr( tmp );
01203 msgPart->setName("unnamed");
01204 msgPart->setCte(DwMime::kCte7bit);
01205 msgPart->setContentDescription(QString("Digest of %1 messages.").arg(msgCnt));
01206
01207 msgPart->setBodyEncoded(QCString(msgPartText.ascii()));
01208 KCursorSaver busy(KBusyPtr::busy());
01209 KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
01210 win->addAttach(msgPart);
01211 win->show();
01212 return OK;
01213 } else {
01214 uint id = 0;
01215 QCString msgText = "";
01216 QPtrList<KMMessage> linklist;
01217 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01218
01219 if (id == 0)
01220 id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01221
01222 msgText += msg->createForwardBody();
01223 linklist.append(msg);
01224 }
01225 if ( id == 0 )
01226 id = mIdentity;
01227 KMMessage *fwdMsg = new KMMessage;
01228 fwdMsg->initHeader(id);
01229 fwdMsg->setAutomaticFields(true);
01230 fwdMsg->setCharset("utf-8");
01231 fwdMsg->setBody(msgText);
01232
01233 for (KMMessage *msg = linklist.first(); msg; msg = linklist.next())
01234 fwdMsg->link(msg, KMMsgStatusForwarded);
01235
01236 KCursorSaver busy(KBusyPtr::busy());
01237 KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
01238 win->setCharset("");
01239 win->show();
01240 return OK;
01241 }
01242 }
01243
01244
01245 KMMessage *msg = msgList.getFirst();
01246 if ( !msg || !msg->codec() )
01247 return Failed;
01248
01249 KCursorSaver busy(KBusyPtr::busy());
01250 KMMessage *fwdMsg = msg->createForward();
01251
01252 uint id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01253 if ( id == 0 )
01254 id = mIdentity;
01255 {
01256 KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
01257 win->setCharset( fwdMsg->codec()->mimeName(), true );
01258 win->setBody( QString::fromUtf8( msg->createForwardBody() ) );
01259 win->show();
01260 }
01261
01262 return OK;
01263 }
01264
01265
01266 KMForwardAttachedCommand::KMForwardAttachedCommand( QWidget *parent,
01267 const QPtrList<KMMsgBase> &msgList, uint identity, KMail::Composer *win )
01268 : KMCommand( parent, msgList ), mIdentity( identity ),
01269 mWin( QGuardedPtr<KMail::Composer>( win ))
01270 {
01271 }
01272
01273 KMForwardAttachedCommand::KMForwardAttachedCommand( QWidget *parent,
01274 KMMessage * msg, uint identity, KMail::Composer *win )
01275 : KMCommand( parent, msg ), mIdentity( identity ),
01276 mWin( QGuardedPtr< KMail::Composer >( win ))
01277 {
01278 }
01279
01280 KMCommand::Result KMForwardAttachedCommand::execute()
01281 {
01282 QPtrList<KMMessage> msgList = retrievedMsgs();
01283 KMMessage *fwdMsg = new KMMessage;
01284
01285 if (msgList.count() >= 2) {
01286
01287
01288 fwdMsg->initHeader(mIdentity);
01289 }
01290 else if (msgList.count() == 1) {
01291 KMMessage *msg = msgList.getFirst();
01292 fwdMsg->initFromMessage(msg);
01293 fwdMsg->setSubject( msg->forwardSubject() );
01294 }
01295
01296 fwdMsg->setAutomaticFields(true);
01297
01298 KCursorSaver busy(KBusyPtr::busy());
01299 if (!mWin)
01300 mWin = KMail::makeComposer(fwdMsg, mIdentity);
01301
01302
01303 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01304
01305 msg->removePrivateHeaderFields();
01306 msg->removeHeaderField("BCC");
01307
01308 KMMessagePart *msgPart = new KMMessagePart;
01309 msgPart->setTypeStr("message");
01310 msgPart->setSubtypeStr("rfc822");
01311 msgPart->setCharset(msg->charset());
01312 msgPart->setName("forwarded message");
01313 msgPart->setContentDescription(msg->from()+": "+msg->subject());
01314 msgPart->setContentDisposition( "inline" );
01315
01316 QValueList<int> dummy;
01317 msgPart->setBodyAndGuessCte(msg->asString(), dummy, true);
01318 msgPart->setCharset("");
01319
01320 fwdMsg->link(msg, KMMsgStatusForwarded);
01321 mWin->addAttach(msgPart);
01322 }
01323
01324 mWin->show();
01325
01326 return OK;
01327 }
01328
01329
01330 KMRedirectCommand::KMRedirectCommand( QWidget *parent,
01331 KMMessage *msg )
01332 : KMCommand( parent, msg )
01333 {
01334 }
01335
01336 KMCommand::Result KMRedirectCommand::execute()
01337 {
01338 KMMessage *msg = retrievedMessage();
01339 if ( !msg || !msg->codec() )
01340 return Failed;
01341
01342 RedirectDialog dlg( parentWidget(), "redirect", true,
01343 kmkernel->msgSender()->sendImmediate() );
01344 if (dlg.exec()==QDialog::Rejected) return Failed;
01345
01346 KMMessage *newMsg = msg->createRedirect( dlg.to() );
01347 KMFilterAction::sendMDN( msg, KMime::MDN::Dispatched );
01348
01349 const KMail::MessageSender::SendMethod method = dlg.sendImmediate()
01350 ? KMail::MessageSender::SendImmediate
01351 : KMail::MessageSender::SendLater;
01352 if ( !kmkernel->msgSender()->send( newMsg, method ) ) {
01353 kdDebug(5006) << "KMRedirectCommand: could not redirect message (sending failed)" << endl;
01354 return Failed;
01355 }
01356 return OK;
01357 }
01358
01359
01360 KMPrintCommand::KMPrintCommand( QWidget *parent,
01361 KMMessage *msg, bool htmlOverride, bool htmlLoadExtOverride,
01362 bool useFixedFont, const QString & encoding )
01363 : KMCommand( parent, msg ), mHtmlOverride( htmlOverride ),
01364 mHtmlLoadExtOverride( htmlLoadExtOverride ),
01365 mUseFixedFont( useFixedFont ), mEncoding( encoding )
01366 {
01367 }
01368
01369 KMCommand::Result KMPrintCommand::execute()
01370 {
01371 KMReaderWin printWin( 0, 0, 0 );
01372 printWin.setPrinting( true );
01373 printWin.readConfig();
01374 printWin.setHtmlOverride( mHtmlOverride );
01375 printWin.setHtmlLoadExtOverride( mHtmlLoadExtOverride );
01376 printWin.setUseFixedFont( mUseFixedFont );
01377 printWin.setOverrideEncoding( mEncoding );
01378 printWin.setMsg( retrievedMessage(), true );
01379 printWin.printMsg();
01380
01381 return OK;
01382 }
01383
01384
01385 KMSetStatusCommand::KMSetStatusCommand( KMMsgStatus status,
01386 const QValueList<Q_UINT32> &serNums, bool toggle )
01387 : mStatus( status ), mSerNums( serNums ), mToggle( toggle )
01388 {
01389 }
01390
01391 KMCommand::Result KMSetStatusCommand::execute()
01392 {
01393 QValueListIterator<Q_UINT32> it;
01394 int idx = -1;
01395 KMFolder *folder = 0;
01396 bool parentStatus = false;
01397
01398
01399
01400 if (mToggle) {
01401 KMMsgBase *msg;
01402 KMMsgDict::instance()->getLocation( *mSerNums.begin(), &folder, &idx );
01403 if (folder) {
01404 msg = folder->getMsgBase(idx);
01405 if (msg && (msg->status()&mStatus))
01406 parentStatus = true;
01407 else
01408 parentStatus = false;
01409 }
01410 }
01411 QMap< KMFolder*, QValueList<int> > folderMap;
01412 for ( it = mSerNums.begin(); it != mSerNums.end(); ++it ) {
01413 KMMsgDict::instance()->getLocation( *it, &folder, &idx );
01414 if (folder) {
01415 if (mToggle) {
01416 KMMsgBase *msg = folder->getMsgBase(idx);
01417
01418 if (msg) {
01419 bool myStatus;
01420 if (msg->status()&mStatus)
01421 myStatus = true;
01422 else
01423 myStatus = false;
01424 if (myStatus != parentStatus)
01425 continue;
01426 }
01427 }
01428
01429
01430 folderMap[folder].append(idx);
01431 }
01432 }
01433 QMapIterator< KMFolder*, QValueList<int> > it2 = folderMap.begin();
01434 while ( it2 != folderMap.end() ) {
01435 KMFolder *f = it2.key();
01436 f->setStatus( (*it2), mStatus, mToggle );
01437 ++it2;
01438 }
01439
01440
01441 return OK;
01442 }
01443
01444
01445 KMFilterCommand::KMFilterCommand( const QCString &field, const QString &value )
01446 : mField( field ), mValue( value )
01447 {
01448 }
01449
01450 KMCommand::Result KMFilterCommand::execute()
01451 {
01452 kmkernel->filterMgr()->createFilter( mField, mValue );
01453
01454 return OK;
01455 }
01456
01457
01458 KMFilterActionCommand::KMFilterActionCommand( QWidget *parent,
01459 const QPtrList<KMMsgBase> &msgList,
01460 KMFilter *filter )
01461 : KMCommand( parent, msgList ), mFilter( filter )
01462 {
01463 }
01464
01465 KMCommand::Result KMFilterActionCommand::execute()
01466 {
01467 KCursorSaver busy( KBusyPtr::busy() );
01468 QPtrList<KMMessage> msgList = retrievedMsgs();
01469
01470 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next())
01471 if( msg->parent() )
01472 kmkernel->filterMgr()->tempOpenFolder(msg->parent());
01473
01474 int counter = 0;
01475 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01476 msg->setTransferInProgress(false);
01477
01478 if ( !( ++counter % 20 ) )
01479 KApplication::kApplication()->processEvents( 50 );
01480
01481 int filterResult = kmkernel->filterMgr()->process(msg, mFilter);
01482 if (filterResult == 2) {
01483
01484 perror("Critical error");
01485 kmkernel->emergencyExit( i18n("Not enough free disk space?" ));
01486 }
01487 msg->setTransferInProgress(true);
01488 }
01489
01490 return OK;
01491 }
01492
01493
01494 KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter,
01495 KMHeaders *headers,
01496 KMMainWidget *main )
01497 : QObject( main ),
01498 mFilter( filter ), mHeaders( headers ), mMainWidget( main )
01499 {
01500 }
01501
01502 void KMMetaFilterActionCommand::start()
01503 {
01504 if (ActionScheduler::isEnabled() ) {
01505
01506 KMFilterMgr::FilterSet set = KMFilterMgr::All;
01507 QValueList<KMFilter*> filters;
01508 filters.append( mFilter );
01509 ActionScheduler *scheduler = new ActionScheduler( set, filters, mHeaders );
01510 scheduler->setAlwaysMatch( true );
01511 scheduler->setAutoDestruct( true );
01512
01513 int contentX, contentY;
01514 HeaderItem *nextItem = mHeaders->prepareMove( &contentX, &contentY );
01515 QPtrList<KMMsgBase> msgList = *mHeaders->selectedMsgs(true);
01516 mHeaders->finalizeMove( nextItem, contentX, contentY );
01517
01518 for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
01519 scheduler->execFilters( msg );
01520 } else {
01521 KMCommand *filterCommand = new KMFilterActionCommand( mMainWidget,
01522 *mHeaders->selectedMsgs(), mFilter);
01523 filterCommand->start();
01524 int contentX, contentY;
01525 HeaderItem *item = mHeaders->prepareMove( &contentX, &contentY );
01526 mHeaders->finalizeMove( item, contentX, contentY );
01527 }
01528 }
01529
01530 FolderShortcutCommand::FolderShortcutCommand( KMMainWidget *mainwidget,
01531 KMFolder *folder )
01532 : mMainWidget( mainwidget ), mFolder( folder ), mAction( 0 )
01533 {
01534 }
01535
01536
01537 FolderShortcutCommand::~FolderShortcutCommand()
01538 {
01539 if ( mAction ) mAction->unplugAll();
01540 delete mAction;
01541 }
01542
01543 void FolderShortcutCommand::start()
01544 {
01545 mMainWidget->slotSelectFolder( mFolder );
01546 }
01547
01548 void FolderShortcutCommand::setAction( KAction* action )
01549 {
01550 mAction = action;
01551 }
01552
01553 KMMailingListFilterCommand::KMMailingListFilterCommand( QWidget *parent,
01554 KMMessage *msg )
01555 : KMCommand( parent, msg )
01556 {
01557 }
01558
01559 KMCommand::Result KMMailingListFilterCommand::execute()
01560 {
01561 QCString name;
01562 QString value;
01563 KMMessage *msg = retrievedMessage();
01564 if (!msg)
01565 return Failed;
01566
01567 if ( !MailingList::name( msg, name, value ).isEmpty() ) {
01568 kmkernel->filterMgr()->createFilter( name, value );
01569 return OK;
01570 }
01571 else
01572 return Failed;
01573 }
01574
01575
01576 void KMMenuCommand::folderToPopupMenu(bool move,
01577 QObject *receiver, KMMenuToFolder *aMenuToFolder, QPopupMenu *menu )
01578 {
01579 while ( menu->count() )
01580 {
01581 QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
01582 if (popup)
01583 delete popup;
01584 else
01585 menu->removeItemAt( 0 );
01586 }
01587
01588 if (!kmkernel->imapFolderMgr()->dir().first() &&
01589 !kmkernel->dimapFolderMgr()->dir().first())
01590 {
01591 makeFolderMenu( &kmkernel->folderMgr()->dir(), move,
01592 receiver, aMenuToFolder, menu );
01593 } else {
01594
01595 QPopupMenu* subMenu = new QPopupMenu(menu);
01596 makeFolderMenu( &kmkernel->folderMgr()->dir(),
01597 move, receiver, aMenuToFolder, subMenu );
01598 menu->insertItem( i18n( "Local Folders" ), subMenu );
01599 KMFolderDir* fdir = &kmkernel->imapFolderMgr()->dir();
01600 for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
01601 if (node->isDir())
01602 continue;
01603 subMenu = new QPopupMenu(menu);
01604 makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
01605 menu->insertItem( node->label(), subMenu );
01606 }
01607 fdir = &kmkernel->dimapFolderMgr()->dir();
01608 for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
01609 if (node->isDir())
01610 continue;
01611 subMenu = new QPopupMenu(menu);
01612 makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
01613 menu->insertItem( node->label(), subMenu );
01614 }
01615 }
01616 }
01617
01618 void KMMenuCommand::makeFolderMenu(KMFolderNode* node, bool move,
01619 QObject *receiver, KMMenuToFolder *aMenuToFolder, QPopupMenu *menu )
01620 {
01621
01622 if (move)
01623 {
01624 disconnect(menu, SIGNAL(activated(int)), receiver,
01625 SLOT(moveSelectedToFolder(int)));
01626 connect(menu, SIGNAL(activated(int)), receiver,
01627 SLOT(moveSelectedToFolder(int)));
01628 } else {
01629 disconnect(menu, SIGNAL(activated(int)), receiver,
01630 SLOT(copySelectedToFolder(int)));
01631 connect(menu, SIGNAL(activated(int)), receiver,
01632 SLOT(copySelectedToFolder(int)));
01633 }
01634
01635 KMFolder *folder = 0;
01636 KMFolderDir *folderDir = 0;
01637 if (node->isDir()) {
01638 folderDir = static_cast<KMFolderDir*>(node);
01639 } else {
01640 folder = static_cast<KMFolder*>(node);
01641 folderDir = folder->child();
01642 }
01643
01644 if (folder && !folder->noContent())
01645 {
01646 int menuId;
01647 if (move)
01648 menuId = menu->insertItem(i18n("Move to This Folder"));
01649 else
01650 menuId = menu->insertItem(i18n("Copy to This Folder"));
01651 aMenuToFolder->insert( menuId, folder );
01652 menu->setItemEnabled( menuId, !folder->isReadOnly() );
01653 menu->insertSeparator();
01654 }
01655
01656 if (!folderDir)
01657 return;
01658
01659 for (KMFolderNode *it = folderDir->first(); it; it = folderDir->next() ) {
01660 if (it->isDir())
01661 continue;
01662 KMFolder *child = static_cast<KMFolder*>(it);
01663 QString label = child->label();
01664 label.replace("&","&&");
01665 if (child->child() && child->child()->first()) {
01666
01667 QPopupMenu *subMenu = new QPopupMenu(menu, "subMenu");
01668 makeFolderMenu( child, move, receiver,
01669 aMenuToFolder, subMenu );
01670 menu->insertItem( label, subMenu );
01671 } else {
01672
01673 int menuId = menu->insertItem( label );
01674 aMenuToFolder->insert( menuId, child );
01675 menu->setItemEnabled( menuId, !child->isReadOnly() );
01676 }
01677 }
01678 return;
01679 }
01680
01681
01682 KMCopyCommand::KMCopyCommand( KMFolder* destFolder,
01683 const QPtrList<KMMsgBase> &msgList )
01684 :mDestFolder( destFolder ), mMsgList( msgList )
01685 {
01686 setDeletesItself( true );
01687 }
01688
01689 KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg )
01690 :mDestFolder( destFolder )
01691 {
01692 setDeletesItself( true );
01693 mMsgList.append( &msg->toMsgBase() );
01694 }
01695
01696 KMCommand::Result KMCopyCommand::execute()
01697 {
01698 KMMsgBase *msgBase;
01699 KMMessage *msg, *newMsg;
01700 int idx = -1;
01701 bool isMessage;
01702 QPtrList<KMMessage> list;
01703 QPtrList<KMMessage> localList;
01704
01705 if (mDestFolder && mDestFolder->open() != 0)
01706 {
01707 deleteLater();
01708 return Failed;
01709 }
01710
01711 KCursorSaver busy(KBusyPtr::busy());
01712
01713 mWaitingForMsgs.clear();
01714 for (msgBase = mMsgList.first(); msgBase; msgBase = mMsgList.next() )
01715 {
01716 KMFolder *srcFolder = msgBase->parent();
01717 if (isMessage = msgBase->isMessage())
01718 {
01719 msg = static_cast<KMMessage*>(msgBase);
01720 } else {
01721 idx = srcFolder->find(msgBase);
01722 assert(idx != -1);
01723 msg = srcFolder->getMsg(idx);
01724 }
01725
01726 if (srcFolder &&
01727 (srcFolder->folderType()== KMFolderTypeImap) &&
01728 (mDestFolder->folderType() == KMFolderTypeImap) &&
01729 (static_cast<KMFolderImap*>(srcFolder->storage())->account() ==
01730 static_cast<KMFolderImap*>(mDestFolder->storage())->account()))
01731 {
01732
01733 list.append(msg);
01734 } else {
01735 newMsg = new KMMessage;
01736 newMsg->setComplete(msg->isComplete());
01737
01738 if (!newMsg->isComplete())
01739 newMsg->setReadyToShow(false);
01740 newMsg->fromString(msg->asString());
01741 newMsg->setStatus(msg->status());
01742
01743 if (srcFolder && !newMsg->isComplete())
01744 {
01745
01746 mWaitingForMsgs.append( msg->getMsgSerNum() );
01747 disconnect(mDestFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
01748 this, SLOT(slotMsgAdded(KMFolder*, Q_UINT32)));
01749 connect(mDestFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
01750 this, SLOT(slotMsgAdded(KMFolder*, Q_UINT32)));
01751 newMsg->setParent(msg->parent());
01752 FolderJob *job = srcFolder->createJob(newMsg);
01753 job->setCancellable( false );
01754 connect(job, SIGNAL(messageRetrieved(KMMessage*)),
01755 mDestFolder, SLOT(reallyAddCopyOfMsg(KMMessage*)));
01756 job->start();
01757 } else {
01758
01759 localList.append(newMsg);
01760 }
01761 }
01762
01763 if (!isMessage && list.isEmpty())
01764 {
01765 assert(idx != -1);
01766 srcFolder->unGetMsg( idx );
01767 }
01768
01769 }
01770
01771 bool deleteNow = false;
01772 if (!localList.isEmpty())
01773 {
01774 QValueList<int> index;
01775 mDestFolder->addMsg( localList, index );
01776 for ( QValueListIterator<int> it = index.begin(); it != index.end(); ++it ) {
01777 mDestFolder->unGetMsg( *it );
01778 }
01779 if ( mDestFolder->folderType() == KMFolderTypeImap ) {
01780 if ( mWaitingForMsgs.isEmpty() ) {
01781
01782 KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
01783 connect( imapDestFolder, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
01784 this, SLOT( slotFolderComplete() ) );
01785 }
01786 } else {
01787 deleteNow = true;
01788 }
01789 }
01790
01791
01792
01793 if (!list.isEmpty())
01794 {
01795
01796 KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
01797 connect( imapDestFolder, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
01798 this, SLOT( slotFolderComplete() ) );
01799 imapDestFolder->copyMsg(list);
01800 imapDestFolder->getFolder();
01801 }
01802
01803
01804
01805 if ( deleteNow )
01806 {
01807 mDestFolder->close();
01808 deleteLater();
01809 }
01810
01811 return OK;
01812 }
01813
01814 void KMCopyCommand::slotMsgAdded( KMFolder*, Q_UINT32 serNum )
01815 {
01816 mWaitingForMsgs.remove( serNum );
01817 if ( mWaitingForMsgs.isEmpty() )
01818 {
01819 mDestFolder->close();
01820 deleteLater();
01821 }
01822 }
01823
01824 void KMCopyCommand::slotFolderComplete()
01825 {
01826 mDestFolder->close();
01827 deleteLater();
01828 }
01829
01830
01831 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01832 const QPtrList<KMMsgBase> &msgList)
01833 : mDestFolder( destFolder ), mMsgList( msgList ), mProgressItem( 0 )
01834 {
01835 }
01836
01837 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01838 KMMessage *msg )
01839 : mDestFolder( destFolder ), mProgressItem( 0 )
01840 {
01841 mMsgList.append( &msg->toMsgBase() );
01842 }
01843
01844 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01845 KMMsgBase *msgBase )
01846 : mDestFolder( destFolder ), mProgressItem( 0 )
01847 {
01848 mMsgList.append( msgBase );
01849 }
01850
01851 KMMoveCommand::KMMoveCommand( Q_UINT32 )
01852 : mProgressItem( 0 )
01853 {
01854 }
01855
01856 KMCommand::Result KMMoveCommand::execute()
01857 {
01858 setEmitsCompletedItself( true );
01859 setDeletesItself( true );
01860 typedef QMap< KMFolder*, QPtrList<KMMessage>* > FolderToMessageListMap;
01861 FolderToMessageListMap folderDeleteList;
01862
01863 if (mDestFolder && mDestFolder->open() != 0) {
01864 completeMove( Failed );
01865 return Failed;
01866 }
01867 KCursorSaver busy(KBusyPtr::busy());
01868
01869
01870 Q_ASSERT( !mProgressItem );
01871 mProgressItem =
01872 ProgressManager::createProgressItem (
01873 "move"+ProgressManager::getUniqueID(),
01874 mDestFolder ? i18n( "Moving messages" ) : i18n( "Deleting messages" ) );
01875 connect( mProgressItem, SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
01876 this, SLOT( slotMoveCanceled() ) );
01877
01878 KMMessage *msg;
01879 KMMsgBase *msgBase;
01880 int rc = 0;
01881 int index;
01882 QPtrList<KMMessage> list;
01883 int undoId = -1;
01884
01885 if (mDestFolder) {
01886 connect (mDestFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
01887 this, SLOT(slotMsgAddedToDestFolder(KMFolder*, Q_UINT32)));
01888 for ( msgBase=mMsgList.first(); msgBase; msgBase=mMsgList.next() ) {
01889 mLostBoys.append( msgBase->getMsgSerNum() );
01890 }
01891 }
01892 mProgressItem->setTotalItems( mMsgList.count() );
01893
01894 for (msgBase=mMsgList.first(); msgBase && !rc; msgBase=mMsgList.next()) {
01895 KMFolder *srcFolder = msgBase->parent();
01896 if (srcFolder == mDestFolder)
01897 continue;
01898 bool undo = msgBase->enableUndo();
01899 int idx = srcFolder->find(msgBase);
01900 assert(idx != -1);
01901 if ( msgBase->isMessage() ) {
01902 msg = static_cast<KMMessage*>(msgBase);
01903 } else {
01904 msg = srcFolder->getMsg(idx);
01905 }
01906
01907 if ( msg->transferInProgress() &&
01908 srcFolder->folderType() == KMFolderTypeImap )
01909 {
01910
01911 msg->setTransferInProgress( false, true );
01912 static_cast<KMFolderImap*>(srcFolder->storage())->ignoreJobsForMessage( msg );
01913 }
01914
01915 if (mDestFolder) {
01916 if (mDestFolder->folderType() == KMFolderTypeImap) {
01917
01918
01919
01920 KMFolderImap *imapFolder = static_cast<KMFolderImap*> ( mDestFolder->storage() );
01921 disconnect (imapFolder, SIGNAL(folderComplete( KMFolderImap*, bool )),
01922 this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
01923
01924 connect (imapFolder, SIGNAL(folderComplete( KMFolderImap*, bool )),
01925 this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
01926 list.append(msg);
01927 } else {
01928
01929 rc = mDestFolder->moveMsg(msg, &index);
01930 if (rc == 0 && index != -1) {
01931 KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 );
01932 if (undo && mb)
01933 {
01934 if ( undoId == -1 )
01935 undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder );
01936 kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() );
01937 }
01938 } else if (rc != 0) {
01939
01940
01941 completeMove( Failed );
01942 return Failed;
01943 }
01944 }
01945 } else {
01946
01947
01948 if (srcFolder->folderType() == KMFolderTypeImap) {
01949 if (!folderDeleteList[srcFolder])
01950 folderDeleteList[srcFolder] = new QPtrList<KMMessage>;
01951 folderDeleteList[srcFolder]->append( msg );
01952 } else {
01953 srcFolder->removeMsg(idx);
01954 delete msg;
01955 }
01956 }
01957 }
01958 if (!list.isEmpty() && mDestFolder) {
01959
01960 mDestFolder->moveMsg(list, &index);
01961 } else {
01962 FolderToMessageListMap::Iterator it;
01963 for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
01964 it.key()->removeMsg(*it.data());
01965 delete it.data();
01966 }
01967
01968 completeMove( OK );
01969 }
01970
01971 return OK;
01972 }
01973
01974 void KMMoveCommand::slotImapFolderCompleted(KMFolderImap* imapFolder, bool success)
01975 {
01976 disconnect (imapFolder, SIGNAL(folderComplete( KMFolderImap*, bool )),
01977 this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
01978 if ( success ) {
01979
01980
01981
01982
01983
01984
01985 if ( !mLostBoys.isEmpty() ) {
01986 kdDebug(5006) << "### Not all moved messages reported back that they were " << endl
01987 << "### added to the target folder. Did uidValidity change? " << endl;
01988 }
01989 completeMove( OK );
01990 } else {
01991
01992 completeMove( Failed );
01993 }
01994 }
01995
01996 void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, Q_UINT32 serNum)
01997 {
01998 if ( folder != mDestFolder || mLostBoys.find( serNum ) == mLostBoys.end() ) {
01999
02000
02001 return;
02002 }
02003 mLostBoys.remove(serNum);
02004 if ( mLostBoys.isEmpty() ) {
02005
02006 disconnect (mDestFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
02007 this, SLOT(slotMsgAddedToDestFolder(KMFolder*, Q_UINT32)));
02008 if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) {
02009 mDestFolder->sync();
02010 }
02011 } else {
02012 if ( mProgressItem ) {
02013 mProgressItem->incCompletedItems();
02014 mProgressItem->updateProgress();
02015 }
02016 }
02017 }
02018
02019 void KMMoveCommand::completeMove( Result result )
02020 {
02021 if ( mDestFolder )
02022 mDestFolder->close();
02023 while ( !mOpenedFolders.empty() ) {
02024 KMFolder *folder = mOpenedFolders.back();
02025 mOpenedFolders.pop_back();
02026 folder->close();
02027 }
02028 if ( mProgressItem ) {
02029 mProgressItem->setComplete();
02030 mProgressItem = 0;
02031 }
02032 setResult( result );
02033 emit completed( this );
02034 deleteLater();
02035 }
02036
02037 void KMMoveCommand::slotMoveCanceled()
02038 {
02039 completeMove( Canceled );
02040 }
02041
02042
02043 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder,
02044 const QPtrList<KMMsgBase> &msgList )
02045 :KMMoveCommand( findTrashFolder( srcFolder ), msgList)
02046 {
02047 srcFolder->open();
02048 mOpenedFolders.push_back( srcFolder );
02049 }
02050
02051 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
02052 :KMMoveCommand( findTrashFolder( srcFolder ), msg)
02053 {
02054 srcFolder->open();
02055 mOpenedFolders.push_back( srcFolder );
02056 }
02057
02058 KMDeleteMsgCommand::KMDeleteMsgCommand( Q_UINT32 sernum )
02059 :KMMoveCommand( sernum )
02060 {
02061 KMFolder *srcFolder;
02062 int idx;
02063 KMMsgDict::instance()->getLocation( sernum, &srcFolder, &idx );
02064 KMMsgBase *msg = srcFolder->getMsgBase( idx );
02065 srcFolder->open();
02066 mOpenedFolders.push_back( srcFolder );
02067 addMsg( msg );
02068 setDestFolder( findTrashFolder( srcFolder ) );
02069 }
02070
02071 KMFolder * KMDeleteMsgCommand::findTrashFolder( KMFolder * folder )
02072 {
02073 KMFolder* trash = folder->trashFolder();
02074 if( !trash )
02075 trash = kmkernel->trashFolder();
02076 if( trash != folder )
02077 return trash;
02078 return 0;
02079 }
02080
02081
02082 KMUrlClickedCommand::KMUrlClickedCommand( const KURL &url, uint identity,
02083 KMReaderWin *readerWin, bool htmlPref, KMMainWidget *mainWidget )
02084 :mUrl( url ), mIdentity( identity ), mReaderWin( readerWin ),
02085 mHtmlPref( htmlPref ), mMainWidget( mainWidget )
02086 {
02087 }
02088
02089 KMCommand::Result KMUrlClickedCommand::execute()
02090 {
02091 KMMessage* msg;
02092
02093 if (mUrl.protocol() == "mailto")
02094 {
02095 msg = new KMMessage;
02096 msg->initHeader(mIdentity);
02097 msg->setCharset("utf-8");
02098 msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
02099 QString query=mUrl.query();
02100 while (!query.isEmpty()) {
02101 QString queryPart;
02102 int secondQuery = query.find('?',1);
02103 if (secondQuery != -1)
02104 queryPart = query.left(secondQuery);
02105 else
02106 queryPart = query;
02107 query = query.mid(queryPart.length());
02108
02109 if (queryPart.left(9) == "?subject=")
02110 msg->setSubject( KURL::decode_string(queryPart.mid(9)) );
02111 else if (queryPart.left(6) == "?body=")
02112
02113
02114 msg->setBody( KURL::decode_string(queryPart.mid(6)).latin1() );
02115 else if (queryPart.left(4) == "?cc=")
02116 msg->setCc( KURL::decode_string(queryPart.mid(4)) );
02117 }
02118
02119 KMail::Composer * win = KMail::makeComposer( msg, mIdentity );
02120 win->setCharset("", TRUE);
02121 win->show();
02122 }
02123 else if ( mUrl.protocol() == "im" )
02124 {
02125 kmkernel->imProxy()->chatWithContact( mUrl.path() );
02126 }
02127 else if ((mUrl.protocol() == "http") || (mUrl.protocol() == "https") ||
02128 (mUrl.protocol() == "ftp") || (mUrl.protocol() == "file") ||
02129 (mUrl.protocol() == "ftps") || (mUrl.protocol() == "sftp" ) ||
02130 (mUrl.protocol() == "help") || (mUrl.protocol() == "vnc") ||
02131 (mUrl.protocol() == "smb") || (mUrl.protocol() == "fish") ||
02132 (mUrl.protocol() == "news"))
02133 {
02134 KPIM::BroadcastStatus::instance()->setStatusMsg( i18n("Opening URL..."));
02135 KMimeType::Ptr mime = KMimeType::findByURL( mUrl );
02136 if (mime->name() == "application/x-desktop" ||
02137 mime->name() == "application/x-executable" ||
02138 mime->name() == "application/x-msdos-program" ||
02139 mime->name() == "application/x-shellscript" )
02140 {
02141 if (KMessageBox::warningYesNo( 0, i18n( "<qt>Do you really want to execute <b>%1</b>?</qt>" )
02142 .arg( mUrl.prettyURL() ), QString::null, i18n("Execute"), KStdGuiItem::cancel() ) != KMessageBox::Yes)
02143 return Canceled;
02144 }
02145 (void) new KRun( mUrl );
02146 }
02147 else
02148 return Failed;
02149
02150 return OK;
02151 }
02152
02153 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, KMMessage *msg )
02154 : KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
02155 {
02156 }
02157
02158 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, const QPtrList<KMMsgBase>& msgs )
02159 : KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
02160 {
02161 }
02162
02163 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, QPtrList<partNode>& attachments,
02164 KMMessage *msg, bool encoded )
02165 : KMCommand( parent ), mImplicitAttachments( false ), mEncoded( encoded )
02166 {
02167 for ( QPtrListIterator<partNode> it( attachments ); it.current(); ++it ) {
02168 mAttachmentMap.insert( it.current(), msg );
02169 }
02170 }
02171
02172 KMCommand::Result KMSaveAttachmentsCommand::execute()
02173 {
02174 setEmitsCompletedItself( true );
02175 if ( mImplicitAttachments ) {
02176 QPtrList<KMMessage> msgList = retrievedMsgs();
02177 KMMessage *msg;
02178 for ( QPtrListIterator<KMMessage> itr( msgList );
02179 ( msg = itr.current() );
02180 ++itr ) {
02181 partNode *rootNode = partNode::fromMessage( msg );
02182 for ( partNode *child = rootNode; child;
02183 child = child->firstChild() ) {
02184 for ( partNode *node = child; node; node = node->nextSibling() ) {
02185 if ( node->type() != DwMime::kTypeMultipart )
02186 mAttachmentMap.insert( node, msg );
02187 }
02188 }
02189 }
02190 }
02191 setDeletesItself( true );
02192
02193 KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachmentMap );
02194 connect( command, SIGNAL( partsRetrieved() ),
02195 this, SLOT( slotSaveAll() ) );
02196 command->start();
02197
02198 return OK;
02199 }
02200
02201 void KMSaveAttachmentsCommand::slotSaveAll()
02202 {
02203
02204
02205
02206 if ( mImplicitAttachments ) {
02207 for ( PartNodeMessageMap::iterator it = mAttachmentMap.begin();
02208 it != mAttachmentMap.end(); ) {
02209
02210
02211
02212 if ( it.key()->msgPart().fileName().stripWhiteSpace().isEmpty() &&
02213 ( it.key()->msgPart().name().stripWhiteSpace().isEmpty() ||
02214 !it.key()->parentNode() ) ) {
02215 PartNodeMessageMap::iterator delIt = it;
02216 ++it;
02217 mAttachmentMap.remove( delIt );
02218 }
02219 else
02220 ++it;
02221 }
02222 if ( mAttachmentMap.isEmpty() ) {
02223 KMessageBox::information( 0, i18n("Found no attachments to save.") );
02224 setResult( OK );
02225 emit completed( this );
02226 deleteLater();
02227 return;
02228 }
02229 }
02230
02231 KURL url, dirUrl;
02232 if ( mAttachmentMap.count() > 1 ) {
02233
02234 dirUrl = KDirSelectDialog::selectDirectory( QString::null, false,
02235 parentWidget(),
02236 i18n("Save Attachments To") );
02237 if ( !dirUrl.isValid() ) {
02238 setResult( Canceled );
02239 emit completed( this );
02240 deleteLater();
02241 return;
02242 }
02243
02244
02245 dirUrl.adjustPath( 1 );
02246 }
02247 else {
02248
02249 partNode *node = mAttachmentMap.begin().key();
02250
02251 QString s =
02252 node->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
02253 if ( s.isEmpty() )
02254 s = node->msgPart().name().stripWhiteSpace().replace( ':', '_' );
02255 if ( s.isEmpty() )
02256 s = i18n("filename for an unnamed attachment", "attachment.1");
02257 url = KFileDialog::getSaveURL( s, QString::null, parentWidget(),
02258 QString::null );
02259 if ( url.isEmpty() ) {
02260 setResult( Canceled );
02261 emit completed( this );
02262 deleteLater();
02263 return;
02264 }
02265 }
02266
02267 QMap< QString, int > renameNumbering;
02268
02269 Result globalResult = OK;
02270 int unnamedAtmCount = 0;
02271 for ( PartNodeMessageMap::const_iterator it = mAttachmentMap.begin();
02272 it != mAttachmentMap.end();
02273 ++it ) {
02274 KURL curUrl;
02275 if ( !dirUrl.isEmpty() ) {
02276 curUrl = dirUrl;
02277 QString s =
02278 it.key()->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
02279 if ( s.isEmpty() )
02280 s = it.key()->msgPart().name().stripWhiteSpace().replace( ':', '_' );
02281 if ( s.isEmpty() ) {
02282 ++unnamedAtmCount;
02283 s = i18n("filename for the %1-th unnamed attachment",
02284 "attachment.%1")
02285 .arg( unnamedAtmCount );
02286 }
02287 curUrl.setFileName( s );
02288 } else {
02289 curUrl = url;
02290 }
02291
02292 if ( !curUrl.isEmpty() ) {
02293
02294
02295
02296 QString origFile = curUrl.fileName();
02297 QString file = origFile;
02298
02299 while ( renameNumbering.contains(file) ) {
02300 file = origFile;
02301 int num = renameNumbering[file] + 1;
02302 int dotIdx = file.findRev('.');
02303 file = file.insert( (dotIdx>=0) ? dotIdx : file.length(), QString("_") + QString::number(num) );
02304 }
02305 curUrl.setFileName(file);
02306
02307
02308 if ( !renameNumbering.contains(origFile))
02309 renameNumbering[origFile] = 1;
02310 else
02311 renameNumbering[origFile]++;
02312
02313 if ( file != origFile ) {
02314 if ( !renameNumbering.contains(file))
02315 renameNumbering[file] = 1;
02316 else
02317 renameNumbering[file]++;
02318 }
02319
02320
02321 if ( KIO::NetAccess::exists( curUrl, false, parentWidget() ) ) {
02322 if ( KMessageBox::warningContinueCancel( parentWidget(),
02323 i18n( "A file named %1 already exists. Do you want to overwrite it?" )
02324 .arg( curUrl.fileName() ),
02325 i18n( "File Already Exists" ), i18n("&Overwrite") ) == KMessageBox::Cancel) {
02326 continue;
02327 }
02328 }
02329
02330 const Result result = saveItem( it.key(), curUrl );
02331 if ( result != OK )
02332 globalResult = result;
02333 }
02334 }
02335 setResult( globalResult );
02336 emit completed( this );
02337 deleteLater();
02338 }
02339
02340 KMCommand::Result KMSaveAttachmentsCommand::saveItem( partNode *node,
02341 const KURL& url )
02342 {
02343 bool bSaveEncrypted = false;
02344 bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted;
02345 if( bEncryptedParts )
02346 if( KMessageBox::questionYesNo( parentWidget(),
02347 i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?" ).
02348 arg( url.fileName() ),
02349 i18n( "KMail Question" ), i18n("Keep Encryption"), i18n("Do Not Keep") ) ==
02350 KMessageBox::Yes )
02351 bSaveEncrypted = true;
02352
02353 bool bSaveWithSig = true;
02354 if( node->signatureState() != KMMsgNotSigned )
02355 if( KMessageBox::questionYesNo( parentWidget(),
02356 i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?" ).
02357 arg( url.fileName() ),
02358 i18n( "KMail Question" ), i18n("Keep Signature"), i18n("Do Not Keep") ) !=
02359 KMessageBox::Yes )
02360 bSaveWithSig = false;
02361
02362 QByteArray data;
02363 if ( mEncoded )
02364 {
02365
02366
02367 QCString cstr( node->msgPart().body() );
02368 data = cstr;
02369 data.resize(data.size() - 1);
02370 }
02371 else
02372 {
02373 if( bSaveEncrypted || !bEncryptedParts) {
02374 partNode *dataNode = node;
02375 QCString rawReplyString;
02376 bool gotRawReplyString = false;
02377 if( !bSaveWithSig ) {
02378 if( DwMime::kTypeMultipart == node->type() &&
02379 DwMime::kSubtypeSigned == node->subType() ){
02380
02381 if( node->findType( DwMime::kTypeApplication,
02382 DwMime::kSubtypePgpSignature,
02383 TRUE, false ) ){
02384 dataNode = node->findTypeNot( DwMime::kTypeApplication,
02385 DwMime::kSubtypePgpSignature,
02386 TRUE, false );
02387 }else if( node->findType( DwMime::kTypeApplication,
02388 DwMime::kSubtypePkcs7Mime,
02389 TRUE, false ) ){
02390 dataNode = node->findTypeNot( DwMime::kTypeApplication,
02391 DwMime::kSubtypePkcs7Mime,
02392 TRUE, false );
02393 }else{
02394 dataNode = node->findTypeNot( DwMime::kTypeMultipart,
02395 DwMime::kSubtypeUnknown,
02396 TRUE, false );
02397 }
02398 }else{
02399 ObjectTreeParser otp( 0, 0, false, false, false );
02400
02401
02402 dataNode->setProcessed( false, true );
02403 otp.parseObjectTree( dataNode );
02404
02405 rawReplyString = otp.rawReplyString();
02406 gotRawReplyString = true;
02407 }
02408 }
02409 QByteArray cstr = gotRawReplyString
02410 ? rawReplyString
02411 : dataNode->msgPart().bodyDecodedBinary();
02412 data = cstr;
02413 size_t size = cstr.size();
02414 if ( dataNode->msgPart().type() == DwMime::kTypeText ) {
02415
02416 size = KMail::Util::crlf2lf( cstr.data(), size );
02417 }
02418 data.resize( size );
02419 }
02420 }
02421 QDataStream ds;
02422 QFile file;
02423 KTempFile tf;
02424 tf.setAutoDelete( true );
02425 if ( url.isLocalFile() )
02426 {
02427
02428 file.setName( url.path() );
02429 if ( !file.open( IO_WriteOnly ) )
02430 {
02431 KMessageBox::error( parentWidget(),
02432 i18n( "%2 is detailed error description",
02433 "Could not write the file %1:\n%2" )
02434 .arg( file.name() )
02435 .arg( QString::fromLocal8Bit( strerror( errno ) ) ),
02436 i18n( "KMail Error" ) );
02437 return Failed;
02438 }
02439 fchmod( file.handle(), S_IRUSR | S_IWUSR );
02440 ds.setDevice( &file );
02441 } else
02442 {
02443
02444 ds.setDevice( tf.file() );
02445 }
02446
02447 ds.writeRawBytes( data.data(), data.size() );
02448 if ( !url.isLocalFile() )
02449 {
02450 tf.close();
02451 if ( !KIO::NetAccess::upload( tf.name(), url, parentWidget() ) )
02452 {
02453 KMessageBox::error( parentWidget(),
02454 i18n( "Could not write the file %1." )
02455 .arg( url.path() ),
02456 i18n( "KMail Error" ) );
02457 return Failed;
02458 }
02459 } else
02460 file.close();
02461 return OK;
02462 }
02463
02464 KMLoadPartsCommand::KMLoadPartsCommand( QPtrList<partNode>& parts, KMMessage *msg )
02465 : mNeedsRetrieval( 0 )
02466 {
02467 for ( QPtrListIterator<partNode> it( parts ); it.current(); ++it ) {
02468 mPartMap.insert( it.current(), msg );
02469 }
02470 }
02471
02472 KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
02473 : mNeedsRetrieval( 0 )
02474 {
02475 mPartMap.insert( node, msg );
02476 }
02477
02478 KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
02479 : mNeedsRetrieval( 0 ), mPartMap( partMap )
02480 {
02481 }
02482
02483 void KMLoadPartsCommand::slotStart()
02484 {
02485 for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
02486 it != mPartMap.end();
02487 ++it ) {
02488 if ( !it.key()->msgPart().isComplete() &&
02489 !it.key()->msgPart().partSpecifier().isEmpty() ) {
02490
02491 ++mNeedsRetrieval;
02492 KMFolder* curFolder = it.data()->parent();
02493 if ( curFolder ) {
02494 FolderJob *job =
02495 curFolder->createJob( it.data(), FolderJob::tGetMessage,
02496 0, it.key()->msgPart().partSpecifier() );
02497 job->setCancellable( false );
02498 connect( job, SIGNAL(messageUpdated(KMMessage*, QString)),
02499 this, SLOT(slotPartRetrieved(KMMessage*, QString)) );
02500 job->start();
02501 } else
02502 kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl;
02503 }
02504 }
02505 if ( mNeedsRetrieval == 0 )
02506 execute();
02507 }
02508
02509 void KMLoadPartsCommand::slotPartRetrieved( KMMessage *msg,
02510 QString partSpecifier )
02511 {
02512 DwBodyPart *part =
02513 msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier );
02514 if ( part ) {
02515
02516 for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
02517 it != mPartMap.end();
02518 ++it ) {
02519 if ( it.key()->dwPart()->partId() == part->partId() )
02520 it.key()->setDwPart( part );
02521 }
02522 } else
02523 kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl;
02524 --mNeedsRetrieval;
02525 if ( mNeedsRetrieval == 0 )
02526 execute();
02527 }
02528
02529 KMCommand::Result KMLoadPartsCommand::execute()
02530 {
02531 emit partsRetrieved();
02532 setResult( OK );
02533 emit completed( this );
02534 deleteLater();
02535 return OK;
02536 }
02537
02538 KMResendMessageCommand::KMResendMessageCommand( QWidget *parent,
02539 KMMessage *msg )
02540 :KMCommand( parent, msg )
02541 {
02542 }
02543
02544 KMCommand::Result KMResendMessageCommand::execute()
02545 {
02546 KMMessage *msg = retrievedMessage();
02547
02548 KMMessage *newMsg = new KMMessage(*msg);
02549 newMsg->setCharset(msg->codec()->mimeName());
02550
02551 newMsg->removeHeaderField( "Message-Id" );
02552 newMsg->setParent( 0 );
02553
02554
02555 newMsg->removeHeaderField( "Date" );
02556
02557 KMail::Composer * win = KMail::makeComposer();
02558 win->setMsg(newMsg, false, true);
02559 win->show();
02560
02561 return OK;
02562 }
02563
02564 KMMailingListCommand::KMMailingListCommand( QWidget *parent, KMFolder *folder )
02565 : KMCommand( parent ), mFolder( folder )
02566 {
02567 }
02568
02569 KMCommand::Result KMMailingListCommand::execute()
02570 {
02571 KURL::List lst = urls();
02572 QString handler = ( mFolder->mailingList().handler() == MailingList::KMail )
02573 ? "mailto" : "https";
02574
02575 KMCommand *command = 0;
02576 for ( KURL::List::Iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
02577 if ( handler == (*itr).protocol() ) {
02578 command = new KMUrlClickedCommand( *itr, mFolder->identity(), 0, false );
02579 }
02580 }
02581 if ( !command && !lst.empty() ) {
02582 command =
02583 new KMUrlClickedCommand( lst.first(), mFolder->identity(), 0, false );
02584 }
02585 if ( command ) {
02586 connect( command, SIGNAL( completed( KMCommand * ) ),
02587 this, SLOT( commandCompleted( KMCommand * ) ) );
02588 setDeletesItself( true );
02589 setEmitsCompletedItself( true );
02590 command->start();
02591 return OK;
02592 }
02593 return Failed;
02594 }
02595
02596 void KMMailingListCommand::commandCompleted( KMCommand *command )
02597 {
02598 setResult( command->result() );
02599 emit completed( this );
02600 deleteLater();
02601 }
02602
02603 KMMailingListPostCommand::KMMailingListPostCommand( QWidget *parent, KMFolder *folder )
02604 : KMMailingListCommand( parent, folder )
02605 {
02606 }
02607 KURL::List KMMailingListPostCommand::urls() const
02608 {
02609 return mFolder->mailingList().postURLS();
02610 }
02611
02612 KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( QWidget *parent, KMFolder *folder )
02613 : KMMailingListCommand( parent, folder )
02614 {
02615 }
02616 KURL::List KMMailingListSubscribeCommand::urls() const
02617 {
02618 return mFolder->mailingList().subscribeURLS();
02619 }
02620
02621 KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( QWidget *parent, KMFolder *folder )
02622 : KMMailingListCommand( parent, folder )
02623 {
02624 }
02625 KURL::List KMMailingListUnsubscribeCommand::urls() const
02626 {
02627 return mFolder->mailingList().unsubscribeURLS();
02628 }
02629
02630 KMMailingListArchivesCommand::KMMailingListArchivesCommand( QWidget *parent, KMFolder *folder )
02631 : KMMailingListCommand( parent, folder )
02632 {
02633 }
02634 KURL::List KMMailingListArchivesCommand::urls() const
02635 {
02636 return mFolder->mailingList().archiveURLS();
02637 }
02638
02639 KMMailingListHelpCommand::KMMailingListHelpCommand( QWidget *parent, KMFolder *folder )
02640 : KMMailingListCommand( parent, folder )
02641 {
02642 }
02643 KURL::List KMMailingListHelpCommand::urls() const
02644 {
02645 return mFolder->mailingList().helpURLS();
02646 }
02647
02648 KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
02649 :mUrl( url ), mMessage( msg )
02650 {
02651 }
02652
02653 KMCommand::Result KMIMChatCommand::execute()
02654 {
02655 kdDebug( 5006 ) << k_funcinfo << " URL is: " << mUrl << endl;
02656 QString addr = KMMessage::decodeMailtoUrl( mUrl.path() );
02657
02658 KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
02659 KABC::AddresseeList addressees = addressBook->findByEmail( KPIM::getEmailAddress( addr ) ) ;
02660
02661
02662 if( addressees.count() == 1 ) {
02663 kmkernel->imProxy()->chatWithContact( addressees[0].uid() );
02664 return OK;
02665 }
02666 else
02667 {
02668 kdDebug( 5006 ) << "Didn't find exactly one addressee, couldn't tell who to chat to for that email address. Count = " << addressees.count() << endl;
02669
02670 QString apology;
02671 if ( addressees.isEmpty() )
02672 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." );
02673 else
02674 {
02675 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." );
02676 QStringList nameList;
02677 KABC::AddresseeList::const_iterator it = addressees.begin();
02678 KABC::AddresseeList::const_iterator end = addressees.end();
02679 for ( ; it != end; ++it )
02680 {
02681 nameList.append( (*it).realName() );
02682 }
02683 QString names = nameList.join( QString::fromLatin1( ",\n" ) );
02684 apology = apology.arg( names );
02685 }
02686
02687 KMessageBox::sorry( parentWidget(), apology );
02688 return Failed;
02689 }
02690 }
02691
02692 KMHandleAttachmentCommand::KMHandleAttachmentCommand( partNode* node,
02693 KMMessage* msg, int atmId, const QString& atmName,
02694 AttachmentAction action, KService::Ptr offer, QWidget* parent )
02695 : KMCommand( parent ), mNode( node ), mMsg( msg ), mAtmId( atmId ), mAtmName( atmName ),
02696 mAction( action ), mOffer( offer ), mJob( 0 )
02697 {
02698 }
02699
02700 void KMHandleAttachmentCommand::slotStart()
02701 {
02702 if ( !mNode->msgPart().isComplete() )
02703 {
02704
02705 kdDebug(5006) << "load part" << endl;
02706 KMLoadPartsCommand *command = new KMLoadPartsCommand( mNode, mMsg );
02707 connect( command, SIGNAL( partsRetrieved() ),
02708 this, SLOT( slotPartComplete() ) );
02709 command->start();
02710 } else
02711 {
02712 execute();
02713 }
02714 }
02715
02716 void KMHandleAttachmentCommand::slotPartComplete()
02717 {
02718 execute();
02719 }
02720
02721 KMCommand::Result KMHandleAttachmentCommand::execute()
02722 {
02723 switch( mAction )
02724 {
02725 case Open:
02726 atmOpen();
02727 break;
02728 case OpenWith:
02729 atmOpenWith();
02730 break;
02731 case View:
02732 atmView();
02733 break;
02734 case Save:
02735 atmSave();
02736 break;
02737 case Properties:
02738 atmProperties();
02739 break;
02740 case ChiasmusEncrypt:
02741 atmEncryptWithChiasmus();
02742 return Undefined;
02743 break;
02744 default:
02745 kdDebug(5006) << "unknown action " << mAction << endl;
02746 break;
02747 }
02748 setResult( OK );
02749 emit completed( this );
02750 deleteLater();
02751 return OK;
02752 }
02753
02754 QString KMHandleAttachmentCommand::createAtmFileLink() const
02755 {
02756 QFileInfo atmFileInfo( mAtmName );
02757
02758 if ( atmFileInfo.size() == 0 )
02759 {
02760 kdDebug(5006) << k_funcinfo << "rewriting attachment" << endl;
02761
02762 QByteArray data = mNode->msgPart().bodyDecodedBinary();
02763 size_t size = data.size();
02764 if ( mNode->msgPart().type() == DwMime::kTypeText && size) {
02765
02766 size = KMail::Util::crlf2lf( data.data(), size );
02767 }
02768 KPIM::kBytesToFile( data.data(), size, mAtmName, false, false, false );
02769 }
02770
02771 KTempFile *linkFile = new KTempFile( locateLocal("tmp", atmFileInfo.fileName() +"_["),
02772 "]."+ atmFileInfo.extension() );
02773
02774 linkFile->setAutoDelete(true);
02775 QString linkName = linkFile->name();
02776 delete linkFile;
02777
02778 if ( ::link(QFile::encodeName( mAtmName ), QFile::encodeName( linkName )) == 0 ) {
02779 return linkName;
02780 }
02781 return QString::null;
02782 }
02783
02784 KService::Ptr KMHandleAttachmentCommand::getServiceOffer()
02785 {
02786 KMMessagePart& msgPart = mNode->msgPart();
02787 const QString contentTypeStr =
02788 ( msgPart.typeStr() + '/' + msgPart.subtypeStr() ).lower();
02789
02790 if ( contentTypeStr == "text/x-vcard" ) {
02791 atmView();
02792 return 0;
02793 }
02794
02795 KMimeType::Ptr mimetype;
02796
02797 mimetype = KMimeType::mimeType( contentTypeStr );
02798 if ( mimetype->name() == "application/octet-stream" ) {
02799
02800 mimetype = KMimeType::findByPath( mAtmName, 0, true );
02801 }
02802 if ( ( mimetype->name() == "application/octet-stream" )
02803 && msgPart.isComplete() ) {
02804
02805
02806 mimetype = KMimeType::findByFileContent( mAtmName );
02807 }
02808 return KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
02809 }
02810
02811 void KMHandleAttachmentCommand::atmOpen()
02812 {
02813 if ( !mOffer )
02814 mOffer = getServiceOffer();
02815 if ( !mOffer ) {
02816 kdDebug(5006) << k_funcinfo << "got no offer" << endl;
02817 return;
02818 }
02819
02820 KURL::List lst;
02821 KURL url;
02822 bool autoDelete = true;
02823 QString fname = createAtmFileLink();
02824
02825 if ( fname.isNull() ) {
02826 autoDelete = false;
02827 fname = mAtmName;
02828 }
02829
02830 url.setPath( fname );
02831 lst.append( url );
02832 if ( (KRun::run( *mOffer, lst, autoDelete ) <= 0) && autoDelete ) {
02833 QFile::remove(url.path());
02834 }
02835 }
02836
02837 void KMHandleAttachmentCommand::atmOpenWith()
02838 {
02839 KURL::List lst;
02840 KURL url;
02841 bool autoDelete = true;
02842 QString fname = createAtmFileLink();
02843
02844 if ( fname.isNull() ) {
02845 autoDelete = false;
02846 fname = mAtmName;
02847 }
02848
02849 url.setPath( fname );
02850 lst.append( url );
02851 if ( (! KRun::displayOpenWithDialog(lst, autoDelete)) && autoDelete ) {
02852 QFile::remove( url.path() );
02853 }
02854 }
02855
02856 void KMHandleAttachmentCommand::atmView()
02857 {
02858
02859 emit showAttachment( mAtmId, mAtmName );
02860 }
02861
02862 void KMHandleAttachmentCommand::atmSave()
02863 {
02864 QPtrList<partNode> parts;
02865 parts.append( mNode );
02866
02867 KMSaveAttachmentsCommand *command =
02868 new KMSaveAttachmentsCommand( 0, parts, mMsg, false );
02869 command->start();
02870 }
02871
02872 void KMHandleAttachmentCommand::atmProperties()
02873 {
02874 KMMsgPartDialogCompat dlg( 0, true );
02875 KMMessagePart& msgPart = mNode->msgPart();
02876 dlg.setMsgPart( &msgPart );
02877 dlg.exec();
02878 }
02879
02880 void KMHandleAttachmentCommand::atmEncryptWithChiasmus()
02881 {
02882 const partNode * node = mNode;
02883 Q_ASSERT( node );
02884 if ( !node )
02885 return;
02886
02887
02888 if ( !mAtmName.endsWith( ".xia", false ) )
02889 return;
02890
02891 const Kleo::CryptoBackend::Protocol * chiasmus =
02892 Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
02893 Q_ASSERT( chiasmus );
02894 if ( !chiasmus )
02895 return;
02896
02897 const STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> listjob( chiasmus->specialJob( "x-obtain-keys", QMap<QString,QVariant>() ) );
02898 if ( !listjob.get() ) {
02899 const QString msg = i18n( "Chiasmus backend does not offer the "
02900 "\"x-obtain-keys\" function. Please report this bug." );
02901 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02902 return;
02903 }
02904
02905 if ( listjob->exec() ) {
02906 listjob->showErrorDialog( parentWidget(), i18n( "Chiasmus Backend Error" ) );
02907 return;
02908 }
02909
02910 const QVariant result = listjob->property( "result" );
02911 if ( result.type() != QVariant::StringList ) {
02912 const QString msg = i18n( "Unexpected return value from Chiasmus backend: "
02913 "The \"x-obtain-keys\" function did not return a "
02914 "string list. Please report this bug." );
02915 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02916 return;
02917 }
02918
02919 const QStringList keys = result.toStringList();
02920 if ( keys.empty() ) {
02921 const QString msg = i18n( "No keys have been found. Please check that a "
02922 "valid key path has been set in the Chiasmus "
02923 "configuration." );
02924 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02925 return;
02926 }
02927
02928 ChiasmusKeySelector selectorDlg( parentWidget(), i18n( "Chiasmus Decryption Key Selection" ),
02929 keys, GlobalSettings::chiasmusDecryptionKey(),
02930 GlobalSettings::chiasmusDecryptionOptions() );
02931 if ( selectorDlg.exec() != QDialog::Accepted )
02932 return;
02933
02934 GlobalSettings::setChiasmusDecryptionOptions( selectorDlg.options() );
02935 GlobalSettings::setChiasmusDecryptionKey( selectorDlg.key() );
02936 assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() );
02937
02938 Kleo::SpecialJob * job = chiasmus->specialJob( "x-decrypt", QMap<QString,QVariant>() );
02939 if ( !job ) {
02940 const QString msg = i18n( "Chiasmus backend does not offer the "
02941 "\"x-decrypt\" function. Please report this bug." );
02942 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02943 return;
02944 }
02945
02946 const QByteArray input = node->msgPart().bodyDecodedBinary();
02947
02948 if ( !job->setProperty( "key", GlobalSettings::chiasmusDecryptionKey() ) ||
02949 !job->setProperty( "options", GlobalSettings::chiasmusDecryptionOptions() ) ||
02950 !job->setProperty( "input", input ) ) {
02951 const QString msg = i18n( "The \"x-decrypt\" function does not accept "
02952 "the expected parameters. Please report this bug." );
02953 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02954 return;
02955 }
02956
02957 setDeletesItself( true );
02958 if ( job->start() ) {
02959 job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
02960 return;
02961 }
02962
02963 mJob = job;
02964 connect( job, SIGNAL(result(const GpgME::Error&,const QVariant&)),
02965 this, SLOT(slotAtmDecryptWithChiasmusResult(const GpgME::Error&,const QVariant&)) );
02966 }
02967
02968
02969 static bool checkOverwrite( const KURL& url, bool& overwrite, QWidget* w )
02970 {
02971 if ( KIO::NetAccess::exists( url, false , w ) ) {
02972 if ( KMessageBox::Cancel ==
02973 KMessageBox::warningContinueCancel(
02974 w,
02975 i18n( "A file named \"%1\" already exists. "
02976 "Are you sure you want to overwrite it?" ).arg( url.prettyURL() ),
02977 i18n( "Overwrite File?" ),
02978 i18n( "&Overwrite" ) ) )
02979 return false;
02980 overwrite = true;
02981 }
02982 return true;
02983 }
02984
02985 static const QString chomp( const QString & base, const QString & suffix, bool cs ) {
02986 return base.endsWith( suffix, cs ) ? base.left( base.length() - suffix.length() ) : base ;
02987 }
02988
02989 void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusResult( const GpgME::Error & err, const QVariant & result )
02990 {
02991 LaterDeleterWithCommandCompletion d( this );
02992 if ( !mJob )
02993 return;
02994 Q_ASSERT( mJob == sender() );
02995 if ( mJob != sender() )
02996 return;
02997 Kleo::Job * job = mJob;
02998 mJob = 0;
02999 if ( err.isCanceled() )
03000 return;
03001 if ( err ) {
03002 job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
03003 return;
03004 }
03005
03006 if ( result.type() != QVariant::ByteArray ) {
03007 const QString msg = i18n( "Unexpected return value from Chiasmus backend: "
03008 "The \"x-decrypt\" function did not return a "
03009 "byte array. Please report this bug." );
03010 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
03011 return;
03012 }
03013
03014 const KURL url = KFileDialog::getSaveURL( chomp( mAtmName, ".xia", false ), QString::null, parentWidget() );
03015 if ( url.isEmpty() )
03016 return;
03017
03018 bool overwrite = false;
03019 if ( !checkOverwrite( url, overwrite, parentWidget() ) )
03020 return;
03021
03022 d.setDisabled( true );
03023 KIO::Job * uploadJob = KIO::storedPut( result.toByteArray(), url, -1, overwrite, false );
03024 uploadJob->setWindow( parentWidget() );
03025 connect( uploadJob, SIGNAL(result(KIO::Job*)),
03026 this, SLOT(slotAtmDecryptWithChiasmusUploadResult(KIO::Job*)) );
03027 }
03028
03029 void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusUploadResult( KIO::Job * job )
03030 {
03031 if ( job->error() )
03032 job->showErrorDialog();
03033 LaterDeleterWithCommandCompletion d( this );
03034 d.setResult( OK );
03035 }
03036
03037 #include "kmcommands.moc"