kmail Library API Documentation

kmcommands.cpp

00001 // -*- mode: C++; c-file-style: "gnu" -*-
00002 // kmcommands
00003 // (c) 2002 Don Sanders <sanders@kde.org>
00004 // License: GPL
00005 //
00006 // This file implements various "command" classes. These command classes
00007 // are based on the command design pattern.
00008 //
00009 // Historically various operations were implemented as slots of KMMainWin.
00010 // This proved inadequate as KMail has multiple top level windows
00011 // (KMMainWin, KMReaderMainWin, KMFldSearch, KMComposeWin) that may
00012 // benefit from using these operations. It is desirable that these
00013 // classes can operate without depending on or altering the state of
00014 // a KMMainWin, in fact it is possible no KMMainWin object even exists.
00015 //
00016 // Now these operations have been rewritten as KMCommand based classes,
00017 // making them independent of KMMainWin.
00018 //
00019 // The base command class KMCommand is async, which is a difference
00020 // from the conventional command pattern. As normal derived classes implement
00021 // the execute method, but client classes call start() instead of
00022 // calling execute() directly. start() initiates async operations,
00023 // and on completion of these operations calls execute() and then deletes
00024 // the command. (So the client must not construct commands on the stack).
00025 //
00026 // The type of async operation supported by KMCommand is retrieval
00027 // of messages from an IMAP server.
00028 
00029 #include "kmcommands.h"
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034 
00035 #include <errno.h>
00036 #include <mimelib/enum.h>
00037 #include <mimelib/field.h>
00038 #include <mimelib/mimepp.h>
00039 #include <mimelib/string.h>
00040 #include <kapplication.h>
00041 #include <dcopclient.h>
00042 
00043 #include <qtextcodec.h>
00044 
00045 #include <libkdepim/email.h>
00046 #include <kdebug.h>
00047 #include <kencodingfiledialog.h>
00048 #include <kio/netaccess.h>
00049 #include <kabc/stdaddressbook.h>
00050 #include <kabc/addresseelist.h>
00051 #include <klocale.h>
00052 #include <kmessagebox.h>
00053 #include <kparts/browserextension.h>
00054 #include <kprogress.h>
00055 #include <krun.h>
00056 #include <kbookmarkmanager.h>
00057 #include <kstandarddirs.h>
00058 #include <ktempfile.h>
00059 #if !KDE_IS_VERSION( 3, 3, 0 )
00060 # include <storedtransferjob.h> // from libkleo
00061 #endif
00062 #include "actionscheduler.h"
00063 using KMail::ActionScheduler;
00064 #include "mailinglist-magic.h"
00065 #include "kmaddrbook.h"
00066 #include <kaddrbook.h>
00067 #include "kmcomposewin.h"
00068 #include "kmfiltermgr.h"
00069 #include "kmfoldermbox.h"
00070 #include "kmfolderimap.h"
00071 #include "kmfoldermgr.h"
00072 #include "kmheaders.h"
00073 #include "kmmainwidget.h"
00074 #include "kmmsgdict.h"
00075 #include "messagesender.h"
00076 #include "undostack.h"
00077 #include "kcursorsaver.h"
00078 #include "partNode.h"
00079 #include "objecttreeparser.h"
00080 using KMail::ObjectTreeParser;
00081 using KMail::FolderJob;
00082 #include "mailsourceviewer.h"
00083 using KMail::MailSourceViewer;
00084 #include "kmreadermainwin.h"
00085 #include "secondarywindow.h"
00086 using KMail::SecondaryWindow;
00087 #include "kimproxy.h"
00088 
00089 #include "progressmanager.h"
00090 using KPIM::ProgressManager;
00091 using KPIM::ProgressItem;
00092 
00093 #include "broadcaststatus.h"
00094 
00095 #include "headerstrategy.h"
00096 using KMail::HeaderStrategy;
00097 #include "headerstyle.h"
00098 using KMail::HeaderStyle;
00099 
00100 #include "kmcommands.moc"
00101 
00102 KMCommand::KMCommand( QWidget *parent )
00103   : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
00104     mEmitsCompletedItself( false ), mParent( parent )
00105 {
00106 }
00107 
00108 KMCommand::KMCommand( QWidget *parent, const QPtrList<KMMsgBase> &msgList )
00109   : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
00110     mEmitsCompletedItself( false ), mParent( parent ), mMsgList( msgList )
00111 {
00112 }
00113 
00114 KMCommand::KMCommand( QWidget *parent, KMMsgBase *msgBase )
00115   : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
00116     mEmitsCompletedItself( false ), mParent( parent )
00117 {
00118   mMsgList.append( msgBase );
00119 }
00120 
00121 KMCommand::KMCommand( QWidget *parent, KMMessage *msg )
00122   : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
00123     mEmitsCompletedItself( false ), mParent( parent )
00124 {
00125   mMsgList.append( &msg->toMsgBase() );
00126 }
00127 
00128 KMCommand::~KMCommand()
00129 {
00130   QValueListIterator<QGuardedPtr<KMFolder> > fit;
00131   for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
00132     if (!(*fit))
00133       continue;
00134     (*fit)->close();
00135   }
00136 }
00137 
00138 KMCommand::Result KMCommand::result()
00139 {
00140   if ( mResult == Undefined )
00141     kdDebug(5006) << k_funcinfo << "mResult is Undefined" << endl;
00142   return mResult;
00143 }
00144 
00145 void KMCommand::start()
00146 {
00147   QTimer::singleShot( 0, this, SLOT( slotStart() ) );
00148 }
00149 
00150 
00151 const QPtrList<KMMessage> KMCommand::retrievedMsgs() const
00152 {
00153   return mRetrievedMsgs;
00154 }
00155 
00156 KMMessage *KMCommand::retrievedMessage() const
00157 {
00158   return mRetrievedMsgs.getFirst();
00159 }
00160 
00161 QWidget *KMCommand::parentWidget() const
00162 {
00163   return mParent;
00164 }
00165 
00166 int KMCommand::mCountJobs = 0;
00167 
00168 void KMCommand::slotStart()
00169 {
00170   connect( this, SIGNAL( messagesTransfered( KMCommand::Result ) ),
00171            this, SLOT( slotPostTransfer( KMCommand::Result ) ) );
00172   kmkernel->filterMgr()->ref();
00173 
00174   if (mMsgList.find(0) != -1) {
00175       emit messagesTransfered( Failed );
00176       return;
00177   }
00178 
00179   if ((mMsgList.count() == 1) &&
00180       (mMsgList.getFirst()->isMessage()) &&
00181       (mMsgList.getFirst()->parent() == 0))
00182   {
00183     // Special case of operating on message that isn't in a folder
00184     mRetrievedMsgs.append((KMMessage*)mMsgList.getFirst());
00185     emit messagesTransfered( OK );
00186     return;
00187   }
00188 
00189   for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
00190     if (!mb->parent()) {
00191       emit messagesTransfered( Failed );
00192       return;
00193     } else {
00194       mFolders.append( mb->parent() );
00195       mb->parent()->open();
00196     }
00197 
00198   // transfer the selected messages first
00199   transferSelectedMsgs();
00200 }
00201 
00202 void KMCommand::slotPostTransfer( KMCommand::Result result )
00203 {
00204   disconnect( this, SIGNAL( messagesTransfered( KMCommand::Result ) ),
00205               this, SLOT( slotPostTransfer( KMCommand::Result ) ) );
00206   if ( result == OK )
00207     result = execute();
00208   mResult = result;
00209   QPtrListIterator<KMMessage> it( mRetrievedMsgs );
00210   KMMessage* msg;
00211   while ( (msg = it.current()) != 0 )
00212   {
00213     ++it;
00214     if (msg->parent())
00215       msg->setTransferInProgress(false);
00216   }
00217   kmkernel->filterMgr()->deref();
00218   if ( !emitsCompletedItself() )
00219     emit completed( this );
00220   if ( !deletesItself() )
00221     deleteLater();
00222 }
00223 
00224 void KMCommand::transferSelectedMsgs()
00225 {
00226   // make sure no other transfer is active
00227   if (KMCommand::mCountJobs > 0) {
00228     emit messagesTransfered( Failed );
00229     return;
00230   }
00231 
00232   bool complete = true;
00233   KMCommand::mCountJobs = 0;
00234   mCountMsgs = 0;
00235   mRetrievedMsgs.clear();
00236   mCountMsgs = mMsgList.count();
00237   uint totalSize = 0;
00238   // the KProgressDialog for the user-feedback. Only enable it if it's needed.
00239   // For some commands like KMSetStatusCommand it's not needed. Note, that
00240   // for some reason the KProgressDialog eats the MouseReleaseEvent (if a
00241   // command is executed after the MousePressEvent), cf. bug #71761.
00242   if ( mCountMsgs > 0 ) {
00243     mProgressDialog = new KProgressDialog(mParent, "transferProgress",
00244       i18n("Please wait"),
00245       i18n("Please wait while the message is transferred",
00246         "Please wait while the %n messages are transferred", mMsgList.count()),
00247       true);
00248     mProgressDialog->setMinimumDuration(1000);
00249   }
00250   for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
00251   {
00252     // check if all messages are complete
00253     KMMessage *thisMsg = 0;
00254     if ( mb->isMessage() )
00255       thisMsg = static_cast<KMMessage*>(mb);
00256     else
00257     {
00258       KMFolder *folder = mb->parent();
00259       int idx = folder->find(mb);
00260       if (idx < 0) continue;
00261       thisMsg = folder->getMsg(idx);
00262     }
00263     if (!thisMsg) continue;
00264     if ( thisMsg->transferInProgress() &&
00265          thisMsg->parent()->folderType() == KMFolderTypeImap )
00266     {
00267       thisMsg->setTransferInProgress( false, true );
00268       thisMsg->parent()->ignoreJobsForMessage( thisMsg );
00269     }
00270 
00271     if ( thisMsg->parent() && !thisMsg->isComplete() &&
00272          ( !mProgressDialog || !mProgressDialog->wasCancelled() ) )
00273     {
00274       kdDebug(5006)<<"### INCOMPLETE\n";
00275       // the message needs to be transferred first
00276       complete = false;
00277       KMCommand::mCountJobs++;
00278       FolderJob *job = thisMsg->parent()->createJob(thisMsg);
00279       job->setCancellable( false );
00280       totalSize += thisMsg->msgSizeServer();
00281       // emitted when the message was transferred successfully
00282       connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00283               this, SLOT(slotMsgTransfered(KMMessage*)));
00284       // emitted when the job is destroyed
00285       connect(job, SIGNAL(finished()),
00286               this, SLOT(slotJobFinished()));
00287       connect(job, SIGNAL(progress(unsigned long, unsigned long)),
00288               this, SLOT(slotProgress(unsigned long, unsigned long)));
00289       // msg musn't be deleted
00290       thisMsg->setTransferInProgress(true);
00291       job->start();
00292     } else {
00293       thisMsg->setTransferInProgress(true);
00294       mRetrievedMsgs.append(thisMsg);
00295     }
00296   }
00297 
00298   if (complete)
00299   {
00300     delete mProgressDialog;
00301     mProgressDialog = 0;
00302     emit messagesTransfered( OK );
00303   } else {
00304     // wait for the transfer and tell the progressBar the necessary steps
00305     if ( mProgressDialog ) {
00306       connect(mProgressDialog, SIGNAL(cancelClicked()),
00307               this, SLOT(slotTransferCancelled()));
00308       mProgressDialog->progressBar()->setTotalSteps(totalSize);
00309     }
00310   }
00311 }
00312 
00313 void KMCommand::slotMsgTransfered(KMMessage* msg)
00314 {
00315   if ( mProgressDialog && mProgressDialog->wasCancelled() ) {
00316     emit messagesTransfered( Canceled );
00317     return;
00318   }
00319 
00320   // save the complete messages
00321   mRetrievedMsgs.append(msg);
00322 }
00323 
00324 void KMCommand::slotProgress( unsigned long done, unsigned long /*total*/ )
00325 {
00326   mProgressDialog->progressBar()->setProgress( done );
00327 }
00328 
00329 void KMCommand::slotJobFinished()
00330 {
00331   // the job is finished (with / without error)
00332   KMCommand::mCountJobs--;
00333 
00334   if ( mProgressDialog && mProgressDialog->wasCancelled() ) return;
00335 
00336   if ( (mCountMsgs - static_cast<int>(mRetrievedMsgs.count())) > KMCommand::mCountJobs )
00337   {
00338     // the message wasn't retrieved before => error
00339     if ( mProgressDialog )
00340       mProgressDialog->hide();
00341     slotTransferCancelled();
00342     return;
00343   }
00344   // update the progressbar
00345   if ( mProgressDialog ) {
00346     mProgressDialog->setLabel(i18n("Please wait while the message is transferred",
00347           "Please wait while the %n messages are transferred", KMCommand::mCountJobs));
00348   }
00349   if (KMCommand::mCountJobs == 0)
00350   {
00351     // all done
00352     delete mProgressDialog;
00353     mProgressDialog = 0;
00354     emit messagesTransfered( OK );
00355   }
00356 }
00357 
00358 void KMCommand::slotTransferCancelled()
00359 {
00360   // kill the pending jobs
00361   QValueListIterator<QGuardedPtr<KMFolder> > fit;
00362   for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
00363     if (!(*fit))
00364       continue;
00365     KMFolder *folder = *fit;
00366     KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder);
00367     if (imapFolder && imapFolder->account()) {
00368       imapFolder->account()->killAllJobs();
00369     }
00370   }
00371 
00372   KMCommand::mCountJobs = 0;
00373   mCountMsgs = 0;
00374   // unget the transfered messages
00375   QPtrListIterator<KMMessage> it( mRetrievedMsgs );
00376   KMMessage* msg;
00377   while ( (msg = it.current()) != 0 )
00378   {
00379     KMFolder *folder = msg->parent();
00380     ++it;
00381     if (!folder)
00382       continue;
00383     msg->setTransferInProgress(false);
00384     int idx = folder->find(msg);
00385     if (idx > 0) folder->unGetMsg(idx);
00386   }
00387   mRetrievedMsgs.clear();
00388   emit messagesTransfered( Canceled );
00389 }
00390 
00391 void KMCommand::keepFolderOpen( KMFolder *folder )
00392 {
00393   folder->open();
00394   mFolders.append( folder );
00395 }
00396 
00397 KMMailtoComposeCommand::KMMailtoComposeCommand( const KURL &url,
00398                                                 KMMessage *msg )
00399   :mUrl( url ), mMessage( msg )
00400 {
00401 }
00402 
00403 KMCommand::Result KMMailtoComposeCommand::execute()
00404 {
00405   KMComposeWin *win;
00406   KMMessage *msg = new KMMessage;
00407   uint id = 0;
00408 
00409   if ( mMessage && mMessage->parent() )
00410     id = mMessage->parent()->identity();
00411 
00412   msg->initHeader(id);
00413   msg->setCharset("utf-8");
00414   msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
00415 
00416   win = new KMComposeWin(msg, id);
00417   win->setCharset("", TRUE);
00418   win->setFocusToSubject();
00419   win->show();
00420 
00421   return OK;
00422 }
00423 
00424 
00425 KMMailtoReplyCommand::KMMailtoReplyCommand( QWidget *parent,
00426    const KURL &url, KMMessage *msg, const QString &selection )
00427   :KMCommand( parent, msg ), mUrl( url ), mSelection( selection  )
00428 {
00429 }
00430 
00431 KMCommand::Result KMMailtoReplyCommand::execute()
00432 {
00433   //TODO : consider factoring createReply into this method.
00434   KMMessage *msg = retrievedMessage();
00435   KMComposeWin *win;
00436   KMMessage *rmsg = msg->createReply( KMail::ReplyNone, mSelection );
00437   rmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
00438 
00439   win = new KMComposeWin(rmsg, 0);
00440   win->setCharset(msg->codec()->mimeName(), TRUE);
00441   win->setReplyFocus();
00442   win->show();
00443 
00444   return OK;
00445 }
00446 
00447 
00448 KMMailtoForwardCommand::KMMailtoForwardCommand( QWidget *parent,
00449    const KURL &url, KMMessage *msg )
00450   :KMCommand( parent, msg ), mUrl( url )
00451 {
00452 }
00453 
00454 KMCommand::Result KMMailtoForwardCommand::execute()
00455 {
00456   //TODO : consider factoring createForward into this method.
00457   KMMessage *msg = retrievedMessage();
00458   KMComposeWin *win;
00459   KMMessage *fmsg = msg->createForward();
00460   fmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
00461 
00462   win = new KMComposeWin(fmsg);
00463   win->setCharset(msg->codec()->mimeName(), TRUE);
00464   win->show();
00465 
00466   return OK;
00467 }
00468 
00469 
00470 KMAddBookmarksCommand::KMAddBookmarksCommand( const KURL &url, QWidget *parent )
00471   : KMCommand( parent ), mUrl( url )
00472 {
00473 }
00474 
00475 KMCommand::Result KMAddBookmarksCommand::execute()
00476 {
00477   QString filename = locateLocal( "data", QString::fromLatin1("konqueror/bookmarks.xml") );
00478   KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,
00479                                                                     false );
00480   KBookmarkGroup group = bookManager->root();
00481   group.addBookmark( bookManager, mUrl.path(), KURL( mUrl ) );
00482   if( bookManager->save() ) {
00483     bookManager->emitChanged( group );
00484   }
00485 
00486   return OK;
00487 }
00488 
00489 KMMailtoAddAddrBookCommand::KMMailtoAddAddrBookCommand( const KURL &url,
00490    QWidget *parent )
00491   : KMCommand( parent ), mUrl( url )
00492 {
00493 }
00494 
00495 KMCommand::Result KMMailtoAddAddrBookCommand::execute()
00496 {
00497   KAddrBookExternal::addEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
00498                                parentWidget() );
00499 
00500   return OK;
00501 }
00502 
00503 
00504 KMMailtoOpenAddrBookCommand::KMMailtoOpenAddrBookCommand( const KURL &url,
00505    QWidget *parent )
00506   : KMCommand( parent ), mUrl( url )
00507 {
00508 }
00509 
00510 KMCommand::Result KMMailtoOpenAddrBookCommand::execute()
00511 {
00512   QString addr = KMMessage::decodeMailtoUrl( mUrl.path() );
00513   KAddrBookExternal::openEmail( KPIM::getEmailAddr(addr), addr ,
00514                                 parentWidget() );
00515 
00516   return OK;
00517 }
00518 
00519 
00520 KMUrlCopyCommand::KMUrlCopyCommand( const KURL &url, KMMainWidget *mainWidget )
00521   :mUrl( url ), mMainWidget( mainWidget )
00522 {
00523 }
00524 
00525 KMCommand::Result KMUrlCopyCommand::execute()
00526 {
00527   QClipboard* clip = QApplication::clipboard();
00528 
00529   if (mUrl.protocol() == "mailto") {
00530     // put the url into the mouse selection and the clipboard
00531     QString address = KMMessage::decodeMailtoUrl( mUrl.path() );
00532     clip->setSelectionMode( true );
00533     clip->setText( address );
00534     clip->setSelectionMode( false );
00535     clip->setText( address );
00536     KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "Address copied to clipboard." ));
00537   } else {
00538     // put the url into the mouse selection and the clipboard
00539     clip->setSelectionMode( true );
00540     clip->setText( mUrl.url() );
00541     clip->setSelectionMode( false );
00542     clip->setText( mUrl.url() );
00543     KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "URL copied to clipboard." ));
00544   }
00545 
00546   return OK;
00547 }
00548 
00549 
00550 KMUrlOpenCommand::KMUrlOpenCommand( const KURL &url, KMReaderWin *readerWin )
00551   :mUrl( url ), mReaderWin( readerWin )
00552 {
00553 }
00554 
00555 KMCommand::Result KMUrlOpenCommand::execute()
00556 {
00557   if ( !mUrl.isEmpty() )
00558     mReaderWin->slotUrlOpen( mUrl, KParts::URLArgs() );
00559 
00560   return OK;
00561 }
00562 
00563 
00564 KMUrlSaveCommand::KMUrlSaveCommand( const KURL &url, QWidget *parent )
00565   : KMCommand( parent ), mUrl( url )
00566 {
00567 }
00568 
00569 KMCommand::Result KMUrlSaveCommand::execute()
00570 {
00571   if ( mUrl.isEmpty() )
00572     return OK;
00573   KURL saveUrl = KFileDialog::getSaveURL(mUrl.fileName(), QString::null,
00574                                          parentWidget() );
00575   if ( saveUrl.isEmpty() )
00576     return Canceled;
00577   if ( KIO::NetAccess::exists( saveUrl, false, parentWidget() ) )
00578   {
00579     if (KMessageBox::warningContinueCancel(0,
00580         i18n("<qt>File <b>%1</b> exists.<br>Do you want to replace it?</qt>")
00581         .arg(saveUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
00582         != KMessageBox::Continue)
00583       return Canceled;
00584   }
00585   KIO::Job *job = KIO::file_copy(mUrl, saveUrl, -1, true);
00586   connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotUrlSaveResult(KIO::Job*)));
00587   setEmitsCompletedItself( true );
00588   return OK;
00589 }
00590 
00591 void KMUrlSaveCommand::slotUrlSaveResult( KIO::Job *job )
00592 {
00593   if ( job->error() ) {
00594     job->showErrorDialog();
00595     setResult( Failed );
00596     emit completed( this );
00597   }
00598   else {
00599     setResult( OK );
00600     emit completed( this );
00601   }
00602 }
00603 
00604 #if KDE_IS_VERSION( 3, 3, 0 )
00605 # define KIO_STORED_PUT KIO::storedPut
00606 #else
00607   // this one comes from libkleopatra...
00608 # define KIO_STORED_PUT KIOext::put
00609 #endif
00610 
00611 KMail::SaveTextAsCommand::SaveTextAsCommand( const QString & txt, QWidget * parent )
00612   : KMCommand( parent ), mText( txt ) {}
00613 
00614 KMCommand::Result KMail::SaveTextAsCommand::execute() {
00615   if ( mText.isEmpty() )
00616     return OK;
00617 
00618   const KEncodingFileDialog::Result res = KEncodingFileDialog::getSaveURLAndEncoding( QString::null, QString::null, QString::null, parentWidget() );
00619   if ( res.URLs.empty() )
00620     return Canceled;
00621   const KURL saveUrl = res.URLs.front();
00622   if ( !saveUrl.isValid() )
00623     return Canceled;
00624   if ( KIO::NetAccess::exists( saveUrl, false, parentWidget() ) ) {
00625     if (KMessageBox::warningContinueCancel(0,
00626         i18n("<qt>File <b>%1</b> exists.<br>Do you want to replace it?</qt>")
00627         .arg(saveUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
00628         != KMessageBox::Continue)
00629       return Canceled;
00630   }
00631   const QTextCodec * codec = QTextCodec::codecForName( res.encoding.latin1() );
00632   Q_ASSERT( codec );
00633   if ( !codec )
00634     return Canceled;
00635   int len = -1;
00636   QByteArray data = codec->fromUnicode( mText, len );
00637   data.resize( len );
00638   KIO::Job * uploadJob = KIO_STORED_PUT( data, saveUrl, -1, true /*overwrite*/, false /*resume*/ );
00639   uploadJob->setWindow( parentWidget() );
00640   connect( uploadJob, SIGNAL(result(KIO::Job*)), SLOT(slotResult(KIO::Job*)) );
00641   setEmitsCompletedItself( true );
00642   return OK;
00643 }
00644 
00645 #undef KIO_STORED_PUT
00646 
00647 void KMail::SaveTextAsCommand::slotResult( KIO::Job * job ) {
00648   if ( job->error() ) {
00649     job->showErrorDialog();
00650     setResult( Failed );
00651   } else {
00652     setResult( OK );
00653   }
00654   emit completed( this );
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     return Failed;
00668 
00669   // Remember the old parent, we need it a bit further down to be able
00670   // to put the unchanged messsage back in the drafts folder if the nth
00671   // edit is discarded, for n > 1.
00672   KMFolder *parent = msg->parent();
00673   if ( parent )
00674     parent->take( parent->find( msg ) );
00675 
00676   KMComposeWin *win = new KMComposeWin();
00677   msg->setTransferInProgress(false); // From here on on, the composer owns the message.
00678   win->setMsg(msg, FALSE, TRUE);
00679   win->setFolder( parent );
00680   win->show();
00681 
00682   return OK;
00683 }
00684 
00685 KMShowMsgSrcCommand::KMShowMsgSrcCommand( KMMessage *msg, bool fixedFont )
00686   : mFixedFont( fixedFont ), mMsg ( msg )
00687 {
00688 }
00689 
00690 void KMShowMsgSrcCommand::start()
00691 {
00692   QString str = mMsg->codec()->toUnicode( mMsg->asString() );
00693 
00694   MailSourceViewer *viewer = new MailSourceViewer(); // deletes itself upon close
00695   viewer->setCaption( i18n("Message as Plain Text") );
00696   viewer->setText(str);
00697   if( mFixedFont )
00698     viewer->setFont(KGlobalSettings::fixedFont());
00699 
00700   // Well, there is no widget to be seen here, so we have to use QCursor::pos()
00701   // Update: (GS) I'm not going to make this code behave according to Xinerama
00702   //         configuration because this is quite the hack.
00703   if (QApplication::desktop()->isVirtualDesktop()) {
00704     int scnum = QApplication::desktop()->screenNumber(QCursor::pos());
00705     viewer->resize(QApplication::desktop()->screenGeometry(scnum).width()/2,
00706                   2*QApplication::desktop()->screenGeometry(scnum).height()/3);
00707   } else {
00708     viewer->resize(QApplication::desktop()->geometry().width()/2,
00709                   2*QApplication::desktop()->geometry().height()/3);
00710   }
00711   viewer->show();
00712 }
00713 
00714 static KURL subjectToUrl( const QString & subject ) {
00715     return KFileDialog::getSaveURL( subject.stripWhiteSpace()
00716                                            .replace( QDir::separator(), '_' ),
00717                                     "*.mbox" );
00718 }
00719 
00720 KMSaveMsgCommand::KMSaveMsgCommand( QWidget *parent, KMMessage * msg )
00721   : KMCommand( parent ),
00722     mMsgListIndex( 0 ),
00723     mStandAloneMessage( 0 ),
00724     mOffset( 0 ),
00725     mTotalSize( msg ? msg->msgSize() : 0 )
00726 {
00727   if ( !msg ) return;
00728   setDeletesItself( true );
00729   // If the mail has a serial number, operate on sernums, if it does not
00730   // we need to work with the pointer, but can be reasonably sure it won't
00731   // go away, since it'll be an encapsulated message or one that was opened
00732   // from an .eml file.
00733   if ( msg->getMsgSerNum() != 0 ) {
00734     mMsgList.append( msg->getMsgSerNum() );
00735     if ( msg->parent() ) {
00736       msg->parent()->open();
00737     }
00738   } else {
00739     mStandAloneMessage = msg;
00740   }
00741   mUrl = subjectToUrl( msg->cleanSubject() );
00742 }
00743 
00744 KMSaveMsgCommand::KMSaveMsgCommand( QWidget *parent,
00745                                     const QPtrList<KMMsgBase> &msgList )
00746   : KMCommand( parent ),
00747     mMsgListIndex( 0 ),
00748     mStandAloneMessage( 0 ),
00749     mOffset( 0 ),
00750     mTotalSize( 0 )
00751 {
00752   if (!msgList.getFirst())
00753     return;
00754   setDeletesItself( true );
00755   KMMsgBase *msgBase = msgList.getFirst();
00756 
00757   // We operate on serNums and not the KMMsgBase pointers, as those can
00758   // change, or become invalid when changing the current message, switching
00759   // folders, etc.
00760   QPtrListIterator<KMMsgBase> it(msgList);
00761   while ( it.current() ) {
00762     mMsgList.append( (*it)->getMsgSerNum() );
00763     mTotalSize += (*it)->msgSize();
00764     if ((*it)->parent() != 0)
00765       (*it)->parent()->open();
00766     ++it;
00767   }
00768   mMsgListIndex = 0;
00769   mUrl = subjectToUrl( msgBase->cleanSubject() );
00770 }
00771 
00772 KURL KMSaveMsgCommand::url()
00773 {
00774   return mUrl;
00775 }
00776 
00777 KMCommand::Result KMSaveMsgCommand::execute()
00778 {
00779   mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, false, false );
00780   mJob->slotTotalSize( mTotalSize );
00781   mJob->setAsyncDataEnabled( true );
00782   mJob->setReportDataSent( true );
00783   connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)),
00784     SLOT(slotSaveDataReq()));
00785   connect(mJob, SIGNAL(result(KIO::Job*)),
00786     SLOT(slotSaveResult(KIO::Job*)));
00787   setEmitsCompletedItself( true );
00788   return OK;
00789 }
00790 
00791 void KMSaveMsgCommand::slotSaveDataReq()
00792 {
00793   int remainingBytes = mData.size() - mOffset;
00794   if ( remainingBytes > 0 ) {
00795     // eat leftovers first
00796     if ( remainingBytes > MAX_CHUNK_SIZE )
00797       remainingBytes = MAX_CHUNK_SIZE;
00798 
00799     QByteArray data;
00800     data.duplicate( mData.data() + mOffset, remainingBytes );
00801     mJob->sendAsyncData( data );
00802     mOffset += remainingBytes;
00803     return;
00804   }
00805   // No leftovers, process next message.
00806   if ( mMsgListIndex < mMsgList.size() ) {
00807     KMMessage *msg = 0;
00808     int idx = -1;
00809     KMFolder * p = 0;
00810     kmkernel->msgDict()->getLocation( mMsgList[mMsgListIndex], &p, &idx );
00811     assert( p );
00812     assert( idx >= 0 );
00813     msg = p->getMsg(idx);
00814 
00815     if ( msg ) {
00816       if (msg->transferInProgress()) {
00817         QByteArray data = QByteArray();
00818         mJob->sendAsyncData( data );
00819       }
00820       msg->setTransferInProgress( true );
00821       if (msg->isComplete() ) {
00822         slotMessageRetrievedForSaving(msg);
00823       } else {
00824         // retrieve Message first
00825         if (msg->parent()  && !msg->isComplete() ) {
00826           FolderJob *job = msg->parent()->createJob(msg);
00827           job->setCancellable( false );
00828           connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00829               this, SLOT(slotMessageRetrievedForSaving(KMMessage*)));
00830           job->start();
00831         }
00832       }
00833     } else {
00834       mJob->slotError( KIO::ERR_ABORTED,
00835                        i18n("The message was removed while saving it. "
00836                             "It has not been saved.") );
00837     }
00838   } else {
00839     if ( mStandAloneMessage ) {
00840       // do the special case of a standalone message
00841       slotMessageRetrievedForSaving( mStandAloneMessage );
00842       mStandAloneMessage = 0;
00843     } else {
00844       // No more messages. Tell the putjob we are done.
00845       QByteArray data = QByteArray();
00846       mJob->sendAsyncData( data );
00847     }
00848   }
00849 }
00850 
00851 void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg)
00852 {
00853   QCString str( msg->mboxMessageSeparator() );
00854   str += KMFolderMbox::escapeFrom( msg->asString() );
00855   str += "\n";
00856   msg->setTransferInProgress(false);
00857 
00858   mData = str;
00859   mData.resize(mData.size() - 1);
00860   mOffset = 0;
00861   QByteArray data;
00862   int size;
00863   // Unless it is great than 64 k send the whole message. kio buffers for us.
00864   if( mData.size() > (unsigned int) MAX_CHUNK_SIZE )
00865     size = MAX_CHUNK_SIZE;
00866   else
00867     size = mData.size();
00868 
00869   data.duplicate( mData, size );
00870   mJob->sendAsyncData( data );
00871   mOffset += size;
00872   ++mMsgListIndex;
00873   // Get rid of the message.
00874   if (msg->parent()) {
00875     int idx = -1;
00876     KMFolder * p = 0;
00877     kmkernel->msgDict()->getLocation( msg, &p, &idx );
00878     assert( p == msg->parent() ); assert( idx >= 0 );
00879     p->unGetMsg( idx );
00880     p->close();
00881   }
00882 }
00883 
00884 void KMSaveMsgCommand::slotSaveResult(KIO::Job *job)
00885 {
00886   if (job->error())
00887   {
00888     if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
00889     {
00890       if (KMessageBox::warningContinueCancel(0,
00891         i18n("File %1 exists.\nDo you want to replace it?")
00892         .arg(mUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
00893         == KMessageBox::Continue) {
00894         mOffset = 0;
00895 
00896         mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, true, false );
00897         mJob->slotTotalSize( mTotalSize );
00898         mJob->setAsyncDataEnabled( true );
00899         mJob->setReportDataSent( true );
00900         connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)),
00901             SLOT(slotSaveDataReq()));
00902         connect(mJob, SIGNAL(result(KIO::Job*)),
00903             SLOT(slotSaveResult(KIO::Job*)));
00904       }
00905     }
00906     else
00907     {
00908       job->showErrorDialog();
00909       setResult( Failed );
00910       emit completed( this );
00911       deleteLater();
00912     }
00913   } else {
00914     setResult( OK );
00915     emit completed( this );
00916     deleteLater();
00917   }
00918 }
00919 
00920 //-----------------------------------------------------------------------------
00921 
00922 KMOpenMsgCommand::KMOpenMsgCommand( QWidget *parent, const KURL & url,
00923                                     const QString & encoding )
00924   : KMCommand( parent ),
00925     mUrl( url ),
00926     mEncoding( encoding )
00927 {
00928   setDeletesItself( true );
00929 }
00930 
00931 KMCommand::Result KMOpenMsgCommand::execute()
00932 {
00933   if ( mUrl.isEmpty() ) {
00934     mUrl = KFileDialog::getOpenURL( ":OpenMessage", "message/rfc822",
00935                                     parentWidget(), i18n("Open Message") );
00936   }
00937   if ( mUrl.isEmpty() ) {
00938     setDeletesItself( false );
00939     return Canceled;
00940   }
00941   mJob = KIO::get( mUrl, false, false );
00942   mJob->setReportDataSent( true );
00943   connect( mJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
00944            this, SLOT( slotDataArrived( KIO::Job*, const QByteArray & ) ) );
00945   connect( mJob, SIGNAL( result( KIO::Job * ) ),
00946            SLOT( slotResult( KIO::Job * ) ) );
00947   setEmitsCompletedItself( true );
00948   return OK;
00949 }
00950 
00951 void KMOpenMsgCommand::slotDataArrived( KIO::Job *, const QByteArray & data )
00952 {
00953   if ( data.isEmpty() )
00954     return;
00955 
00956   mMsgString.append( data.data(), data.size() );
00957 }
00958 
00959 void KMOpenMsgCommand::slotResult( KIO::Job *job )
00960 {
00961   if ( job->error() ) {
00962     // handle errors
00963     job->showErrorDialog();
00964     setResult( Failed );
00965     emit completed( this );
00966   }
00967   else {
00968     int startOfMessage = 0;
00969     if ( mMsgString.compare( 0, 5, "From ", 5 ) == 0 ) {
00970       startOfMessage = mMsgString.find( '\n' );
00971       if ( startOfMessage == -1 ) {
00972         KMessageBox::sorry( parentWidget(),
00973                             i18n( "The file doesn't contain a message." ) );
00974         setResult( Failed );
00975         emit completed( this );
00976         // Emulate closing of a secondary window so that KMail exits in case it
00977         // was started with the --view command line option. Otherwise an
00978         // invisible KMail would keep running.
00979         SecondaryWindow *win = new SecondaryWindow();
00980         win->close();
00981         win->deleteLater();
00982         deleteLater();
00983         return;
00984       }
00985       startOfMessage += 1; // the message starts after the '\n'
00986     }
00987     // check for multiple messages in the file
00988     bool multipleMessages = true;
00989     int endOfMessage = mMsgString.find( "\nFrom " );
00990     if ( endOfMessage == -1 ) {
00991       endOfMessage = mMsgString.length();
00992       multipleMessages = false;
00993     }
00994     DwMessage *dwMsg = new DwMessage;
00995     dwMsg->FromString( mMsgString.substr( startOfMessage,
00996                                           endOfMessage - startOfMessage ) );
00997     dwMsg->Parse();
00998     // check whether we have a message ( no headers => this isn't a message )
00999     if ( dwMsg->Headers().NumFields() == 0 ) {
01000       KMessageBox::sorry( parentWidget(),
01001                           i18n( "The file doesn't contain a message." ) );
01002       delete dwMsg; dwMsg = 0;
01003       setResult( Failed );
01004       emit completed( this );
01005       // Emulate closing of a secondary window (see above).
01006       SecondaryWindow *win = new SecondaryWindow();
01007       win->close();
01008       win->deleteLater();
01009       deleteLater();
01010       return;
01011     }
01012     KMMessage *msg = new KMMessage( dwMsg );
01013     msg->setComplete( true );
01014     msg->setReadyToShow( true );
01015     KMReaderMainWin *win = new KMReaderMainWin();
01016     win->showMsg( mEncoding, msg );
01017     win->show();
01018     if ( multipleMessages )
01019       KMessageBox::information( win,
01020                                 i18n( "The file contains multiple messages. "
01021                                       "Only the first message is shown." ) );
01022     setResult( OK );
01023     emit completed( this );
01024   }
01025   deleteLater();
01026 }
01027 
01028 //-----------------------------------------------------------------------------
01029 
01030 //TODO: ReplyTo, NoQuoteReplyTo, ReplyList, ReplyToAll, ReplyAuthor
01031 //      are all similar and should be factored
01032 KMReplyToCommand::KMReplyToCommand( QWidget *parent, KMMessage *msg,
01033                                     const QString &selection )
01034   : KMCommand( parent, msg ), mSelection( selection )
01035 {
01036 }
01037 
01038 KMCommand::Result KMReplyToCommand::execute()
01039 {
01040   KCursorSaver busy(KBusyPtr::busy());
01041   KMMessage *msg = retrievedMessage();
01042   KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection );
01043   KMComposeWin *win = new KMComposeWin( reply );
01044   win->setCharset( msg->codec()->mimeName(), TRUE );
01045   win->setReplyFocus();
01046   win->show();
01047 
01048   return OK;
01049 }
01050 
01051 
01052 KMNoQuoteReplyToCommand::KMNoQuoteReplyToCommand( QWidget *parent,
01053                                                   KMMessage *msg )
01054   : KMCommand( parent, msg )
01055 {
01056 }
01057 
01058 KMCommand::Result KMNoQuoteReplyToCommand::execute()
01059 {
01060   KCursorSaver busy(KBusyPtr::busy());
01061   KMMessage *msg = retrievedMessage();
01062   KMMessage *reply = msg->createReply( KMail::ReplySmart, "", TRUE);
01063   KMComposeWin *win = new KMComposeWin( reply );
01064   win->setCharset(msg->codec()->mimeName(), TRUE);
01065   win->setReplyFocus(false);
01066   win->show();
01067 
01068   return OK;
01069 }
01070 
01071 
01072 KMReplyListCommand::KMReplyListCommand( QWidget *parent,
01073   KMMessage *msg, const QString &selection )
01074  : KMCommand( parent, msg ), mSelection( selection )
01075 {
01076 }
01077 
01078 KMCommand::Result KMReplyListCommand::execute()
01079 {
01080   KCursorSaver busy(KBusyPtr::busy());
01081   KMMessage *msg = retrievedMessage();
01082   KMMessage *reply = msg->createReply( KMail::ReplyList, mSelection);
01083   KMComposeWin *win = new KMComposeWin( reply );
01084   win->setCharset(msg->codec()->mimeName(), TRUE);
01085   win->setReplyFocus(false);
01086   win->show();
01087 
01088   return OK;
01089 }
01090 
01091 
01092 KMReplyToAllCommand::KMReplyToAllCommand( QWidget *parent,
01093   KMMessage *msg, const QString &selection )
01094   :KMCommand( parent, msg ), mSelection( selection )
01095 {
01096 }
01097 
01098 KMCommand::Result KMReplyToAllCommand::execute()
01099 {
01100   KCursorSaver busy(KBusyPtr::busy());
01101   KMMessage *msg = retrievedMessage();
01102   KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection );
01103   KMComposeWin *win = new KMComposeWin( reply );
01104   win->setCharset( msg->codec()->mimeName(), TRUE );
01105   win->setReplyFocus();
01106   win->show();
01107 
01108   return OK;
01109 }
01110 
01111 
01112 KMReplyAuthorCommand::KMReplyAuthorCommand( QWidget *parent, KMMessage *msg,
01113                                             const QString &selection )
01114   : KMCommand( parent, msg ), mSelection( selection )
01115 {
01116 }
01117 
01118 KMCommand::Result KMReplyAuthorCommand::execute()
01119 {
01120   KCursorSaver busy(KBusyPtr::busy());
01121   KMMessage *msg = retrievedMessage();
01122   KMMessage *reply = msg->createReply( KMail::ReplyAuthor, mSelection );
01123   KMComposeWin *win = new KMComposeWin( reply );
01124   win->setCharset( msg->codec()->mimeName(), TRUE );
01125   win->setReplyFocus();
01126   win->show();
01127 
01128   return OK;
01129 }
01130 
01131 
01132 KMForwardCommand::KMForwardCommand( QWidget *parent,
01133   const QPtrList<KMMsgBase> &msgList, uint identity )
01134   : KMCommand( parent, msgList ),
01135     mIdentity( identity )
01136 {
01137 }
01138 
01139 KMForwardCommand::KMForwardCommand( QWidget *parent, KMMessage *msg,
01140                                     uint identity )
01141   : KMCommand( parent, msg ),
01142     mIdentity( identity )
01143 {
01144 }
01145 
01146 KMCommand::Result KMForwardCommand::execute()
01147 {
01148   KMComposeWin *win;
01149   QPtrList<KMMessage> msgList = retrievedMsgs();
01150 
01151   if (msgList.count() >= 2) {
01152     // ask if they want a mime digest forward
01153 
01154     if (KMessageBox::questionYesNo( parentWidget(),
01155                                     i18n("Forward selected messages as "
01156                                          "a MIME digest?") )
01157         == KMessageBox::Yes) {
01158       uint id = 0;
01159       KMMessage *fwdMsg = new KMMessage;
01160       KMMessagePart *msgPart = new KMMessagePart;
01161       QString msgPartText;
01162       int msgCnt = 0; // incase there are some we can't forward for some reason
01163 
01164       // dummy header initialization; initialization with the correct identity
01165       // is done below
01166       fwdMsg->initHeader(id);
01167       fwdMsg->setAutomaticFields(true);
01168       fwdMsg->mMsg->Headers().ContentType().CreateBoundary(1);
01169       QCString boundary( fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() );
01170       msgPartText = i18n("\nThis is a MIME digest forward. The content of the"
01171                          " message is contained in the attachment(s).\n\n\n");
01172       // iterate through all the messages to be forwarded
01173       for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01174         // set the identity
01175         if (id == 0)
01176           id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01177         // set the part header
01178         msgPartText += "--";
01179         msgPartText += QString::fromLatin1( boundary );
01180         msgPartText += "\nContent-Type: MESSAGE/RFC822";
01181         msgPartText += QString("; CHARSET=%1").arg(msg->charset());
01182         msgPartText += "\n";
01183         DwHeaders dwh;
01184         dwh.MessageId().CreateDefault();
01185         msgPartText += QString("Content-ID: %1\n").arg(dwh.MessageId().AsString().c_str());
01186         msgPartText += QString("Content-Description: %1").arg(msg->subject());
01187         if (!msg->subject().contains("(fwd)"))
01188           msgPartText += " (fwd)";
01189         msgPartText += "\n\n";
01190         // remove headers that shouldn't be forwarded
01191         msg->removePrivateHeaderFields();
01192         msg->removeHeaderField("BCC");
01193         // set the part
01194         msgPartText += msg->headerAsString();
01195         msgPartText += "\n";
01196         msgPartText += msg->body();
01197         msgPartText += "\n";     // eot
01198         msgCnt++;
01199         fwdMsg->link(msg, KMMsgStatusForwarded);
01200       }
01201       if ( id == 0 )
01202         id = mIdentity; // use folder identity if no message had an id set
01203       fwdMsg->initHeader(id);
01204       msgPartText += "--";
01205       msgPartText += QString::fromLatin1( boundary );
01206       msgPartText += "--\n";
01207       QCString tmp;
01208       msgPart->setTypeStr("MULTIPART");
01209       tmp.sprintf( "Digest; boundary=\"%s\"", boundary.data() );
01210       msgPart->setSubtypeStr( tmp );
01211       msgPart->setName("unnamed");
01212       msgPart->setCte(DwMime::kCte7bit);   // does it have to be 7bit?
01213       msgPart->setContentDescription(QString("Digest of %1 messages.").arg(msgCnt));
01214       // THIS HAS TO BE AFTER setCte()!!!!
01215       msgPart->setBodyEncoded(QCString(msgPartText.ascii()));
01216       KCursorSaver busy(KBusyPtr::busy());
01217       win = new KMComposeWin(fwdMsg, id);
01218       win->addAttach(msgPart);
01219       win->show();
01220       return OK;
01221     } else {            // NO MIME DIGEST, Multiple forward
01222       uint id = 0;
01223       QCString msgText = "";
01224       QPtrList<KMMessage> linklist;
01225       for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01226         // set the identity
01227         if (id == 0)
01228           id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01229 
01230         msgText += msg->createForwardBody();
01231         linklist.append(msg);
01232       }
01233       if ( id == 0 )
01234         id = mIdentity; // use folder identity if no message had an id set
01235       KMMessage *fwdMsg = new KMMessage;
01236       fwdMsg->initHeader(id);
01237       fwdMsg->setAutomaticFields(true);
01238       fwdMsg->setCharset("utf-8");
01239       fwdMsg->setBody(msgText);
01240 
01241       for (KMMessage *msg = linklist.first(); msg; msg = linklist.next())
01242         fwdMsg->link(msg, KMMsgStatusForwarded);
01243 
01244       KCursorSaver busy(KBusyPtr::busy());
01245       win = new KMComposeWin(fwdMsg, id);
01246       win->setCharset("");
01247       win->show();
01248       return OK;
01249     }
01250   }
01251 
01252   // forward a single message at most.
01253   KMMessage *msg = msgList.getFirst();
01254   if ( !msg || !msg->codec() )
01255     return Failed;
01256 
01257   KCursorSaver busy(KBusyPtr::busy());
01258   KMMessage *fwdMsg = msg->createForward();
01259 
01260   win = new KMComposeWin( fwdMsg );
01261   win->setCharset( fwdMsg->codec()->mimeName(), true );
01262   win->setBody( QString::fromUtf8( msg->createForwardBody() ) );
01263   win->show();
01264 
01265   return OK;
01266 }
01267 
01268 
01269 KMForwardAttachedCommand::KMForwardAttachedCommand( QWidget *parent,
01270   const QPtrList<KMMsgBase> &msgList, uint identity, KMComposeWin *win )
01271   : KMCommand( parent, msgList ), mIdentity( identity ),
01272     mWin( QGuardedPtr< KMComposeWin >( win ))
01273 {
01274 }
01275 
01276 KMForwardAttachedCommand::KMForwardAttachedCommand( QWidget *parent,
01277   KMMessage * msg, uint identity, KMComposeWin *win )
01278   : KMCommand( parent, msg ), mIdentity( identity ),
01279     mWin( QGuardedPtr< KMComposeWin >( win ))
01280 {
01281 }
01282 
01283 KMCommand::Result KMForwardAttachedCommand::execute()
01284 {
01285   QPtrList<KMMessage> msgList = retrievedMsgs();
01286   KMMessage *fwdMsg = new KMMessage;
01287 
01288   if (msgList.count() >= 2) {
01289     // don't respect X-KMail-Identity headers because they might differ for
01290     // the selected mails
01291     fwdMsg->initHeader(mIdentity);
01292   }
01293   else if (msgList.count() == 1) {
01294     KMMessage *msg = msgList.getFirst();
01295     fwdMsg->initFromMessage(msg);
01296     fwdMsg->setSubject( msg->forwardSubject() );
01297   }
01298 
01299   fwdMsg->setAutomaticFields(true);
01300 
01301   KCursorSaver busy(KBusyPtr::busy());
01302   if (!mWin)
01303     mWin = new KMComposeWin(fwdMsg, mIdentity);
01304 
01305   // iterate through all the messages to be forwarded
01306   for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01307     // remove headers that shouldn't be forwarded
01308     msg->removePrivateHeaderFields();
01309     msg->removeHeaderField("BCC");
01310     // set the part
01311     KMMessagePart *msgPart = new KMMessagePart;
01312     msgPart->setTypeStr("message");
01313     msgPart->setSubtypeStr("rfc822");
01314     msgPart->setCharset(msg->charset());
01315     msgPart->setName("forwarded message");
01316     msgPart->setContentDescription(msg->from()+": "+msg->subject());
01317     msgPart->setContentDisposition( "inline" );
01318     // THIS HAS TO BE AFTER setCte()!!!!
01319     msgPart->setMessageBody( msg->asString() );
01320     msgPart->setCharset("");
01321 
01322     fwdMsg->link(msg, KMMsgStatusForwarded);
01323     mWin->addAttach(msgPart);
01324   }
01325 
01326   mWin->show();
01327 
01328   return OK;
01329 }
01330 
01331 
01332 KMRedirectCommand::KMRedirectCommand( QWidget *parent,
01333   KMMessage *msg )
01334   : KMCommand( parent, msg )
01335 {
01336 }
01337 
01338 KMCommand::Result KMRedirectCommand::execute()
01339 {
01340   //TODO: move KMMessage::createRedirect to here
01341   KMComposeWin *win;
01342   KMMessage *msg = retrievedMessage();
01343   if ( !msg || !msg->codec() )
01344     return Failed;
01345 
01346   KCursorSaver busy(KBusyPtr::busy());
01347   win = new KMComposeWin();
01348   win->setMsg(msg->createRedirect(), FALSE);
01349   win->setCharset(msg->codec()->mimeName());
01350   win->show();
01351 
01352   return OK;
01353 }
01354 
01355 
01356 KMBounceCommand::KMBounceCommand( QWidget *parent,
01357   KMMessage *msg )
01358   : KMCommand( parent, msg )
01359 {
01360 }
01361 
01362 KMCommand::Result KMBounceCommand::execute()
01363 {
01364   KMMessage *msg = retrievedMessage();
01365   KMMessage *newMsg = msg->createBounce( TRUE /* with UI */);
01366   if (newMsg)
01367     kmkernel->msgSender()->send(newMsg, kmkernel->msgSender()->sendImmediate());
01368 
01369   return OK;
01370 }
01371 
01372 
01373 KMPrintCommand::KMPrintCommand( QWidget *parent,
01374   KMMessage *msg, bool htmlOverride, const QString & encoding,
01375   const HeaderStyle * style,
01376   const HeaderStrategy * strategy )
01377   : KMCommand( parent, msg ), mHtmlOverride( htmlOverride ), mEncoding( encoding ),
01378     mStyle( style ), mStrategy( strategy )
01379 {
01380 }
01381 
01382 KMCommand::Result KMPrintCommand::execute()
01383 {
01384   KMReaderWin printWin( 0, 0, 0 );
01385   printWin.setPrinting(TRUE);
01386   printWin.readConfig();
01387   if( mStyle != 0 && mStrategy != 0 )
01388     printWin.setHeaderStyleAndStrategy( mStyle, mStrategy );
01389   printWin.setHtmlOverride( mHtmlOverride );
01390   printWin.setOverrideEncoding( mEncoding );
01391   printWin.setMsg(retrievedMessage(), TRUE);
01392   printWin.printMsg();
01393 
01394   return OK;
01395 }
01396 
01397 
01398 KMSetStatusCommand::KMSetStatusCommand( KMMsgStatus status,
01399   const QValueList<Q_UINT32> &serNums, bool toggle )
01400   : mStatus( status ), mSerNums( serNums ), mToggle( toggle )
01401 {
01402 }
01403 
01404 KMCommand::Result KMSetStatusCommand::execute()
01405 {
01406   QValueListIterator<Q_UINT32> it;
01407   int idx = -1;
01408   KMFolder *folder = 0;
01409   bool parentStatus = false;
01410 
01411   // Toggle actions on threads toggle the whole thread
01412   // depending on the state of the parent.
01413   if (mToggle) {
01414     KMMsgBase *msg;
01415     kmkernel->msgDict()->getLocation( *mSerNums.begin(), &folder, &idx );
01416     if (folder) {
01417       msg = folder->getMsgBase(idx);
01418       if (msg && (msg->status()&mStatus))
01419         parentStatus = true;
01420       else
01421         parentStatus = false;
01422     }
01423   }
01424   QMap< KMFolder*, QValueList<int> > folderMap;
01425   for ( it = mSerNums.begin(); it != mSerNums.end(); ++it ) {
01426     kmkernel->msgDict()->getLocation( *it, &folder, &idx );
01427     if (folder) {
01428       if (mToggle) {
01429         KMMsgBase *msg = folder->getMsgBase(idx);
01430         // check if we are already at the target toggle state
01431         if (msg) {
01432           bool myStatus;
01433           if (msg->status()&mStatus)
01434             myStatus = true;
01435           else
01436             myStatus = false;
01437           if (myStatus != parentStatus)
01438             continue;
01439         }
01440       }
01441       /* Collect the ids for each folder in a separate list and
01442          send them off in one go at the end. */
01443       folderMap[folder].append(idx);
01444     }
01445   }
01446   QMapIterator< KMFolder*, QValueList<int> > it2 = folderMap.begin();
01447   while ( it2 != folderMap.end() ) {
01448      KMFolder *f = it2.key();
01449      f->setStatus( (*it2), mStatus, mToggle );
01450      ++it2;
01451   }
01452   //kapp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", QByteArray() );
01453 
01454   return OK;
01455 }
01456 
01457 
01458 KMFilterCommand::KMFilterCommand( const QCString &field, const QString &value )
01459   : mField( field ), mValue( value )
01460 {
01461 }
01462 
01463 KMCommand::Result KMFilterCommand::execute()
01464 {
01465   kmkernel->filterMgr()->createFilter( mField, mValue );
01466 
01467   return OK;
01468 }
01469 
01470 
01471 KMFilterActionCommand::KMFilterActionCommand( QWidget *parent,
01472                                               const QPtrList<KMMsgBase> &msgList,
01473                                               KMFilter *filter )
01474   : KMCommand( parent, msgList ), mFilter( filter  )
01475 {
01476 }
01477 
01478 KMCommand::Result KMFilterActionCommand::execute()
01479 {
01480   QPtrList<KMMessage> msgList = retrievedMsgs();
01481 
01482   for (KMMessage *msg = msgList.first(); msg; msg = msgList.next())
01483     if( msg->parent() )
01484       kmkernel->filterMgr()->tempOpenFolder(msg->parent());
01485 
01486   for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01487     msg->setTransferInProgress(false);
01488 
01489     int filterResult = kmkernel->filterMgr()->process(msg, mFilter);
01490     if (filterResult == 2) {
01491       // something went horribly wrong (out of space?)
01492       perror("Critical error");
01493       kmkernel->emergencyExit( i18n("Not enough free disk space?" ));
01494     }
01495     msg->setTransferInProgress(true);
01496   }
01497 
01498   return OK;
01499 }
01500 
01501 
01502 KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter,
01503                                                       KMHeaders *headers,
01504                                                       KMMainWidget *main )
01505     : QObject( main ),
01506       mFilter( filter ), mHeaders( headers ), mMainWidget( main )
01507 {
01508 }
01509 
01510 void KMMetaFilterActionCommand::start()
01511 {
01512 #if 0 // use action scheduler
01513   KMFilterMgr::FilterSet set = KMFilterMgr::All;
01514   QPtrList<KMFilter> filters;
01515   filters.append( mFilter );
01516   ActionScheduler *scheduler = new ActionScheduler( set, filters, mHeaders );
01517   scheduler->setAlwaysMatch( true );
01518   scheduler->setAutoDestruct( true );
01519 
01520   int contentX, contentY;
01521   KMHeaderItem *nextItem = mHeaders->prepareMove( &contentX, &contentY );
01522   QPtrList<KMMsgBase> msgList = *mHeaders->selectedMsgs(true);
01523   mHeaders->finalizeMove( nextItem, contentX, contentY );
01524 
01525 
01526   for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
01527     scheduler->execFilters( msg );
01528 #else
01529   KMCommand *filterCommand = new KMFilterActionCommand( mMainWidget,
01530   *mHeaders->selectedMsgs(), mFilter);
01531   filterCommand->start();
01532   int contentX, contentY;
01533   KMHeaderItem *item = mHeaders->prepareMove( &contentX, &contentY );
01534   mHeaders->finalizeMove( item, contentX, contentY );
01535 #endif
01536 }
01537 
01538 
01539 KMMailingListFilterCommand::KMMailingListFilterCommand( QWidget *parent,
01540                                                         KMMessage *msg )
01541   : KMCommand( parent, msg )
01542 {
01543 }
01544 
01545 KMCommand::Result KMMailingListFilterCommand::execute()
01546 {
01547   QCString name;
01548   QString value;
01549   KMMessage *msg = retrievedMessage();
01550   if (!msg)
01551     return Failed;
01552 
01553   if ( !MailingList::name( msg, name, value ).isEmpty() ) {
01554     kmkernel->filterMgr()->createFilter( name, value );
01555     return OK;
01556   }
01557   else
01558     return Failed;
01559 }
01560 
01561 
01562 void KMMenuCommand::folderToPopupMenu(bool move,
01563   QObject *receiver, KMMenuToFolder *aMenuToFolder, QPopupMenu *menu )
01564 {
01565   while ( menu->count() )
01566   {
01567     QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
01568     if (popup)
01569       delete popup;
01570     else
01571       menu->removeItemAt( 0 );
01572   }
01573 
01574   if (!kmkernel->imapFolderMgr()->dir().first() &&
01575       !kmkernel->dimapFolderMgr()->dir().first())
01576   { // only local folders
01577     makeFolderMenu( &kmkernel->folderMgr()->dir(), move,
01578                     receiver, aMenuToFolder, menu );
01579   } else {
01580     // operate on top-level items
01581     QPopupMenu* subMenu = new QPopupMenu(menu);
01582     makeFolderMenu( &kmkernel->folderMgr()->dir(),
01583                     move, receiver, aMenuToFolder, subMenu );
01584     menu->insertItem( i18n( "Local Folders" ), subMenu );
01585     KMFolderDir* fdir = &kmkernel->imapFolderMgr()->dir();
01586     for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
01587       if (node->isDir())
01588         continue;
01589       subMenu = new QPopupMenu(menu);
01590       makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
01591       menu->insertItem( node->label(), subMenu );
01592     }
01593     fdir = &kmkernel->dimapFolderMgr()->dir();
01594     for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
01595       if (node->isDir())
01596         continue;
01597       subMenu = new QPopupMenu(menu);
01598       makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
01599       menu->insertItem( node->label(), subMenu );
01600     }
01601   }
01602 }
01603 
01604 void KMMenuCommand::makeFolderMenu(KMFolderNode* node, bool move,
01605   QObject *receiver, KMMenuToFolder *aMenuToFolder, QPopupMenu *menu )
01606 {
01607   // connect the signals
01608   if (move)
01609   {
01610     disconnect(menu, SIGNAL(activated(int)), receiver,
01611            SLOT(moveSelectedToFolder(int)));
01612     connect(menu, SIGNAL(activated(int)), receiver,
01613              SLOT(moveSelectedToFolder(int)));
01614   } else {
01615     disconnect(menu, SIGNAL(activated(int)), receiver,
01616            SLOT(copySelectedToFolder(int)));
01617     connect(menu, SIGNAL(activated(int)), receiver,
01618              SLOT(copySelectedToFolder(int)));
01619   }
01620 
01621   KMFolder *folder = 0;
01622   KMFolderDir *folderDir = 0;
01623   if (node->isDir()) {
01624     folderDir = static_cast<KMFolderDir*>(node);
01625   } else {
01626     folder = static_cast<KMFolder*>(node);
01627     folderDir = folder->child();
01628   }
01629 
01630   if (folder && !folder->noContent())
01631   {
01632     int menuId;
01633     if (move)
01634       menuId = menu->insertItem(i18n("Move to This Folder"));
01635     else
01636       menuId = menu->insertItem(i18n("Copy to This Folder"));
01637     aMenuToFolder->insert( menuId, folder );
01638     menu->setItemEnabled( menuId, !folder->isReadOnly() );
01639     menu->insertSeparator();
01640   }
01641 
01642   if (!folderDir)
01643     return;
01644 
01645   for (KMFolderNode *it = folderDir->first(); it; it = folderDir->next() ) {
01646     if (it->isDir())
01647       continue;
01648     KMFolder *child = static_cast<KMFolder*>(it);
01649     QString label = child->label();
01650     label.replace("&","&&");
01651     if (child->child() && child->child()->first()) {
01652       // descend
01653       QPopupMenu *subMenu = new QPopupMenu(menu, "subMenu");
01654       makeFolderMenu( child, move, receiver,
01655                       aMenuToFolder, subMenu );
01656       menu->insertItem( label, subMenu );
01657     } else {
01658       // insert an item
01659       int menuId = menu->insertItem( label );
01660       aMenuToFolder->insert( menuId, child );
01661       menu->setItemEnabled( menuId, !child->isReadOnly() );
01662     }
01663   }
01664   return;
01665 }
01666 
01667 
01668 KMCopyCommand::KMCopyCommand( KMFolder* destFolder,
01669                               const QPtrList<KMMsgBase> &msgList )
01670 :mDestFolder( destFolder ), mMsgList( msgList )
01671 {
01672 }
01673 
01674 KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg )
01675   :mDestFolder( destFolder )
01676 {
01677   mMsgList.append( &msg->toMsgBase() );
01678 }
01679 
01680 KMCommand::Result KMCopyCommand::execute()
01681 {
01682   KMMsgBase *msgBase;
01683   KMMessage *msg, *newMsg;
01684   int idx = -1;
01685   bool isMessage;
01686   QPtrList<KMMessage> list;
01687 
01688   if (mDestFolder && mDestFolder->open() != 0)
01689     return Failed;
01690 
01691   KCursorSaver busy(KBusyPtr::busy());
01692 
01693   for (msgBase = mMsgList.first(); msgBase; msgBase = mMsgList.next() )
01694   {
01695     KMFolder *srcFolder = msgBase->parent();
01696     if (isMessage = msgBase->isMessage())
01697     {
01698       msg = static_cast<KMMessage*>(msgBase);
01699     } else {
01700       idx = srcFolder->find(msgBase);
01701       assert(idx != -1);
01702       msg = srcFolder->getMsg(idx);
01703     }
01704 
01705     if (srcFolder &&
01706         (srcFolder->folderType()== KMFolderTypeImap) &&
01707         (mDestFolder->folderType() == KMFolderTypeImap) &&
01708         (static_cast<KMFolderImap*>(srcFolder->storage())->account() ==
01709          static_cast<KMFolderImap*>(mDestFolder->storage())->account()))
01710     {
01711       list.append(msg);
01712     } else {
01713       newMsg = new KMMessage;
01714       newMsg->setComplete(msg->isComplete());
01715       // make sure the attachment state is only calculated when it's complete
01716       if (!newMsg->isComplete())
01717         newMsg->setReadyToShow(false);
01718       newMsg->fromString(msg->asString());
01719       newMsg->setStatus(msg->status());
01720 
01721       if (srcFolder && !newMsg->isComplete())
01722       {
01723         newMsg->setParent(msg->parent());
01724         FolderJob *job = srcFolder->createJob(newMsg);
01725         job->setCancellable( false );
01726         connect(job, SIGNAL(messageRetrieved(KMMessage*)),
01727                 mDestFolder, SLOT(reallyAddCopyOfMsg(KMMessage*)));
01728         // msg musn't be deleted
01729         newMsg->setTransferInProgress(true);
01730         job->start();
01731       } else {
01732         int rc, index;
01733         mDestFolder->open();
01734         rc = mDestFolder->addMsg(newMsg, &index);
01735         if (rc == 0 && index != -1)
01736           mDestFolder->unGetMsg( mDestFolder->count() - 1 );
01737         mDestFolder->close();
01738       }
01739     }
01740 
01741     if (!isMessage && list.isEmpty())
01742     {
01743       assert(idx != -1);
01744       srcFolder->unGetMsg( idx );
01745     }
01746 
01747   } // end for
01748   mDestFolder->close();
01749 
01750 //TODO: Get rid of the other cases just use this one for all types of folder
01751 //TODO: requires adding copyMsg and getFolder methods to KMFolder.h
01752 
01753   if (!list.isEmpty())
01754   {
01755     // copy the message(s); note: the list is empty afterwards!
01756     KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
01757     imapDestFolder->copyMsg(list);
01758     imapDestFolder->getFolder();
01759   }
01760 
01761   return OK;
01762 }
01763 
01764 
01765 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01766                               const QPtrList<KMMsgBase> &msgList)
01767   :mDestFolder( destFolder ), mMsgList( msgList ), mProgressItem( 0 )
01768 {
01769   setDeletesItself( true );
01770 }
01771 
01772 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01773                               KMMessage *msg )
01774   :mDestFolder( destFolder ), mProgressItem( 0 )
01775 {
01776   setDeletesItself( true );
01777   mMsgList.append( &msg->toMsgBase() );
01778 }
01779 
01780 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01781                               KMMsgBase *msgBase )
01782   :mDestFolder( destFolder ), mProgressItem( 0 )
01783 {
01784   setDeletesItself( true );
01785   mMsgList.append( msgBase );
01786 }
01787 
01788 KMMoveCommand::KMMoveCommand( Q_UINT32 )
01789 :mProgressItem( 0 )
01790 {
01791   setDeletesItself( true );
01792 }
01793 
01794 KMCommand::Result KMMoveCommand::execute()
01795 {
01796   setEmitsCompletedItself( true );
01797   typedef QMap< KMFolder*, QPtrList<KMMessage>* > FolderToMessageListMap;
01798   FolderToMessageListMap folderDeleteList;
01799 
01800   if (mDestFolder && mDestFolder->open() != 0) {
01801     completeMove( Failed );
01802     return Failed;
01803   }
01804   KCursorSaver busy(KBusyPtr::busy());
01805 
01806   // TODO set SSL state according to source and destfolder connection?
01807   Q_ASSERT( !mProgressItem );
01808   mProgressItem =
01809      ProgressManager::createProgressItem (
01810          "move"+ProgressManager::getUniqueID(),
01811          mDestFolder ? i18n( "Moving messages" ) : i18n( "Deleting messages" ) );
01812   connect( mProgressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
01813            this, SLOT( slotMoveCanceled() ) );
01814 
01815   KMMessage *msg;
01816   KMMsgBase *msgBase;
01817   int rc = 0;
01818   int index;
01819   QPtrList<KMMessage> list;
01820   int undoId = -1;
01821 
01822   if (mDestFolder) {
01823     connect (mDestFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
01824              this, SLOT(slotMsgAddedToDestFolder(KMFolder*, Q_UINT32)));
01825 
01826   }
01827   for ( msgBase=mMsgList.first(); msgBase; msgBase=mMsgList.next() ) {
01828     mLostBoys.append( msgBase->getMsgSerNum() );
01829   }
01830   mProgressItem->setTotalItems( mMsgList.count() );
01831 
01832   for (msgBase=mMsgList.first(); msgBase && !rc; msgBase=mMsgList.next()) {
01833     KMFolder *srcFolder = msgBase->parent();
01834     if (srcFolder == mDestFolder)
01835       continue;
01836     bool undo = msgBase->enableUndo();
01837     int idx = srcFolder->find(msgBase);
01838     assert(idx != -1);
01839     if ( msgBase->isMessage() )
01840       msg = static_cast<KMMessage*>(msgBase);
01841     else
01842       msg = srcFolder->getMsg(idx);
01843 
01844     if ( msg->transferInProgress() &&
01845          srcFolder->folderType() == KMFolderTypeImap )
01846     {
01847       // cancel the download
01848       msg->setTransferInProgress( false, true );
01849       static_cast<KMFolderImap*>(srcFolder->storage())->ignoreJobsForMessage( msg );
01850     }
01851 
01852     if (mDestFolder) {
01853       if (mDestFolder->folderType() == KMFolderTypeImap) {
01854         /* If we are moving to an imap folder, connect to it's completed
01855          * signal so we notice when all the mails should have showed up in it
01856          * but haven't for some reason. */
01857         KMFolderImap *imapFolder = static_cast<KMFolderImap*> ( mDestFolder->storage() );
01858         disconnect (imapFolder, SIGNAL(folderComplete( KMFolderImap*, bool )),
01859                  this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
01860 
01861         connect (imapFolder, SIGNAL(folderComplete( KMFolderImap*, bool )),
01862                  this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
01863         list.append(msg);
01864       } else {
01865         // We are moving to a local folder.
01866         mDestFolder->open();
01867         rc = mDestFolder->moveMsg(msg, &index);
01868         if (rc == 0 && index != -1) {
01869           KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 );
01870           if (undo && mb)
01871           {
01872             if ( undoId == -1 )
01873               undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder );
01874             kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() );
01875           }
01876           mDestFolder->close();
01877         } else if (rc != 0) {
01878           // Something  went wrong. Stop processing here, it is likely that the
01879           // other moves would fail as well.
01880           completeMove( Failed );
01881           mDestFolder->close();
01882           return Failed;
01883         }
01884       }
01885     } else {
01886       // really delete messages that are already in the trash folder or if
01887       // we are really, really deleting, not just moving to trash
01888       if (srcFolder->folderType() == KMFolderTypeImap) {
01889         if (!folderDeleteList[srcFolder])
01890           folderDeleteList[srcFolder] = new QPtrList<KMMessage>;
01891         folderDeleteList[srcFolder]->append( msg );
01892       } else {
01893         srcFolder->removeMsg(idx);
01894         delete msg;
01895       }
01896     }
01897   }
01898   if (!list.isEmpty() && mDestFolder) {
01899        mDestFolder->moveMsg(list, &index);
01900   } else {
01901     FolderToMessageListMap::Iterator it;
01902     for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
01903       it.key()->removeMsg(*it.data());
01904       delete it.data();
01905     }
01906     /* The list is empty, which means that either all messages were to be
01907      * deleted, which is done above, or all of them were already in this folder.
01908      * In both cases make sure a completed() signal is emitted nonetheless. */
01909     KMFolder *srcFolder = 0;
01910     if ( mMsgList.first() ) {
01911       srcFolder = mMsgList.first()->parent();
01912       if ( mDestFolder && mDestFolder == srcFolder ) {
01913         completeMove( OK );
01914       }
01915     }
01916     if ( !mDestFolder ) {
01917       completeMove( OK );
01918     }
01919   }
01920 
01921   return OK;
01922 }
01923 
01924 void KMMoveCommand::slotImapFolderCompleted(KMFolderImap *, bool success)
01925 {
01926   if ( success ) {
01927     // the folder was checked successfully but we were still called, so check
01928     // if we are still waiting for messages to show up. If so, uidValidity
01929     // changed, or something else went wrong. Clean up.
01930 
01931     /* Unfortunately older UW imap servers change uid validity for each put job.
01932      * Yes, it is really that broken. *sigh* So we cannot report error here, I guess. */
01933     if ( !mLostBoys.isEmpty() ) {
01934       kdDebug(5006) <<  "### Not all moved messages reported back that they were " << endl
01935                     <<  "### added to the target folder. Did uidValidity change? " << endl;
01936     }
01937     completeMove( OK );
01938   } else {
01939     // Should we inform the user here or leave that to the caller?
01940     completeMove( Failed );
01941   }
01942 }
01943 
01944 void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, Q_UINT32 serNum)
01945 {
01946   if (folder != mDestFolder || !mLostBoys.contains( serNum ) ) {
01947     kdDebug(5006) << "KMMoveCommand::msgAddedToDestFolder different "
01948                      "folder or invalid serial number." << endl;
01949     return;
01950   }
01951   mLostBoys.remove(serNum);
01952   if ( mLostBoys.isEmpty() ) {
01953     // we are done. All messages transferred to the host succesfully
01954     if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) {
01955       mDestFolder->sync();
01956     }
01957     completeMove( OK );
01958   } else {
01959     mProgressItem->incCompletedItems();
01960     mProgressItem->updateProgress();
01961   }
01962 }
01963 
01964 void KMMoveCommand::completeMove( Result result )
01965 {
01966   if ( mDestFolder )
01967     mDestFolder->close();
01968   while ( !mOpenedFolders.empty() ) {
01969     KMFolder *folder = mOpenedFolders.back();
01970     mOpenedFolders.pop_back();
01971     folder->close();
01972   }
01973   if ( mProgressItem )
01974     mProgressItem->setComplete();
01975   setResult( result );
01976   emit completed( this );
01977   deleteLater();
01978 }
01979 
01980 void KMMoveCommand::slotMoveCanceled()
01981 {
01982   completeMove( Canceled );
01983 }
01984 
01985 // srcFolder doesn't make much sense for searchFolders
01986 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder,
01987   const QPtrList<KMMsgBase> &msgList )
01988 :KMMoveCommand( findTrashFolder( srcFolder ), msgList)
01989 {
01990   srcFolder->open();
01991   mOpenedFolders.push_back( srcFolder );
01992 }
01993 
01994 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
01995 :KMMoveCommand( findTrashFolder( srcFolder ), msg)
01996 {
01997   srcFolder->open();
01998   mOpenedFolders.push_back( srcFolder );
01999 }
02000 
02001 KMDeleteMsgCommand::KMDeleteMsgCommand( Q_UINT32 sernum )
02002 :KMMoveCommand( sernum )
02003 {
02004   KMFolder *srcFolder;
02005   int idx;
02006   kmkernel->msgDict()->getLocation( sernum, &srcFolder, &idx );
02007   KMMsgBase *msg = srcFolder->getMsgBase( idx );
02008   srcFolder->open();
02009   mOpenedFolders.push_back( srcFolder );
02010   addMsg( msg );
02011   setDestFolder( findTrashFolder( srcFolder ) );
02012 }
02013 
02014 KMFolder * KMDeleteMsgCommand::findTrashFolder( KMFolder * folder )
02015 {
02016   KMFolder* trash = folder->trashFolder();
02017   if( !trash )
02018     trash = kmkernel->trashFolder();
02019   if( trash != folder )
02020     return trash;
02021   return 0;
02022 }
02023 
02024 
02025 KMUrlClickedCommand::KMUrlClickedCommand( const KURL &url, uint identity,
02026   KMReaderWin *readerWin, bool htmlPref, KMMainWidget *mainWidget )
02027   :mUrl( url ), mIdentity( identity ), mReaderWin( readerWin ),
02028    mHtmlPref( htmlPref ), mMainWidget( mainWidget )
02029 {
02030 }
02031 
02032 KMCommand::Result KMUrlClickedCommand::execute()
02033 {
02034   KMComposeWin *win;
02035   KMMessage* msg;
02036 
02037   if (mUrl.protocol() == "mailto")
02038   {
02039     msg = new KMMessage;
02040     msg->initHeader(mIdentity);
02041     msg->setCharset("utf-8");
02042     msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
02043     QString query=mUrl.query();
02044     while (!query.isEmpty()) {
02045       QString queryPart;
02046       int secondQuery = query.find('?',1);
02047       if (secondQuery != -1)
02048         queryPart = query.left(secondQuery);
02049       else
02050         queryPart = query;
02051       query = query.mid(queryPart.length());
02052 
02053       if (queryPart.left(9) == "?subject=")
02054         msg->setSubject( KURL::decode_string(queryPart.mid(9)) );
02055       else if (queryPart.left(6) == "?body=")
02056         // It is correct to convert to latin1() as URL should not contain
02057         // anything except ascii.
02058         msg->setBody( KURL::decode_string(queryPart.mid(6)).latin1() );
02059       else if (queryPart.left(4) == "?cc=")
02060         msg->setCc( KURL::decode_string(queryPart.mid(4)) );
02061     }
02062 
02063     win = new KMComposeWin(msg, mIdentity);
02064     win->setCharset("", TRUE);
02065     win->show();
02066   }
02067   else if ( mUrl.protocol() == "im" )
02068   {
02069     kmkernel->imProxy()->chatWithContact( mUrl.path() );
02070   }
02071   else if ((mUrl.protocol() == "http") || (mUrl.protocol() == "https") ||
02072            (mUrl.protocol() == "ftp") || (mUrl.protocol() == "file") ||
02073            (mUrl.protocol() == "ftps") || (mUrl.protocol() == "sftp" ) ||
02074            (mUrl.protocol() == "help") || (mUrl.protocol() == "vnc") ||
02075            (mUrl.protocol() == "smb"))
02076   {
02077     KPIM::BroadcastStatus::instance()->setStatusMsg( i18n("Opening URL..."));
02078     KMimeType::Ptr mime = KMimeType::findByURL( mUrl );
02079     if (mime->name() == "application/x-desktop" ||
02080         mime->name() == "application/x-executable" ||
02081         mime->name() == "application/x-msdos-program" ||
02082         mime->name() == "application/x-shellscript" )
02083     {
02084       if (KMessageBox::warningYesNo( 0, i18n( "<qt>Do you really want to execute <b>%1</b>?</qt>" )
02085         .arg( mUrl.prettyURL() ) ) != KMessageBox::Yes)
02086         return Canceled;
02087     }
02088     (void) new KRun( mUrl );
02089   }
02090   else
02091     return Failed;
02092 
02093   return OK;
02094 }
02095 
02096 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, KMMessage *msg )
02097   : KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
02098 {
02099 }
02100 
02101 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, const QPtrList<KMMsgBase>& msgs )
02102   : KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
02103 {
02104 }
02105 
02106 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, QPtrList<partNode>& attachments,
02107                                                     KMMessage *msg, bool encoded )
02108   : KMCommand( parent, msg ), mImplicitAttachments( false ),
02109     mEncoded( encoded )
02110 {
02111   // do not load the complete message but only parts
02112   msg->setComplete( true );
02113   for ( QPtrListIterator<partNode> it( attachments ); it.current(); ++it ) {
02114     mAttachmentMap.insert( it.current(), msg );
02115   }
02116 }
02117 
02118 KMCommand::Result KMSaveAttachmentsCommand::execute()
02119 {
02120   setEmitsCompletedItself( true );
02121   if ( mImplicitAttachments ) {
02122     QPtrList<KMMessage> msgList = retrievedMsgs();
02123     KMMessage *msg;
02124     for ( QPtrListIterator<KMMessage> itr( msgList );
02125           ( msg = itr.current() );
02126           ++itr ) {
02127       partNode *rootNode = partNode::fromMessage( msg );
02128       for ( partNode *child = rootNode; child;
02129             child = child->firstChild() ) {
02130         for ( partNode *node = child; node; node = node->nextSibling() ) {
02131           if ( node->type() != DwMime::kTypeMultipart )
02132             mAttachmentMap.insert( node, msg );
02133         }
02134       }
02135     }
02136   }
02137   setDeletesItself( true );
02138   // load all parts
02139   KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachmentMap );
02140   connect( command, SIGNAL( partsRetrieved() ),
02141            this, SLOT( slotSaveAll() ) );
02142   command->start();
02143 
02144   return OK;
02145 }
02146 
02147 void KMSaveAttachmentsCommand::slotSaveAll()
02148 {
02149   // now that all message parts have been retrieved, remove all parts which
02150   // don't represent an attachment if they were not explicitely passed in the
02151   // c'tor
02152   if ( mImplicitAttachments ) {
02153     for ( PartNodeMessageMap::iterator it = mAttachmentMap.begin();
02154           it != mAttachmentMap.end(); ) {
02155       // only body parts which have a filename or a name parameter (except for
02156       // the root node for which name is set to the message's subject) are
02157       // considered attachments
02158       if ( it.key()->msgPart().fileName().stripWhiteSpace().isEmpty() &&
02159            ( it.key()->msgPart().name().stripWhiteSpace().isEmpty() ||
02160              !it.key()->parentNode() ) ) {
02161         PartNodeMessageMap::iterator delIt = it;
02162         ++it;
02163         mAttachmentMap.remove( delIt );
02164       }
02165       else
02166         ++it;
02167     }
02168     if ( mAttachmentMap.isEmpty() ) {
02169       KMessageBox::information( 0, i18n("Found no attachments to save.") );
02170       setResult( OK ); // The user has already been informed.
02171       emit completed( this );
02172       deleteLater();
02173       return;
02174     }
02175   }
02176 
02177   KURL url, dirUrl;
02178   if ( mAttachmentMap.count() > 1 ) {
02179     // get the dir
02180     KFileDialog fdlg( ":saveAttachments", QString::null, parentWidget(),
02181                       "save attachments dialog", true );
02182     fdlg.setCaption( i18n("Save Attachments To") );
02183     fdlg.setOperationMode( KFileDialog::Saving );
02184     fdlg.setMode( (unsigned int) KFile::Directory );
02185     if ( fdlg.exec() == QDialog::Rejected || !fdlg.selectedURL().isValid() ) {
02186       setResult( Canceled );
02187       emit completed( this );
02188       deleteLater();
02189       return;
02190     }
02191     dirUrl = fdlg.selectedURL();
02192   }
02193   else {
02194     // only one item, get the desired filename
02195     partNode *node = mAttachmentMap.begin().key();
02196     // replace all ':' with '_' because ':' isn't allowed on FAT volumes
02197     QString s =
02198       node->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
02199     if ( s.isEmpty() )
02200       s = node->msgPart().name().stripWhiteSpace().replace( ':', '_' );
02201     if ( s.isEmpty() )
02202       s = i18n("filename for an unnamed attachment", "attachment.1");
02203     url = KFileDialog::getSaveURL( s, QString::null, parentWidget(),
02204                                    QString::null );
02205     if ( url.isEmpty() ) {
02206       setResult( Canceled );
02207       emit completed( this );
02208       deleteLater();
02209       return;
02210     }
02211   }
02212 
02213   Result globalResult = OK;
02214   int unnamedAtmCount = 0;
02215   for ( PartNodeMessageMap::const_iterator it = mAttachmentMap.begin();
02216         it != mAttachmentMap.end();
02217         ++it ) {
02218     KURL curUrl;
02219     if ( !dirUrl.isEmpty() ) {
02220       curUrl = dirUrl;
02221       QString s =
02222         it.key()->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
02223       if ( s.isEmpty() )
02224         s = it.key()->msgPart().name().stripWhiteSpace().replace( ':', '_' );
02225       if ( s.isEmpty() ) {
02226         ++unnamedAtmCount;
02227         s = i18n("filename for the %1-th unnamed attachment",
02228                  "attachment.%1")
02229             .arg( unnamedAtmCount );
02230       }
02231       curUrl.setFileName( s );
02232     } else {
02233       curUrl = url;
02234     }
02235 
02236     if ( !curUrl.isEmpty() ) {
02237       if ( KIO::NetAccess::exists( curUrl, false, parentWidget() ) ) {
02238         if ( KMessageBox::warningContinueCancel( parentWidget(),
02239               i18n( "A file named %1 already exists. Do you want to overwrite it?" )
02240               .arg( curUrl.fileName() ),
02241               i18n( "File Already Exists" ), i18n("Overwrite") ) == KMessageBox::Cancel) {
02242           continue;
02243         }
02244       }
02245       // save
02246       const Result result = saveItem( it.key(), curUrl );
02247       if ( result != OK )
02248         globalResult = result;
02249     }
02250   }
02251   setResult( globalResult );
02252   emit completed( this );
02253   deleteLater();
02254 }
02255 
02256 KMCommand::Result KMSaveAttachmentsCommand::saveItem( partNode *node,
02257                                                       const KURL& url )
02258 {
02259   bool bSaveEncrypted = false;
02260   bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted;
02261   if( bEncryptedParts )
02262     if( KMessageBox::questionYesNo( parentWidget(),
02263           i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?" ).
02264           arg( url.fileName() ),
02265           i18n( "KMail Question" ) ) ==
02266         KMessageBox::Yes )
02267       bSaveEncrypted = true;
02268 
02269   bool bSaveWithSig = true;
02270   if( node->signatureState() != KMMsgNotSigned )
02271     if( KMessageBox::questionYesNo( parentWidget(),
02272           i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?" ).
02273           arg( url.fileName() ),
02274           i18n( "KMail Question" ) ) !=
02275         KMessageBox::Yes )
02276       bSaveWithSig = false;
02277 
02278   QByteArray data;
02279   if ( mEncoded )
02280   {
02281     // This does not decode the Message Content-Transfer-Encoding
02282     // but saves the _original_ content of the message part
02283     QCString cstr( node->msgPart().body() );
02284     data = cstr;
02285     data.resize(data.size() - 1);
02286   }
02287   else
02288   {
02289     if( bSaveEncrypted || !bEncryptedParts) {
02290       partNode *dataNode = node;
02291       QCString rawReplyString;
02292       bool gotRawReplyString = false;
02293       if( !bSaveWithSig ) {
02294         if( DwMime::kTypeMultipart == node->type() &&
02295             DwMime::kSubtypeSigned == node->subType() ){
02296           // carefully look for the part that is *not* the signature part:
02297           if( node->findType( DwMime::kTypeApplication,
02298                 DwMime::kSubtypePgpSignature,
02299                 TRUE, false ) ){
02300             dataNode = node->findTypeNot( DwMime::kTypeApplication,
02301                 DwMime::kSubtypePgpSignature,
02302                 TRUE, false );
02303           }else if( node->findType( DwMime::kTypeApplication,
02304                 DwMime::kSubtypePkcs7Mime,
02305                 TRUE, false ) ){
02306             dataNode = node->findTypeNot( DwMime::kTypeApplication,
02307                 DwMime::kSubtypePkcs7Mime,
02308                 TRUE, false );
02309           }else{
02310             dataNode = node->findTypeNot( DwMime::kTypeMultipart,
02311                 DwMime::kSubtypeUnknown,
02312                 TRUE, false );
02313           }
02314     }else{
02315       ObjectTreeParser otp( 0, 0, false, false, false );
02316 
02317       // process this node and all it's siblings and descendants
02318       dataNode->setProcessed( false, true );
02319       otp.parseObjectTree( dataNode );
02320 
02321       rawReplyString = otp.rawReplyString();
02322       gotRawReplyString = true;
02323         }
02324       }
02325       QByteArray cstr = gotRawReplyString
02326                          ? rawReplyString
02327                          : dataNode->msgPart().bodyDecodedBinary();
02328       data = cstr;
02329       size_t size = cstr.size();
02330       if ( dataNode->msgPart().type() == DwMime::kTypeText ) {
02331         // convert CRLF to LF before writing text attachments to disk
02332         size = KMFolder::crlf2lf( cstr.data(), size );
02333       }
02334       data.resize( size );
02335     }
02336   }
02337   QDataStream ds;
02338   QFile file;
02339   KTempFile tf;
02340   tf.setAutoDelete( true );
02341   if ( url.isLocalFile() )
02342   {
02343     // save directly
02344     file.setName( url.path() );
02345     if ( !file.open( IO_WriteOnly ) )
02346     {
02347       KMessageBox::error( parentWidget(),
02348           i18n( "%2 is detailed error description",
02349             "Could not write the file %1:\n%2" )
02350           .arg( file.name() )
02351           .arg( QString::fromLocal8Bit( strerror( errno ) ) ),
02352           i18n( "KMail Error" ) );
02353       return Failed;
02354     }
02355     // Don't attempt the below, it causes issues on nfs, among other things
02356     // https://intevation.de/roundup/kolab/issue856
02357     //fchmod( file.handle(), S_IRUSR | S_IWUSR );
02358     ds.setDevice( &file );
02359   } else
02360   {
02361     // tmp file for upload
02362     ds.setDevice( tf.file() );
02363   }
02364 
02365   ds.writeRawBytes( data.data(), data.size() );
02366   if ( !url.isLocalFile() )
02367   {
02368     tf.close();
02369     if ( !KIO::NetAccess::upload( tf.name(), url, parentWidget() ) )
02370     {
02371       KMessageBox::error( parentWidget(),
02372           i18n( "Could not write the file %1." )
02373           .arg( url.path() ),
02374           i18n( "KMail Error" ) );
02375       return Failed;
02376     }
02377   } else
02378     file.close();
02379   return OK;
02380 }
02381 
02382 KMLoadPartsCommand::KMLoadPartsCommand( QPtrList<partNode>& parts, KMMessage *msg )
02383   : mNeedsRetrieval( 0 )
02384 {
02385   for ( QPtrListIterator<partNode> it( parts ); it.current(); ++it ) {
02386     mPartMap.insert( it.current(), msg );
02387   }
02388 }
02389 
02390 KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
02391   : mNeedsRetrieval( 0 )
02392 {
02393   mPartMap.insert( node, msg );
02394 }
02395 
02396 KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
02397   : mNeedsRetrieval( 0 ), mPartMap( partMap )
02398 {
02399 }
02400 
02401 void KMLoadPartsCommand::slotStart()
02402 {
02403   for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
02404         it != mPartMap.end();
02405         ++it ) {
02406     if ( !it.key()->msgPart().isComplete() &&
02407          !it.key()->msgPart().partSpecifier().isEmpty() ) {
02408       // incomplete part, so retrieve it first
02409       ++mNeedsRetrieval;
02410       KMFolder* curFolder = it.data()->parent();
02411       if ( curFolder ) {
02412         FolderJob *job =
02413           curFolder->createJob( it.data(), FolderJob::tGetMessage,
02414                                 0, it.key()->msgPart().partSpecifier() );
02415         job->setCancellable( false );
02416         connect( job, SIGNAL(messageUpdated(KMMessage*, QString)),
02417                  this, SLOT(slotPartRetrieved(KMMessage*, QString)) );
02418         job->start();
02419       } else
02420         kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl;
02421     }
02422   }
02423   if ( mNeedsRetrieval == 0 )
02424     execute();
02425 }
02426 
02427 void KMLoadPartsCommand::slotPartRetrieved( KMMessage *msg,
02428                                             QString partSpecifier )
02429 {
02430   DwBodyPart *part =
02431     msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier );
02432   if ( part ) {
02433     // update the DwBodyPart in the partNode
02434     for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
02435           it != mPartMap.end();
02436           ++it ) {
02437       if ( it.key()->dwPart()->partId() == part->partId() )
02438         it.key()->setDwPart( part );
02439     }
02440   } else
02441     kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl;
02442   --mNeedsRetrieval;
02443   if ( mNeedsRetrieval == 0 )
02444     execute();
02445 }
02446 
02447 KMCommand::Result KMLoadPartsCommand::execute()
02448 {
02449   emit partsRetrieved();
02450   setResult( OK );
02451   emit completed( this );
02452   deleteLater();
02453   return OK;
02454 }
02455 
02456 KMResendMessageCommand::KMResendMessageCommand( QWidget *parent,
02457    KMMessage *msg )
02458   :KMCommand( parent, msg )
02459 {
02460 }
02461 
02462 KMCommand::Result KMResendMessageCommand::execute()
02463 {
02464   KMComposeWin *win;
02465   KMMessage *msg = retrievedMessage();
02466 
02467   KMMessage *newMsg = new KMMessage(*msg);
02468   newMsg->setCharset(msg->codec()->mimeName());
02469   // the message needs a new Message-Id
02470   newMsg->removeHeaderField( "Message-Id" );
02471   newMsg->setParent( 0 );
02472 
02473   // adds the new date to the message
02474   newMsg->removeHeaderField( "Date" );
02475 
02476   win = new KMComposeWin();
02477   win->setMsg(newMsg, false, true);
02478   win->show();
02479 
02480   return OK;
02481 }
02482 
02483 KMMailingListCommand::KMMailingListCommand( QWidget *parent, KMFolder *folder )
02484   : KMCommand( parent ), mFolder( folder )
02485 {
02486 }
02487 
02488 KMCommand::Result KMMailingListCommand::execute()
02489 {
02490   KURL::List lst = urls();
02491   QString handler = ( mFolder->mailingList().handler() == MailingList::KMail )
02492     ? "mailto" : "https";
02493 
02494   KMCommand *command = 0;
02495   for ( KURL::List::Iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
02496     if ( handler == (*itr).protocol() ) {
02497       command = new KMUrlClickedCommand( *itr, mFolder->identity(), 0, false );
02498     }
02499   }
02500   if ( !command && !lst.empty() ) {
02501     command =
02502       new KMUrlClickedCommand( lst.first(), mFolder->identity(), 0, false );
02503   }
02504   if ( command ) {
02505     connect( command, SIGNAL( completed( KMCommand * ) ),
02506              this, SLOT( commandCompleted( KMCommand * ) ) );
02507     setDeletesItself( true );
02508     setEmitsCompletedItself( true );
02509     command->start();
02510     return OK;
02511   }
02512   return Failed;
02513 }
02514 
02515 void KMMailingListCommand::commandCompleted( KMCommand *command )
02516 {
02517   setResult( command->result() );
02518   emit completed( this );
02519   deleteLater();
02520 }
02521 
02522 KMMailingListPostCommand::KMMailingListPostCommand( QWidget *parent, KMFolder *folder )
02523   : KMMailingListCommand( parent, folder )
02524 {
02525 }
02526 KURL::List KMMailingListPostCommand::urls() const
02527 {
02528   return mFolder->mailingList().postURLS();
02529 }
02530 
02531 KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( QWidget *parent, KMFolder *folder )
02532   : KMMailingListCommand( parent, folder )
02533 {
02534 }
02535 KURL::List KMMailingListSubscribeCommand::urls() const
02536 {
02537   return mFolder->mailingList().subscribeURLS();
02538 }
02539 
02540 KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( QWidget *parent, KMFolder *folder )
02541   : KMMailingListCommand( parent, folder )
02542 {
02543 }
02544 KURL::List KMMailingListUnsubscribeCommand::urls() const
02545 {
02546   return mFolder->mailingList().unsubscribeURLS();
02547 }
02548 
02549 KMMailingListArchivesCommand::KMMailingListArchivesCommand( QWidget *parent, KMFolder *folder )
02550   : KMMailingListCommand( parent, folder )
02551 {
02552 }
02553 KURL::List KMMailingListArchivesCommand::urls() const
02554 {
02555   return mFolder->mailingList().archiveURLS();
02556 }
02557 
02558 KMMailingListHelpCommand::KMMailingListHelpCommand( QWidget *parent, KMFolder *folder )
02559   : KMMailingListCommand( parent, folder )
02560 {
02561 }
02562 KURL::List KMMailingListHelpCommand::urls() const
02563 {
02564   return mFolder->mailingList().helpURLS();
02565 }
02566 
02567 KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
02568   :mUrl( url ), mMessage( msg )
02569 {
02570 }
02571 
02572 KMCommand::Result KMIMChatCommand::execute()
02573 {
02574   kdDebug( 5006 ) << k_funcinfo << " URL is: " << mUrl << endl;
02575   // find UID for mail address
02576   KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
02577   KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getEmailAddr( mUrl.path() ) ) ;
02578 
02579   // start chat
02580   if( addresses.count() == 1 ) {
02581     kmkernel->imProxy()->chatWithContact( addresses[0].uid() );
02582     return OK;
02583   }
02584   else
02585   {
02586     kdDebug( 5006 ) << "Didn't find exactly one addressee, couldn't tell who to chat to for that email address.  Count = " << addresses.count() << endl;
02587 
02588     QString apology;
02589     if ( addresses.isEmpty() )
02590       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." );
02591     else
02592     {
02593       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." );
02594       QStringList nameList;
02595       KABC::AddresseeList::const_iterator it = addresses.begin();
02596       KABC::AddresseeList::const_iterator end = addresses.end();
02597       for ( ; it != end; ++it )
02598       {
02599           nameList.append( (*it).realName() );
02600       }
02601       QString names = nameList.join( QString::fromLatin1( ",\n" ) );
02602       apology = apology.arg( names );
02603     }
02604 
02605     KMessageBox::sorry( parentWidget(), apology );
02606     return Failed;
02607   }
02608 }
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 17 09:55:25 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003