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