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