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