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