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