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