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