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