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 (void) new KRun( mUrl );
02149 }
02150 else
02151 return Failed;
02152
02153 return OK;
02154 }
02155
02156 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, KMMessage *msg )
02157 : KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
02158 {
02159 }
02160
02161 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, const QPtrList<KMMsgBase>& msgs )
02162 : KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
02163 {
02164 }
02165
02166 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, QPtrList<partNode>& attachments,
02167 KMMessage *msg, bool encoded )
02168 : KMCommand( parent ), mImplicitAttachments( false ), mEncoded( encoded )
02169 {
02170 for ( QPtrListIterator<partNode> it( attachments ); it.current(); ++it ) {
02171 mAttachmentMap.insert( it.current(), msg );
02172 }
02173 }
02174
02175 KMCommand::Result KMSaveAttachmentsCommand::execute()
02176 {
02177 setEmitsCompletedItself( true );
02178 if ( mImplicitAttachments ) {
02179 QPtrList<KMMessage> msgList = retrievedMsgs();
02180 KMMessage *msg;
02181 for ( QPtrListIterator<KMMessage> itr( msgList );
02182 ( msg = itr.current() );
02183 ++itr ) {
02184 partNode *rootNode = partNode::fromMessage( msg );
02185 for ( partNode *child = rootNode; child;
02186 child = child->firstChild() ) {
02187 for ( partNode *node = child; node; node = node->nextSibling() ) {
02188 if ( node->type() != DwMime::kTypeMultipart )
02189 mAttachmentMap.insert( node, msg );
02190 }
02191 }
02192 }
02193 }
02194 setDeletesItself( true );
02195
02196 KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachmentMap );
02197 connect( command, SIGNAL( partsRetrieved() ),
02198 this, SLOT( slotSaveAll() ) );
02199 command->start();
02200
02201 return OK;
02202 }
02203
02204 void KMSaveAttachmentsCommand::slotSaveAll()
02205 {
02206
02207
02208
02209 if ( mImplicitAttachments ) {
02210 for ( PartNodeMessageMap::iterator it = mAttachmentMap.begin();
02211 it != mAttachmentMap.end(); ) {
02212
02213
02214
02215 if ( it.key()->msgPart().fileName().stripWhiteSpace().isEmpty() &&
02216 ( it.key()->msgPart().name().stripWhiteSpace().isEmpty() ||
02217 !it.key()->parentNode() ) ) {
02218 PartNodeMessageMap::iterator delIt = it;
02219 ++it;
02220 mAttachmentMap.remove( delIt );
02221 }
02222 else
02223 ++it;
02224 }
02225 if ( mAttachmentMap.isEmpty() ) {
02226 KMessageBox::information( 0, i18n("Found no attachments to save.") );
02227 setResult( OK );
02228 emit completed( this );
02229 deleteLater();
02230 return;
02231 }
02232 }
02233
02234 KURL url, dirUrl;
02235 if ( mAttachmentMap.count() > 1 ) {
02236
02237 dirUrl = KDirSelectDialog::selectDirectory( QString::null, false,
02238 parentWidget(),
02239 i18n("Save Attachments To") );
02240 if ( !dirUrl.isValid() ) {
02241 setResult( Canceled );
02242 emit completed( this );
02243 deleteLater();
02244 return;
02245 }
02246
02247
02248 dirUrl.adjustPath( 1 );
02249 }
02250 else {
02251
02252 partNode *node = mAttachmentMap.begin().key();
02253
02254 QString s =
02255 node->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
02256 if ( s.isEmpty() )
02257 s = node->msgPart().name().stripWhiteSpace().replace( ':', '_' );
02258 if ( s.isEmpty() )
02259 s = i18n("filename for an unnamed attachment", "attachment.1");
02260 url = KFileDialog::getSaveURL( s, QString::null, parentWidget(),
02261 QString::null );
02262 if ( url.isEmpty() ) {
02263 setResult( Canceled );
02264 emit completed( this );
02265 deleteLater();
02266 return;
02267 }
02268 }
02269
02270 QMap< QString, int > renameNumbering;
02271
02272 Result globalResult = OK;
02273 int unnamedAtmCount = 0;
02274 for ( PartNodeMessageMap::const_iterator it = mAttachmentMap.begin();
02275 it != mAttachmentMap.end();
02276 ++it ) {
02277 KURL curUrl;
02278 if ( !dirUrl.isEmpty() ) {
02279 curUrl = dirUrl;
02280 QString s =
02281 it.key()->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
02282 if ( s.isEmpty() )
02283 s = it.key()->msgPart().name().stripWhiteSpace().replace( ':', '_' );
02284 if ( s.isEmpty() ) {
02285 ++unnamedAtmCount;
02286 s = i18n("filename for the %1-th unnamed attachment",
02287 "attachment.%1")
02288 .arg( unnamedAtmCount );
02289 }
02290 curUrl.setFileName( s );
02291 } else {
02292 curUrl = url;
02293 }
02294
02295 if ( !curUrl.isEmpty() ) {
02296
02297
02298
02299 QString origFile = curUrl.fileName();
02300 QString file = origFile;
02301
02302 while ( renameNumbering.contains(file) ) {
02303 file = origFile;
02304 int num = renameNumbering[file] + 1;
02305 int dotIdx = file.findRev('.');
02306 file = file.insert( (dotIdx>=0) ? dotIdx : file.length(), QString("_") + QString::number(num) );
02307 }
02308 curUrl.setFileName(file);
02309
02310
02311 if ( !renameNumbering.contains(origFile))
02312 renameNumbering[origFile] = 1;
02313 else
02314 renameNumbering[origFile]++;
02315
02316 if ( file != origFile ) {
02317 if ( !renameNumbering.contains(file))
02318 renameNumbering[file] = 1;
02319 else
02320 renameNumbering[file]++;
02321 }
02322
02323
02324 if ( KIO::NetAccess::exists( curUrl, false, parentWidget() ) ) {
02325 if ( KMessageBox::warningContinueCancel( parentWidget(),
02326 i18n( "A file named %1 already exists. Do you want to overwrite it?" )
02327 .arg( curUrl.fileName() ),
02328 i18n( "File Already Exists" ), i18n("&Overwrite") ) == KMessageBox::Cancel) {
02329 continue;
02330 }
02331 }
02332
02333 const Result result = saveItem( it.key(), curUrl );
02334 if ( result != OK )
02335 globalResult = result;
02336 }
02337 }
02338 setResult( globalResult );
02339 emit completed( this );
02340 deleteLater();
02341 }
02342
02343 KMCommand::Result KMSaveAttachmentsCommand::saveItem( partNode *node,
02344 const KURL& url )
02345 {
02346 bool bSaveEncrypted = false;
02347 bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted;
02348 if( bEncryptedParts )
02349 if( KMessageBox::questionYesNo( parentWidget(),
02350 i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?" ).
02351 arg( url.fileName() ),
02352 i18n( "KMail Question" ), i18n("Keep Encryption"), i18n("Do Not Keep") ) ==
02353 KMessageBox::Yes )
02354 bSaveEncrypted = true;
02355
02356 bool bSaveWithSig = true;
02357 if( node->signatureState() != KMMsgNotSigned )
02358 if( KMessageBox::questionYesNo( parentWidget(),
02359 i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?" ).
02360 arg( url.fileName() ),
02361 i18n( "KMail Question" ), i18n("Keep Signature"), i18n("Do Not Keep") ) !=
02362 KMessageBox::Yes )
02363 bSaveWithSig = false;
02364
02365 QByteArray data;
02366 if ( mEncoded )
02367 {
02368
02369
02370 QCString cstr( node->msgPart().body() );
02371 data = cstr;
02372 data.resize(data.size() - 1);
02373 }
02374 else
02375 {
02376 if( bSaveEncrypted || !bEncryptedParts) {
02377 partNode *dataNode = node;
02378 QCString rawReplyString;
02379 bool gotRawReplyString = false;
02380 if( !bSaveWithSig ) {
02381 if( DwMime::kTypeMultipart == node->type() &&
02382 DwMime::kSubtypeSigned == node->subType() ){
02383
02384 if( node->findType( DwMime::kTypeApplication,
02385 DwMime::kSubtypePgpSignature,
02386 TRUE, false ) ){
02387 dataNode = node->findTypeNot( DwMime::kTypeApplication,
02388 DwMime::kSubtypePgpSignature,
02389 TRUE, false );
02390 }else if( node->findType( DwMime::kTypeApplication,
02391 DwMime::kSubtypePkcs7Mime,
02392 TRUE, false ) ){
02393 dataNode = node->findTypeNot( DwMime::kTypeApplication,
02394 DwMime::kSubtypePkcs7Mime,
02395 TRUE, false );
02396 }else{
02397 dataNode = node->findTypeNot( DwMime::kTypeMultipart,
02398 DwMime::kSubtypeUnknown,
02399 TRUE, false );
02400 }
02401 }else{
02402 ObjectTreeParser otp( 0, 0, false, false, false );
02403
02404
02405 dataNode->setProcessed( false, true );
02406 otp.parseObjectTree( dataNode );
02407
02408 rawReplyString = otp.rawReplyString();
02409 gotRawReplyString = true;
02410 }
02411 }
02412 QByteArray cstr = gotRawReplyString
02413 ? rawReplyString
02414 : dataNode->msgPart().bodyDecodedBinary();
02415 data = cstr;
02416 size_t size = cstr.size();
02417 if ( dataNode->msgPart().type() == DwMime::kTypeText ) {
02418
02419 size = KMail::Util::crlf2lf( cstr.data(), size );
02420 }
02421 data.resize( size );
02422 }
02423 }
02424 QDataStream ds;
02425 QFile file;
02426 KTempFile tf;
02427 tf.setAutoDelete( true );
02428 if ( url.isLocalFile() )
02429 {
02430
02431 file.setName( url.path() );
02432 if ( !file.open( IO_WriteOnly ) )
02433 {
02434 KMessageBox::error( parentWidget(),
02435 i18n( "%2 is detailed error description",
02436 "Could not write the file %1:\n%2" )
02437 .arg( file.name() )
02438 .arg( QString::fromLocal8Bit( strerror( errno ) ) ),
02439 i18n( "KMail Error" ) );
02440 return Failed;
02441 }
02442 fchmod( file.handle(), S_IRUSR | S_IWUSR );
02443 ds.setDevice( &file );
02444 } else
02445 {
02446
02447 ds.setDevice( tf.file() );
02448 }
02449
02450 ds.writeRawBytes( data.data(), data.size() );
02451 if ( !url.isLocalFile() )
02452 {
02453 tf.close();
02454 if ( !KIO::NetAccess::upload( tf.name(), url, parentWidget() ) )
02455 {
02456 KMessageBox::error( parentWidget(),
02457 i18n( "Could not write the file %1." )
02458 .arg( url.path() ),
02459 i18n( "KMail Error" ) );
02460 return Failed;
02461 }
02462 } else
02463 file.close();
02464 return OK;
02465 }
02466
02467 KMLoadPartsCommand::KMLoadPartsCommand( QPtrList<partNode>& parts, KMMessage *msg )
02468 : mNeedsRetrieval( 0 )
02469 {
02470 for ( QPtrListIterator<partNode> it( parts ); it.current(); ++it ) {
02471 mPartMap.insert( it.current(), msg );
02472 }
02473 }
02474
02475 KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
02476 : mNeedsRetrieval( 0 )
02477 {
02478 mPartMap.insert( node, msg );
02479 }
02480
02481 KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
02482 : mNeedsRetrieval( 0 ), mPartMap( partMap )
02483 {
02484 }
02485
02486 void KMLoadPartsCommand::slotStart()
02487 {
02488 for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
02489 it != mPartMap.end();
02490 ++it ) {
02491 if ( !it.key()->msgPart().isComplete() &&
02492 !it.key()->msgPart().partSpecifier().isEmpty() ) {
02493
02494 ++mNeedsRetrieval;
02495 KMFolder* curFolder = it.data()->parent();
02496 if ( curFolder ) {
02497 FolderJob *job =
02498 curFolder->createJob( it.data(), FolderJob::tGetMessage,
02499 0, it.key()->msgPart().partSpecifier() );
02500 job->setCancellable( false );
02501 connect( job, SIGNAL(messageUpdated(KMMessage*, QString)),
02502 this, SLOT(slotPartRetrieved(KMMessage*, QString)) );
02503 job->start();
02504 } else
02505 kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl;
02506 }
02507 }
02508 if ( mNeedsRetrieval == 0 )
02509 execute();
02510 }
02511
02512 void KMLoadPartsCommand::slotPartRetrieved( KMMessage *msg,
02513 QString partSpecifier )
02514 {
02515 DwBodyPart *part =
02516 msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier );
02517 if ( part ) {
02518
02519 for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
02520 it != mPartMap.end();
02521 ++it ) {
02522 if ( it.key()->dwPart()->partId() == part->partId() )
02523 it.key()->setDwPart( part );
02524 }
02525 } else
02526 kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl;
02527 --mNeedsRetrieval;
02528 if ( mNeedsRetrieval == 0 )
02529 execute();
02530 }
02531
02532 KMCommand::Result KMLoadPartsCommand::execute()
02533 {
02534 emit partsRetrieved();
02535 setResult( OK );
02536 emit completed( this );
02537 deleteLater();
02538 return OK;
02539 }
02540
02541 KMResendMessageCommand::KMResendMessageCommand( QWidget *parent,
02542 KMMessage *msg )
02543 :KMCommand( parent, msg )
02544 {
02545 }
02546
02547 KMCommand::Result KMResendMessageCommand::execute()
02548 {
02549 KMMessage *msg = retrievedMessage();
02550
02551 KMMessage *newMsg = new KMMessage(*msg);
02552 newMsg->setCharset(msg->codec()->mimeName());
02553
02554 newMsg->removeHeaderField( "Message-Id" );
02555 newMsg->setParent( 0 );
02556
02557
02558 newMsg->removeHeaderField( "Date" );
02559
02560 KMail::Composer * win = KMail::makeComposer();
02561 win->setMsg(newMsg, false, true);
02562 win->show();
02563
02564 return OK;
02565 }
02566
02567 KMMailingListCommand::KMMailingListCommand( QWidget *parent, KMFolder *folder )
02568 : KMCommand( parent ), mFolder( folder )
02569 {
02570 }
02571
02572 KMCommand::Result KMMailingListCommand::execute()
02573 {
02574 KURL::List lst = urls();
02575 QString handler = ( mFolder->mailingList().handler() == MailingList::KMail )
02576 ? "mailto" : "https";
02577
02578 KMCommand *command = 0;
02579 for ( KURL::List::Iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
02580 if ( handler == (*itr).protocol() ) {
02581 command = new KMUrlClickedCommand( *itr, mFolder->identity(), 0, false );
02582 }
02583 }
02584 if ( !command && !lst.empty() ) {
02585 command =
02586 new KMUrlClickedCommand( lst.first(), mFolder->identity(), 0, false );
02587 }
02588 if ( command ) {
02589 connect( command, SIGNAL( completed( KMCommand * ) ),
02590 this, SLOT( commandCompleted( KMCommand * ) ) );
02591 setDeletesItself( true );
02592 setEmitsCompletedItself( true );
02593 command->start();
02594 return OK;
02595 }
02596 return Failed;
02597 }
02598
02599 void KMMailingListCommand::commandCompleted( KMCommand *command )
02600 {
02601 setResult( command->result() );
02602 emit completed( this );
02603 deleteLater();
02604 }
02605
02606 KMMailingListPostCommand::KMMailingListPostCommand( QWidget *parent, KMFolder *folder )
02607 : KMMailingListCommand( parent, folder )
02608 {
02609 }
02610 KURL::List KMMailingListPostCommand::urls() const
02611 {
02612 return mFolder->mailingList().postURLS();
02613 }
02614
02615 KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( QWidget *parent, KMFolder *folder )
02616 : KMMailingListCommand( parent, folder )
02617 {
02618 }
02619 KURL::List KMMailingListSubscribeCommand::urls() const
02620 {
02621 return mFolder->mailingList().subscribeURLS();
02622 }
02623
02624 KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( QWidget *parent, KMFolder *folder )
02625 : KMMailingListCommand( parent, folder )
02626 {
02627 }
02628 KURL::List KMMailingListUnsubscribeCommand::urls() const
02629 {
02630 return mFolder->mailingList().unsubscribeURLS();
02631 }
02632
02633 KMMailingListArchivesCommand::KMMailingListArchivesCommand( QWidget *parent, KMFolder *folder )
02634 : KMMailingListCommand( parent, folder )
02635 {
02636 }
02637 KURL::List KMMailingListArchivesCommand::urls() const
02638 {
02639 return mFolder->mailingList().archiveURLS();
02640 }
02641
02642 KMMailingListHelpCommand::KMMailingListHelpCommand( QWidget *parent, KMFolder *folder )
02643 : KMMailingListCommand( parent, folder )
02644 {
02645 }
02646 KURL::List KMMailingListHelpCommand::urls() const
02647 {
02648 return mFolder->mailingList().helpURLS();
02649 }
02650
02651 KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
02652 :mUrl( url ), mMessage( msg )
02653 {
02654 }
02655
02656 KMCommand::Result KMIMChatCommand::execute()
02657 {
02658 kdDebug( 5006 ) << k_funcinfo << " URL is: " << mUrl << endl;
02659 QString addr = KMMessage::decodeMailtoUrl( mUrl.path() );
02660
02661 KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
02662 KABC::AddresseeList addressees = addressBook->findByEmail( KPIM::getEmailAddress( addr ) ) ;
02663
02664
02665 if( addressees.count() == 1 ) {
02666 kmkernel->imProxy()->chatWithContact( addressees[0].uid() );
02667 return OK;
02668 }
02669 else
02670 {
02671 kdDebug( 5006 ) << "Didn't find exactly one addressee, couldn't tell who to chat to for that email address. Count = " << addressees.count() << endl;
02672
02673 QString apology;
02674 if ( addressees.isEmpty() )
02675 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." );
02676 else
02677 {
02678 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." );
02679 QStringList nameList;
02680 KABC::AddresseeList::const_iterator it = addressees.begin();
02681 KABC::AddresseeList::const_iterator end = addressees.end();
02682 for ( ; it != end; ++it )
02683 {
02684 nameList.append( (*it).realName() );
02685 }
02686 QString names = nameList.join( QString::fromLatin1( ",\n" ) );
02687 apology = apology.arg( names );
02688 }
02689
02690 KMessageBox::sorry( parentWidget(), apology );
02691 return Failed;
02692 }
02693 }
02694
02695 KMHandleAttachmentCommand::KMHandleAttachmentCommand( partNode* node,
02696 KMMessage* msg, int atmId, const QString& atmName,
02697 AttachmentAction action, KService::Ptr offer, QWidget* parent )
02698 : KMCommand( parent ), mNode( node ), mMsg( msg ), mAtmId( atmId ), mAtmName( atmName ),
02699 mAction( action ), mOffer( offer ), mJob( 0 )
02700 {
02701 }
02702
02703 void KMHandleAttachmentCommand::slotStart()
02704 {
02705 if ( !mNode->msgPart().isComplete() )
02706 {
02707
02708 kdDebug(5006) << "load part" << endl;
02709 KMLoadPartsCommand *command = new KMLoadPartsCommand( mNode, mMsg );
02710 connect( command, SIGNAL( partsRetrieved() ),
02711 this, SLOT( slotPartComplete() ) );
02712 command->start();
02713 } else
02714 {
02715 execute();
02716 }
02717 }
02718
02719 void KMHandleAttachmentCommand::slotPartComplete()
02720 {
02721 execute();
02722 }
02723
02724 KMCommand::Result KMHandleAttachmentCommand::execute()
02725 {
02726 switch( mAction )
02727 {
02728 case Open:
02729 atmOpen();
02730 break;
02731 case OpenWith:
02732 atmOpenWith();
02733 break;
02734 case View:
02735 atmView();
02736 break;
02737 case Save:
02738 atmSave();
02739 break;
02740 case Properties:
02741 atmProperties();
02742 break;
02743 case ChiasmusEncrypt:
02744 atmEncryptWithChiasmus();
02745 return Undefined;
02746 break;
02747 default:
02748 kdDebug(5006) << "unknown action " << mAction << endl;
02749 break;
02750 }
02751 setResult( OK );
02752 emit completed( this );
02753 deleteLater();
02754 return OK;
02755 }
02756
02757 QString KMHandleAttachmentCommand::createAtmFileLink() const
02758 {
02759 QFileInfo atmFileInfo( mAtmName );
02760
02761 if ( atmFileInfo.size() == 0 )
02762 {
02763 kdDebug(5006) << k_funcinfo << "rewriting attachment" << endl;
02764
02765 QByteArray data = mNode->msgPart().bodyDecodedBinary();
02766 size_t size = data.size();
02767 if ( mNode->msgPart().type() == DwMime::kTypeText && size) {
02768
02769 size = KMail::Util::crlf2lf( data.data(), size );
02770 }
02771 KPIM::kBytesToFile( data.data(), size, mAtmName, false, false, false );
02772 }
02773
02774 KTempFile *linkFile = new KTempFile( locateLocal("tmp", atmFileInfo.fileName() +"_["),
02775 "]."+ atmFileInfo.extension() );
02776
02777 linkFile->setAutoDelete(true);
02778 QString linkName = linkFile->name();
02779 delete linkFile;
02780
02781 if ( ::link(QFile::encodeName( mAtmName ), QFile::encodeName( linkName )) == 0 ) {
02782 return linkName;
02783 }
02784 return QString::null;
02785 }
02786
02787 KService::Ptr KMHandleAttachmentCommand::getServiceOffer()
02788 {
02789 KMMessagePart& msgPart = mNode->msgPart();
02790 const QString contentTypeStr =
02791 ( msgPart.typeStr() + '/' + msgPart.subtypeStr() ).lower();
02792
02793 if ( contentTypeStr == "text/x-vcard" ) {
02794 atmView();
02795 return 0;
02796 }
02797
02798 KMimeType::Ptr mimetype;
02799
02800 mimetype = KMimeType::mimeType( contentTypeStr );
02801 if ( mimetype->name() == "application/octet-stream" ) {
02802
02803 mimetype = KMimeType::findByPath( mAtmName, 0, true );
02804 }
02805 if ( ( mimetype->name() == "application/octet-stream" )
02806 && msgPart.isComplete() ) {
02807
02808
02809 mimetype = KMimeType::findByFileContent( mAtmName );
02810 }
02811 return KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
02812 }
02813
02814 void KMHandleAttachmentCommand::atmOpen()
02815 {
02816 if ( !mOffer )
02817 mOffer = getServiceOffer();
02818 if ( !mOffer ) {
02819 kdDebug(5006) << k_funcinfo << "got no offer" << endl;
02820 return;
02821 }
02822
02823 KURL::List lst;
02824 KURL url;
02825 bool autoDelete = true;
02826 QString fname = createAtmFileLink();
02827
02828 if ( fname.isNull() ) {
02829 autoDelete = false;
02830 fname = mAtmName;
02831 }
02832
02833 url.setPath( fname );
02834 lst.append( url );
02835 if ( (KRun::run( *mOffer, lst, autoDelete ) <= 0) && autoDelete ) {
02836 QFile::remove(url.path());
02837 }
02838 }
02839
02840 void KMHandleAttachmentCommand::atmOpenWith()
02841 {
02842 KURL::List lst;
02843 KURL url;
02844 bool autoDelete = true;
02845 QString fname = createAtmFileLink();
02846
02847 if ( fname.isNull() ) {
02848 autoDelete = false;
02849 fname = mAtmName;
02850 }
02851
02852 url.setPath( fname );
02853 lst.append( url );
02854 if ( (! KRun::displayOpenWithDialog(lst, autoDelete)) && autoDelete ) {
02855 QFile::remove( url.path() );
02856 }
02857 }
02858
02859 void KMHandleAttachmentCommand::atmView()
02860 {
02861
02862 emit showAttachment( mAtmId, mAtmName );
02863 }
02864
02865 void KMHandleAttachmentCommand::atmSave()
02866 {
02867 QPtrList<partNode> parts;
02868 parts.append( mNode );
02869
02870 KMSaveAttachmentsCommand *command =
02871 new KMSaveAttachmentsCommand( 0, parts, mMsg, false );
02872 command->start();
02873 }
02874
02875 void KMHandleAttachmentCommand::atmProperties()
02876 {
02877 KMMsgPartDialogCompat dlg( 0, true );
02878 KMMessagePart& msgPart = mNode->msgPart();
02879 dlg.setMsgPart( &msgPart );
02880 dlg.exec();
02881 }
02882
02883 void KMHandleAttachmentCommand::atmEncryptWithChiasmus()
02884 {
02885 const partNode * node = mNode;
02886 Q_ASSERT( node );
02887 if ( !node )
02888 return;
02889
02890
02891 if ( !mAtmName.endsWith( ".xia", false ) )
02892 return;
02893
02894 const Kleo::CryptoBackend::Protocol * chiasmus =
02895 Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
02896 Q_ASSERT( chiasmus );
02897 if ( !chiasmus )
02898 return;
02899
02900 const STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> listjob( chiasmus->specialJob( "x-obtain-keys", QMap<QString,QVariant>() ) );
02901 if ( !listjob.get() ) {
02902 const QString msg = i18n( "Chiasmus backend does not offer the "
02903 "\"x-obtain-keys\" function. Please report this bug." );
02904 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02905 return;
02906 }
02907
02908 if ( listjob->exec() ) {
02909 listjob->showErrorDialog( parentWidget(), i18n( "Chiasmus Backend Error" ) );
02910 return;
02911 }
02912
02913 const QVariant result = listjob->property( "result" );
02914 if ( result.type() != QVariant::StringList ) {
02915 const QString msg = i18n( "Unexpected return value from Chiasmus backend: "
02916 "The \"x-obtain-keys\" function did not return a "
02917 "string list. Please report this bug." );
02918 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02919 return;
02920 }
02921
02922 const QStringList keys = result.toStringList();
02923 if ( keys.empty() ) {
02924 const QString msg = i18n( "No keys have been found. Please check that a "
02925 "valid key path has been set in the Chiasmus "
02926 "configuration." );
02927 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02928 return;
02929 }
02930
02931 ChiasmusKeySelector selectorDlg( parentWidget(), i18n( "Chiasmus Decryption Key Selection" ),
02932 keys, GlobalSettings::chiasmusDecryptionKey(),
02933 GlobalSettings::chiasmusDecryptionOptions() );
02934 if ( selectorDlg.exec() != QDialog::Accepted )
02935 return;
02936
02937 GlobalSettings::setChiasmusDecryptionOptions( selectorDlg.options() );
02938 GlobalSettings::setChiasmusDecryptionKey( selectorDlg.key() );
02939 assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() );
02940
02941 Kleo::SpecialJob * job = chiasmus->specialJob( "x-decrypt", QMap<QString,QVariant>() );
02942 if ( !job ) {
02943 const QString msg = i18n( "Chiasmus backend does not offer the "
02944 "\"x-decrypt\" function. Please report this bug." );
02945 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02946 return;
02947 }
02948
02949 const QByteArray input = node->msgPart().bodyDecodedBinary();
02950
02951 if ( !job->setProperty( "key", GlobalSettings::chiasmusDecryptionKey() ) ||
02952 !job->setProperty( "options", GlobalSettings::chiasmusDecryptionOptions() ) ||
02953 !job->setProperty( "input", input ) ) {
02954 const QString msg = i18n( "The \"x-decrypt\" function does not accept "
02955 "the expected parameters. Please report this bug." );
02956 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
02957 return;
02958 }
02959
02960 setDeletesItself( true );
02961 if ( job->start() ) {
02962 job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
02963 return;
02964 }
02965
02966 mJob = job;
02967 connect( job, SIGNAL(result(const GpgME::Error&,const QVariant&)),
02968 this, SLOT(slotAtmDecryptWithChiasmusResult(const GpgME::Error&,const QVariant&)) );
02969 }
02970
02971
02972 static bool checkOverwrite( const KURL& url, bool& overwrite, QWidget* w )
02973 {
02974 if ( KIO::NetAccess::exists( url, false , w ) ) {
02975 if ( KMessageBox::Cancel ==
02976 KMessageBox::warningContinueCancel(
02977 w,
02978 i18n( "A file named \"%1\" already exists. "
02979 "Are you sure you want to overwrite it?" ).arg( url.prettyURL() ),
02980 i18n( "Overwrite File?" ),
02981 i18n( "&Overwrite" ) ) )
02982 return false;
02983 overwrite = true;
02984 }
02985 return true;
02986 }
02987
02988 static const QString chomp( const QString & base, const QString & suffix, bool cs ) {
02989 return base.endsWith( suffix, cs ) ? base.left( base.length() - suffix.length() ) : base ;
02990 }
02991
02992 void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusResult( const GpgME::Error & err, const QVariant & result )
02993 {
02994 LaterDeleterWithCommandCompletion d( this );
02995 if ( !mJob )
02996 return;
02997 Q_ASSERT( mJob == sender() );
02998 if ( mJob != sender() )
02999 return;
03000 Kleo::Job * job = mJob;
03001 mJob = 0;
03002 if ( err.isCanceled() )
03003 return;
03004 if ( err ) {
03005 job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
03006 return;
03007 }
03008
03009 if ( result.type() != QVariant::ByteArray ) {
03010 const QString msg = i18n( "Unexpected return value from Chiasmus backend: "
03011 "The \"x-decrypt\" function did not return a "
03012 "byte array. Please report this bug." );
03013 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
03014 return;
03015 }
03016
03017 const KURL url = KFileDialog::getSaveURL( chomp( mAtmName, ".xia", false ), QString::null, parentWidget() );
03018 if ( url.isEmpty() )
03019 return;
03020
03021 bool overwrite = false;
03022 if ( !checkOverwrite( url, overwrite, parentWidget() ) )
03023 return;
03024
03025 d.setDisabled( true );
03026 KIO::Job * uploadJob = KIO::storedPut( result.toByteArray(), url, -1, overwrite, false );
03027 uploadJob->setWindow( parentWidget() );
03028 connect( uploadJob, SIGNAL(result(KIO::Job*)),
03029 this, SLOT(slotAtmDecryptWithChiasmusUploadResult(KIO::Job*)) );
03030 }
03031
03032 void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusUploadResult( KIO::Job * job )
03033 {
03034 if ( job->error() )
03035 job->showErrorDialog();
03036 LaterDeleterWithCommandCompletion d( this );
03037 d.setResult( OK );
03038 }
03039
03040 #include "kmcommands.moc"