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     mOffset( 0 ),
00724     mTotalSize( msg ? msg->msgSize() : 0 )
00725 {
00726   if ( !msg ) return;
00727   setDeletesItself( true );
00728   mMsgList.append( msg->getMsgSerNum() );
00729   mUrl = subjectToUrl( msg->cleanSubject() );
00730 }
00731 
00732 KMSaveMsgCommand::KMSaveMsgCommand( QWidget *parent,
00733                                     const QPtrList<KMMsgBase> &msgList )
00734   : KMCommand( parent ),
00735     mMsgListIndex( 0 ),
00736     mOffset( 0 ),
00737     mTotalSize( 0 )
00738 {
00739   if (!msgList.getFirst())
00740     return;
00741   setDeletesItself( true );
00742   KMMsgBase *msgBase = msgList.getFirst();
00743 
00744   // We operate on serNums and not the KMMsgBase pointers, as those can
00745   // change, or become invalid when changing the current message, switching
00746   // folders, etc.
00747   QPtrListIterator<KMMsgBase> it(msgList);
00748   while ( it.current() ) {
00749     mMsgList.append( (*it)->getMsgSerNum() );
00750     mTotalSize += (*it)->msgSize();
00751     if ((*it)->parent() != 0)
00752       (*it)->parent()->open();
00753     ++it;
00754   }
00755   mMsgListIndex = 0;
00756   mUrl = subjectToUrl( msgBase->cleanSubject() );
00757 }
00758 
00759 KURL KMSaveMsgCommand::url()
00760 {
00761   return mUrl;
00762 }
00763 
00764 KMCommand::Result KMSaveMsgCommand::execute()
00765 {
00766   mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, false, false );
00767   mJob->slotTotalSize( mTotalSize );
00768   mJob->setAsyncDataEnabled( true );
00769   mJob->setReportDataSent( true );
00770   connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)),
00771     SLOT(slotSaveDataReq()));
00772   connect(mJob, SIGNAL(result(KIO::Job*)),
00773     SLOT(slotSaveResult(KIO::Job*)));
00774   setEmitsCompletedItself( true );
00775   return OK;
00776 }
00777 
00778 void KMSaveMsgCommand::slotSaveDataReq()
00779 {
00780   int remainingBytes = mData.size() - mOffset;
00781   if ( remainingBytes > 0 ) {
00782     // eat leftovers first
00783     if ( remainingBytes > MAX_CHUNK_SIZE )
00784       remainingBytes = MAX_CHUNK_SIZE;
00785 
00786     QByteArray data;
00787     data.duplicate( mData.data() + mOffset, remainingBytes );
00788     mJob->sendAsyncData( data );
00789     mOffset += remainingBytes;
00790     return;
00791   }
00792   // No leftovers, process next message.
00793   if ( mMsgListIndex < mMsgList.size() ) {
00794     KMMessage *msg = 0;
00795     int idx = -1;
00796     KMFolder * p = 0;
00797     kmkernel->msgDict()->getLocation( mMsgList[mMsgListIndex], &p, &idx );
00798     assert( p );
00799     assert( idx >= 0 );
00800     msg = p->getMsg(idx);
00801 
00802     if (msg->transferInProgress()) {
00803       QByteArray data = QByteArray();
00804       mJob->sendAsyncData( data );
00805     }
00806     msg->setTransferInProgress( true );
00807     if (msg->isComplete() ) {
00808       slotMessageRetrievedForSaving(msg);
00809     } else {
00810       // retrieve Message first
00811       if (msg->parent()  && !msg->isComplete() ) {
00812         FolderJob *job = msg->parent()->createJob(msg);
00813         job->setCancellable( false );
00814         connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00815             this, SLOT(slotMessageRetrievedForSaving(KMMessage*)));
00816         job->start();
00817       }
00818     }
00819   } else {
00820     // No more messages. Tell the putjob we are done.
00821     QByteArray data = QByteArray();
00822     mJob->sendAsyncData( data );
00823   }
00824 }
00825 
00826 void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg)
00827 {
00828   QCString str( msg->mboxMessageSeparator() );
00829   str += KMFolderMbox::escapeFrom( msg->asString() );
00830   str += "\n";
00831   msg->setTransferInProgress(false);
00832 
00833   mData = str;
00834   mData.resize(mData.size() - 1);
00835   mOffset = 0;
00836   QByteArray data;
00837   int size;
00838   // Unless it is great than 64 k send the whole message. kio buffers for us.
00839   if( mData.size() > (unsigned int) MAX_CHUNK_SIZE )
00840     size = MAX_CHUNK_SIZE;
00841   else
00842     size = mData.size();
00843 
00844   data.duplicate( mData, size );
00845   mJob->sendAsyncData( data );
00846   mOffset += size;
00847   ++mMsgListIndex;
00848   // Get rid of the message.
00849   if (msg->parent()) {
00850     int idx = -1;
00851     KMFolder * p = 0;
00852     kmkernel->msgDict()->getLocation( msg, &p, &idx );
00853     assert( p == msg->parent() ); assert( idx >= 0 );
00854     p->unGetMsg( idx );
00855     p->close();
00856   }
00857 }
00858 
00859 void KMSaveMsgCommand::slotSaveResult(KIO::Job *job)
00860 {
00861   if (job->error())
00862   {
00863     if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
00864     {
00865       if (KMessageBox::warningContinueCancel(0,
00866         i18n("File %1 exists.\nDo you want to replace it?")
00867         .arg(mUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
00868         == KMessageBox::Continue) {
00869         mOffset = 0;
00870 
00871         mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, true, false );
00872         mJob->slotTotalSize( mTotalSize );
00873         mJob->setAsyncDataEnabled( true );
00874         mJob->setReportDataSent( true );
00875         connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)),
00876             SLOT(slotSaveDataReq()));
00877         connect(mJob, SIGNAL(result(KIO::Job*)),
00878             SLOT(slotSaveResult(KIO::Job*)));
00879       }
00880     }
00881     else
00882     {
00883       job->showErrorDialog();
00884       setResult( Failed );
00885       emit completed( this );
00886       deleteLater();
00887     }
00888   } else {
00889     setResult( OK );
00890     emit completed( this );
00891     deleteLater();
00892   }
00893 }
00894 
00895 //-----------------------------------------------------------------------------
00896 
00897 KMOpenMsgCommand::KMOpenMsgCommand( QWidget *parent, const KURL & url,
00898                                     const QString & encoding )
00899   : KMCommand( parent ),
00900     mUrl( url ),
00901     mEncoding( encoding )
00902 {
00903   setDeletesItself( true );
00904 }
00905 
00906 KMCommand::Result KMOpenMsgCommand::execute()
00907 {
00908   if ( mUrl.isEmpty() ) {
00909     mUrl = KFileDialog::getOpenURL( ":OpenMessage", "message/rfc822",
00910                                     parentWidget(), i18n("Open Message") );
00911   }
00912   if ( mUrl.isEmpty() ) {
00913     setDeletesItself( false );
00914     return Canceled;
00915   }
00916   mJob = KIO::get( mUrl, false, false );
00917   mJob->setReportDataSent( true );
00918   connect( mJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
00919            this, SLOT( slotDataArrived( KIO::Job*, const QByteArray & ) ) );
00920   connect( mJob, SIGNAL( result( KIO::Job * ) ),
00921            SLOT( slotResult( KIO::Job * ) ) );
00922   setEmitsCompletedItself( true );
00923   return OK;
00924 }
00925 
00926 void KMOpenMsgCommand::slotDataArrived( KIO::Job *, const QByteArray & data )
00927 {
00928   if ( data.isEmpty() )
00929     return;
00930 
00931   mMsgString.append( data.data(), data.size() );
00932 }
00933 
00934 void KMOpenMsgCommand::slotResult( KIO::Job *job )
00935 {
00936   if ( job->error() ) {
00937     // handle errors
00938     job->showErrorDialog();
00939     setResult( Failed );
00940     emit completed( this );
00941   }
00942   else {
00943     int startOfMessage = 0;
00944     if ( mMsgString.compare( 0, 5, "From ", 5 ) == 0 ) {
00945       startOfMessage = mMsgString.find( '\n' );
00946       if ( startOfMessage == -1 ) {
00947         KMessageBox::sorry( parentWidget(),
00948                             i18n( "The file doesn't contain a message." ) );
00949         setResult( Failed );
00950         emit completed( this );
00951         // Emulate closing of a secondary window so that KMail exits in case it
00952         // was started with the --view command line option. Otherwise an
00953         // invisible KMail would keep running.
00954         SecondaryWindow *win = new SecondaryWindow();
00955         win->close();
00956         win->deleteLater();
00957         deleteLater();
00958         return;
00959       }
00960       startOfMessage += 1; // the message starts after the '\n'
00961     }
00962     // check for multiple messages in the file
00963     bool multipleMessages = true;
00964     int endOfMessage = mMsgString.find( "\nFrom " );
00965     if ( endOfMessage == -1 ) {
00966       endOfMessage = mMsgString.length();
00967       multipleMessages = false;
00968     }
00969     DwMessage *dwMsg = new DwMessage;
00970     dwMsg->FromString( mMsgString.substr( startOfMessage,
00971                                           endOfMessage - startOfMessage ) );
00972     dwMsg->Parse();
00973     // check whether we have a message ( no headers => this isn't a message )
00974     if ( dwMsg->Headers().NumFields() == 0 ) {
00975       KMessageBox::sorry( parentWidget(),
00976                           i18n( "The file doesn't contain a message." ) );
00977       delete dwMsg; dwMsg = 0;
00978       setResult( Failed );
00979       emit completed( this );
00980       // Emulate closing of a secondary window (see above).
00981       SecondaryWindow *win = new SecondaryWindow();
00982       win->close();
00983       win->deleteLater();
00984       deleteLater();
00985       return;
00986     }
00987     KMMessage *msg = new KMMessage( dwMsg );
00988     msg->setComplete( true );
00989     msg->setReadyToShow( true );
00990     KMReaderMainWin *win = new KMReaderMainWin();
00991     win->showMsg( mEncoding, msg );
00992     win->show();
00993     if ( multipleMessages )
00994       KMessageBox::information( win,
00995                                 i18n( "The file contains multiple messages. "
00996                                       "Only the first message is shown." ) );
00997     setResult( OK );
00998     emit completed( this );
00999   }
01000   deleteLater();
01001 }
01002 
01003 //-----------------------------------------------------------------------------
01004 
01005 //TODO: ReplyTo, NoQuoteReplyTo, ReplyList, ReplyToAll, ReplyAuthor
01006 //      are all similar and should be factored
01007 KMReplyToCommand::KMReplyToCommand( QWidget *parent, KMMessage *msg,
01008                                     const QString &selection )
01009   : KMCommand( parent, msg ), mSelection( selection )
01010 {
01011 }
01012 
01013 KMCommand::Result KMReplyToCommand::execute()
01014 {
01015   KCursorSaver busy(KBusyPtr::busy());
01016   KMMessage *msg = retrievedMessage();
01017   KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection );
01018   KMComposeWin *win = new KMComposeWin( reply );
01019   win->setCharset( msg->codec()->mimeName(), TRUE );
01020   win->setReplyFocus();
01021   win->show();
01022 
01023   return OK;
01024 }
01025 
01026 
01027 KMNoQuoteReplyToCommand::KMNoQuoteReplyToCommand( QWidget *parent,
01028                                                   KMMessage *msg )
01029   : KMCommand( parent, msg )
01030 {
01031 }
01032 
01033 KMCommand::Result KMNoQuoteReplyToCommand::execute()
01034 {
01035   KCursorSaver busy(KBusyPtr::busy());
01036   KMMessage *msg = retrievedMessage();
01037   KMMessage *reply = msg->createReply( KMail::ReplySmart, "", TRUE);
01038   KMComposeWin *win = new KMComposeWin( reply );
01039   win->setCharset(msg->codec()->mimeName(), TRUE);
01040   win->setReplyFocus(false);
01041   win->show();
01042 
01043   return OK;
01044 }
01045 
01046 
01047 KMReplyListCommand::KMReplyListCommand( QWidget *parent,
01048   KMMessage *msg, const QString &selection )
01049  : KMCommand( parent, msg ), mSelection( selection )
01050 {
01051 }
01052 
01053 KMCommand::Result KMReplyListCommand::execute()
01054 {
01055   KCursorSaver busy(KBusyPtr::busy());
01056   KMMessage *msg = retrievedMessage();
01057   KMMessage *reply = msg->createReply( KMail::ReplyList, mSelection);
01058   KMComposeWin *win = new KMComposeWin( reply );
01059   win->setCharset(msg->codec()->mimeName(), TRUE);
01060   win->setReplyFocus(false);
01061   win->show();
01062 
01063   return OK;
01064 }
01065 
01066 
01067 KMReplyToAllCommand::KMReplyToAllCommand( QWidget *parent,
01068   KMMessage *msg, const QString &selection )
01069   :KMCommand( parent, msg ), mSelection( selection )
01070 {
01071 }
01072 
01073 KMCommand::Result KMReplyToAllCommand::execute()
01074 {
01075   KCursorSaver busy(KBusyPtr::busy());
01076   KMMessage *msg = retrievedMessage();
01077   KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection );
01078   KMComposeWin *win = new KMComposeWin( reply );
01079   win->setCharset( msg->codec()->mimeName(), TRUE );
01080   win->setReplyFocus();
01081   win->show();
01082 
01083   return OK;
01084 }
01085 
01086 
01087 KMReplyAuthorCommand::KMReplyAuthorCommand( QWidget *parent, KMMessage *msg,
01088                                             const QString &selection )
01089   : KMCommand( parent, msg ), mSelection( selection )
01090 {
01091 }
01092 
01093 KMCommand::Result KMReplyAuthorCommand::execute()
01094 {
01095   KCursorSaver busy(KBusyPtr::busy());
01096   KMMessage *msg = retrievedMessage();
01097   KMMessage *reply = msg->createReply( KMail::ReplyAuthor, mSelection );
01098   KMComposeWin *win = new KMComposeWin( reply );
01099   win->setCharset( msg->codec()->mimeName(), TRUE );
01100   win->setReplyFocus();
01101   win->show();
01102 
01103   return OK;
01104 }
01105 
01106 
01107 KMForwardCommand::KMForwardCommand( QWidget *parent,
01108   const QPtrList<KMMsgBase> &msgList, uint identity )
01109   : KMCommand( parent, msgList ),
01110     mIdentity( identity )
01111 {
01112 }
01113 
01114 KMForwardCommand::KMForwardCommand( QWidget *parent, KMMessage *msg,
01115                                     uint identity )
01116   : KMCommand( parent, msg ),
01117     mIdentity( identity )
01118 {
01119 }
01120 
01121 KMCommand::Result KMForwardCommand::execute()
01122 {
01123   KMComposeWin *win;
01124   QPtrList<KMMessage> msgList = retrievedMsgs();
01125 
01126   if (msgList.count() >= 2) {
01127     // ask if they want a mime digest forward
01128 
01129     if (KMessageBox::questionYesNo( parentWidget(),
01130                                     i18n("Forward selected messages as "
01131                                          "a MIME digest?") )
01132         == KMessageBox::Yes) {
01133       uint id = 0;
01134       KMMessage *fwdMsg = new KMMessage;
01135       KMMessagePart *msgPart = new KMMessagePart;
01136       QString msgPartText;
01137       int msgCnt = 0; // incase there are some we can't forward for some reason
01138 
01139       // dummy header initialization; initialization with the correct identity
01140       // is done below
01141       fwdMsg->initHeader(id);
01142       fwdMsg->setAutomaticFields(true);
01143       fwdMsg->mMsg->Headers().ContentType().CreateBoundary(1);
01144       QCString boundary( fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() );
01145       msgPartText = i18n("\nThis is a MIME digest forward. The content of the"
01146                          " message is contained in the attachment(s).\n\n\n");
01147       // iterate through all the messages to be forwarded
01148       for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01149         // set the identity
01150         if (id == 0)
01151           id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01152         // set the part header
01153         msgPartText += "--";
01154         msgPartText += QString::fromLatin1( boundary );
01155         msgPartText += "\nContent-Type: MESSAGE/RFC822";
01156         msgPartText += QString("; CHARSET=%1").arg(msg->charset());
01157         msgPartText += "\n";
01158         DwHeaders dwh;
01159         dwh.MessageId().CreateDefault();
01160         msgPartText += QString("Content-ID: %1\n").arg(dwh.MessageId().AsString().c_str());
01161         msgPartText += QString("Content-Description: %1").arg(msg->subject());
01162         if (!msg->subject().contains("(fwd)"))
01163           msgPartText += " (fwd)";
01164         msgPartText += "\n\n";
01165         // remove headers that shouldn't be forwarded
01166         msg->removePrivateHeaderFields();
01167         msg->removeHeaderField("BCC");
01168         // set the part
01169         msgPartText += msg->headerAsString();
01170         msgPartText += "\n";
01171         msgPartText += msg->body();
01172         msgPartText += "\n";     // eot
01173         msgCnt++;
01174         fwdMsg->link(msg, KMMsgStatusForwarded);
01175       }
01176       if ( id == 0 )
01177         id = mIdentity; // use folder identity if no message had an id set
01178       fwdMsg->initHeader(id);
01179       msgPartText += "--";
01180       msgPartText += QString::fromLatin1( boundary );
01181       msgPartText += "--\n";
01182       QCString tmp;
01183       msgPart->setTypeStr("MULTIPART");
01184       tmp.sprintf( "Digest; boundary=\"%s\"", boundary.data() );
01185       msgPart->setSubtypeStr( tmp );
01186       msgPart->setName("unnamed");
01187       msgPart->setCte(DwMime::kCte7bit);   // does it have to be 7bit?
01188       msgPart->setContentDescription(QString("Digest of %1 messages.").arg(msgCnt));
01189       // THIS HAS TO BE AFTER setCte()!!!!
01190       msgPart->setBodyEncoded(QCString(msgPartText.ascii()));
01191       KCursorSaver busy(KBusyPtr::busy());
01192       win = new KMComposeWin(fwdMsg, id);
01193       win->addAttach(msgPart);
01194       win->show();
01195       return OK;
01196     } else {            // NO MIME DIGEST, Multiple forward
01197       uint id = 0;
01198       QCString msgText = "";
01199       QPtrList<KMMessage> linklist;
01200       for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01201         // set the identity
01202         if (id == 0)
01203           id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01204 
01205         msgText += msg->createForwardBody();
01206         linklist.append(msg);
01207       }
01208       if ( id == 0 )
01209         id = mIdentity; // use folder identity if no message had an id set
01210       KMMessage *fwdMsg = new KMMessage;
01211       fwdMsg->initHeader(id);
01212       fwdMsg->setAutomaticFields(true);
01213       fwdMsg->setCharset("utf-8");
01214       fwdMsg->setBody(msgText);
01215 
01216       for (KMMessage *msg = linklist.first(); msg; msg = linklist.next())
01217         fwdMsg->link(msg, KMMsgStatusForwarded);
01218 
01219       KCursorSaver busy(KBusyPtr::busy());
01220       win = new KMComposeWin(fwdMsg, id);
01221       win->setCharset("");
01222       win->show();
01223       return OK;
01224     }
01225   }
01226 
01227   // forward a single message at most.
01228   KMMessage *msg = msgList.getFirst();
01229   if ( !msg || !msg->codec() )
01230     return Failed;
01231 
01232   KCursorSaver busy(KBusyPtr::busy());
01233   KMMessage *fwdMsg = msg->createForward();
01234 
01235   win = new KMComposeWin( fwdMsg );
01236   win->setCharset( fwdMsg->codec()->mimeName(), true );
01237   win->setBody( QString::fromUtf8( msg->createForwardBody() ) );
01238   win->show();
01239 
01240   return OK;
01241 }
01242 
01243 
01244 KMForwardAttachedCommand::KMForwardAttachedCommand( QWidget *parent,
01245   const QPtrList<KMMsgBase> &msgList, uint identity, KMComposeWin *win )
01246   : KMCommand( parent, msgList ), mIdentity( identity ),
01247     mWin( QGuardedPtr< KMComposeWin >( win ))
01248 {
01249 }
01250 
01251 KMForwardAttachedCommand::KMForwardAttachedCommand( QWidget *parent,
01252   KMMessage * msg, uint identity, KMComposeWin *win )
01253   : KMCommand( parent, msg ), mIdentity( identity ),
01254     mWin( QGuardedPtr< KMComposeWin >( win ))
01255 {
01256 }
01257 
01258 KMCommand::Result KMForwardAttachedCommand::execute()
01259 {
01260   QPtrList<KMMessage> msgList = retrievedMsgs();
01261   KMMessage *fwdMsg = new KMMessage;
01262 
01263   if (msgList.count() >= 2) {
01264     // don't respect X-KMail-Identity headers because they might differ for
01265     // the selected mails
01266     fwdMsg->initHeader(mIdentity);
01267   }
01268   else if (msgList.count() == 1) {
01269     KMMessage *msg = msgList.getFirst();
01270     fwdMsg->initFromMessage(msg);
01271     fwdMsg->setSubject( msg->forwardSubject() );
01272   }
01273 
01274   fwdMsg->setAutomaticFields(true);
01275 
01276   KCursorSaver busy(KBusyPtr::busy());
01277   if (!mWin)
01278     mWin = new KMComposeWin(fwdMsg, mIdentity);
01279 
01280   // iterate through all the messages to be forwarded
01281   for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01282     // remove headers that shouldn't be forwarded
01283     msg->removePrivateHeaderFields();
01284     msg->removeHeaderField("BCC");
01285     // set the part
01286     KMMessagePart *msgPart = new KMMessagePart;
01287     msgPart->setTypeStr("message");
01288     msgPart->setSubtypeStr("rfc822");
01289     msgPart->setCharset(msg->charset());
01290     msgPart->setName("forwarded message");
01291     msgPart->setContentDescription(msg->from()+": "+msg->subject());
01292     msgPart->setContentDisposition( "inline" );
01293     // THIS HAS TO BE AFTER setCte()!!!!
01294     msgPart->setMessageBody( msg->asString() );
01295     msgPart->setCharset("");
01296 
01297     fwdMsg->link(msg, KMMsgStatusForwarded);
01298     mWin->addAttach(msgPart);
01299   }
01300 
01301   mWin->show();
01302 
01303   return OK;
01304 }
01305 
01306 
01307 KMRedirectCommand::KMRedirectCommand( QWidget *parent,
01308   KMMessage *msg )
01309   : KMCommand( parent, msg )
01310 {
01311 }
01312 
01313 KMCommand::Result KMRedirectCommand::execute()
01314 {
01315   //TODO: move KMMessage::createRedirect to here
01316   KMComposeWin *win;
01317   KMMessage *msg = retrievedMessage();
01318   if ( !msg || !msg->codec() )
01319     return Failed;
01320 
01321   KCursorSaver busy(KBusyPtr::busy());
01322   win = new KMComposeWin();
01323   win->setMsg(msg->createRedirect(), FALSE);
01324   win->setCharset(msg->codec()->mimeName());
01325   win->show();
01326 
01327   return OK;
01328 }
01329 
01330 
01331 KMBounceCommand::KMBounceCommand( QWidget *parent,
01332   KMMessage *msg )
01333   : KMCommand( parent, msg )
01334 {
01335 }
01336 
01337 KMCommand::Result KMBounceCommand::execute()
01338 {
01339   KMMessage *msg = retrievedMessage();
01340   KMMessage *newMsg = msg->createBounce( TRUE /* with UI */);
01341   if (newMsg)
01342     kmkernel->msgSender()->send(newMsg, kmkernel->msgSender()->sendImmediate());
01343 
01344   return OK;
01345 }
01346 
01347 
01348 KMPrintCommand::KMPrintCommand( QWidget *parent,
01349   KMMessage *msg, bool htmlOverride, const QString & encoding,
01350   const HeaderStyle * style,
01351   const HeaderStrategy * strategy )
01352   : KMCommand( parent, msg ), mHtmlOverride( htmlOverride ), mEncoding( encoding ),
01353     mStyle( style ), mStrategy( strategy )
01354 {
01355 }
01356 
01357 KMCommand::Result KMPrintCommand::execute()
01358 {
01359   KMReaderWin printWin( 0, 0, 0 );
01360   printWin.setPrinting(TRUE);
01361   printWin.readConfig();
01362   if( mStyle != 0 && mStrategy != 0 )
01363     printWin.setHeaderStyleAndStrategy( mStyle, mStrategy );
01364   printWin.setHtmlOverride( mHtmlOverride );
01365   printWin.setOverrideEncoding( mEncoding );
01366   printWin.setMsg(retrievedMessage(), TRUE);
01367   printWin.printMsg();
01368 
01369   return OK;
01370 }
01371 
01372 
01373 KMSetStatusCommand::KMSetStatusCommand( KMMsgStatus status,
01374   const QValueList<Q_UINT32> &serNums, bool toggle )
01375   : mStatus( status ), mSerNums( serNums ), mToggle( toggle )
01376 {
01377 }
01378 
01379 KMCommand::Result KMSetStatusCommand::execute()
01380 {
01381   QValueListIterator<Q_UINT32> it;
01382   int idx = -1;
01383   KMFolder *folder = 0;
01384   bool parentStatus = false;
01385 
01386   // Toggle actions on threads toggle the whole thread
01387   // depending on the state of the parent.
01388   if (mToggle) {
01389     KMMsgBase *msg;
01390     kmkernel->msgDict()->getLocation( *mSerNums.begin(), &folder, &idx );
01391     if (folder) {
01392       msg = folder->getMsgBase(idx);
01393       if (msg && (msg->status()&mStatus))
01394         parentStatus = true;
01395       else
01396         parentStatus = false;
01397     }
01398   }
01399   QMap< KMFolder*, QValueList<int> > folderMap;
01400   for ( it = mSerNums.begin(); it != mSerNums.end(); ++it ) {
01401     kmkernel->msgDict()->getLocation( *it, &folder, &idx );
01402     if (folder) {
01403       if (mToggle) {
01404         KMMsgBase *msg = folder->getMsgBase(idx);
01405         // check if we are already at the target toggle state
01406         if (msg) {
01407           bool myStatus;
01408           if (msg->status()&mStatus)
01409             myStatus = true;
01410           else
01411             myStatus = false;
01412           if (myStatus != parentStatus)
01413             continue;
01414         }
01415       }
01416       /* Collect the ids for each folder in a separate list and
01417          send them off in one go at the end. */
01418       folderMap[folder].append(idx);
01419     }
01420   }
01421   QMapIterator< KMFolder*, QValueList<int> > it2 = folderMap.begin();
01422   while ( it2 != folderMap.end() ) {
01423      KMFolder *f = it2.key();
01424      f->setStatus( (*it2), mStatus, mToggle );
01425      ++it2;
01426   }
01427   //kapp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", QByteArray() );
01428 
01429   return OK;
01430 }
01431 
01432 
01433 KMFilterCommand::KMFilterCommand( const QCString &field, const QString &value )
01434   : mField( field ), mValue( value )
01435 {
01436 }
01437 
01438 KMCommand::Result KMFilterCommand::execute()
01439 {
01440   kmkernel->filterMgr()->createFilter( mField, mValue );
01441 
01442   return OK;
01443 }
01444 
01445 
01446 KMFilterActionCommand::KMFilterActionCommand( QWidget *parent,
01447                                               const QPtrList<KMMsgBase> &msgList,
01448                                               KMFilter *filter )
01449   : KMCommand( parent, msgList ), mFilter( filter  )
01450 {
01451 }
01452 
01453 KMCommand::Result KMFilterActionCommand::execute()
01454 {
01455   QPtrList<KMMessage> msgList = retrievedMsgs();
01456 
01457   for (KMMessage *msg = msgList.first(); msg; msg = msgList.next())
01458     if( msg->parent() )
01459       kmkernel->filterMgr()->tempOpenFolder(msg->parent());
01460 
01461   for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
01462     msg->setTransferInProgress(false);
01463 
01464     int filterResult = kmkernel->filterMgr()->process(msg, mFilter);
01465     if (filterResult == 2) {
01466       // something went horribly wrong (out of space?)
01467       perror("Critical error");
01468       kmkernel->emergencyExit( i18n("Not enough free disk space?" ));
01469     }
01470     msg->setTransferInProgress(true);
01471   }
01472 
01473   return OK;
01474 }
01475 
01476 
01477 KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter,
01478                                                       KMHeaders *headers,
01479                                                       KMMainWidget *main )
01480     : QObject( main ),
01481       mFilter( filter ), mHeaders( headers ), mMainWidget( main )
01482 {
01483 }
01484 
01485 void KMMetaFilterActionCommand::start()
01486 {
01487 #if 0 // use action scheduler
01488   KMFilterMgr::FilterSet set = KMFilterMgr::All;
01489   QPtrList<KMFilter> filters;
01490   filters.append( mFilter );
01491   ActionScheduler *scheduler = new ActionScheduler( set, filters, mHeaders );
01492   scheduler->setAlwaysMatch( true );
01493   scheduler->setAutoDestruct( true );
01494 
01495   int contentX, contentY;
01496   KMHeaderItem *nextItem = mHeaders->prepareMove( &contentX, &contentY );
01497   QPtrList<KMMsgBase> msgList = *mHeaders->selectedMsgs(true);
01498   mHeaders->finalizeMove( nextItem, contentX, contentY );
01499 
01500 
01501   for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
01502     scheduler->execFilters( msg );
01503 #else
01504   KMCommand *filterCommand = new KMFilterActionCommand( mMainWidget,
01505   *mHeaders->selectedMsgs(), mFilter);
01506   filterCommand->start();
01507   int contentX, contentY;
01508   KMHeaderItem *item = mHeaders->prepareMove( &contentX, &contentY );
01509   mHeaders->finalizeMove( item, contentX, contentY );
01510 #endif
01511 }
01512 
01513 
01514 KMMailingListFilterCommand::KMMailingListFilterCommand( QWidget *parent,
01515                                                         KMMessage *msg )
01516   : KMCommand( parent, msg )
01517 {
01518 }
01519 
01520 KMCommand::Result KMMailingListFilterCommand::execute()
01521 {
01522   QCString name;
01523   QString value;
01524   KMMessage *msg = retrievedMessage();
01525   if (!msg)
01526     return Failed;
01527 
01528   if ( !MailingList::name( msg, name, value ).isEmpty() ) {
01529     kmkernel->filterMgr()->createFilter( name, value );
01530     return OK;
01531   }
01532   else
01533     return Failed;
01534 }
01535 
01536 
01537 void KMMenuCommand::folderToPopupMenu(bool move,
01538   QObject *receiver, KMMenuToFolder *aMenuToFolder, QPopupMenu *menu )
01539 {
01540   while ( menu->count() )
01541   {
01542     QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
01543     if (popup)
01544       delete popup;
01545     else
01546       menu->removeItemAt( 0 );
01547   }
01548 
01549   if (!kmkernel->imapFolderMgr()->dir().first() &&
01550       !kmkernel->dimapFolderMgr()->dir().first())
01551   { // only local folders
01552     makeFolderMenu( &kmkernel->folderMgr()->dir(), move,
01553                     receiver, aMenuToFolder, menu );
01554   } else {
01555     // operate on top-level items
01556     QPopupMenu* subMenu = new QPopupMenu(menu);
01557     makeFolderMenu( &kmkernel->folderMgr()->dir(),
01558                     move, receiver, aMenuToFolder, subMenu );
01559     menu->insertItem( i18n( "Local Folders" ), subMenu );
01560     KMFolderDir* fdir = &kmkernel->imapFolderMgr()->dir();
01561     for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
01562       if (node->isDir())
01563         continue;
01564       subMenu = new QPopupMenu(menu);
01565       makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
01566       menu->insertItem( node->label(), subMenu );
01567     }
01568     fdir = &kmkernel->dimapFolderMgr()->dir();
01569     for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
01570       if (node->isDir())
01571         continue;
01572       subMenu = new QPopupMenu(menu);
01573       makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
01574       menu->insertItem( node->label(), subMenu );
01575     }
01576   }
01577 }
01578 
01579 void KMMenuCommand::makeFolderMenu(KMFolderNode* node, bool move,
01580   QObject *receiver, KMMenuToFolder *aMenuToFolder, QPopupMenu *menu )
01581 {
01582   // connect the signals
01583   if (move)
01584   {
01585     disconnect(menu, SIGNAL(activated(int)), receiver,
01586            SLOT(moveSelectedToFolder(int)));
01587     connect(menu, SIGNAL(activated(int)), receiver,
01588              SLOT(moveSelectedToFolder(int)));
01589   } else {
01590     disconnect(menu, SIGNAL(activated(int)), receiver,
01591            SLOT(copySelectedToFolder(int)));
01592     connect(menu, SIGNAL(activated(int)), receiver,
01593              SLOT(copySelectedToFolder(int)));
01594   }
01595 
01596   KMFolder *folder = 0;
01597   KMFolderDir *folderDir = 0;
01598   if (node->isDir()) {
01599     folderDir = static_cast<KMFolderDir*>(node);
01600   } else {
01601     folder = static_cast<KMFolder*>(node);
01602     folderDir = folder->child();
01603   }
01604 
01605   if (folder && !folder->noContent())
01606   {
01607     int menuId;
01608     if (move)
01609       menuId = menu->insertItem(i18n("Move to This Folder"));
01610     else
01611       menuId = menu->insertItem(i18n("Copy to This Folder"));
01612     aMenuToFolder->insert( menuId, folder );
01613     menu->setItemEnabled( menuId, !folder->isReadOnly() );
01614     menu->insertSeparator();
01615   }
01616 
01617   if (!folderDir)
01618     return;
01619 
01620   for (KMFolderNode *it = folderDir->first(); it; it = folderDir->next() ) {
01621     if (it->isDir())
01622       continue;
01623     KMFolder *child = static_cast<KMFolder*>(it);
01624     QString label = child->label();
01625     label.replace("&","&&");
01626     if (child->child() && child->child()->first()) {
01627       // descend
01628       QPopupMenu *subMenu = new QPopupMenu(menu, "subMenu");
01629       makeFolderMenu( child, move, receiver,
01630                       aMenuToFolder, subMenu );
01631       menu->insertItem( label, subMenu );
01632     } else {
01633       // insert an item
01634       int menuId = menu->insertItem( label );
01635       aMenuToFolder->insert( menuId, child );
01636       menu->setItemEnabled( menuId, !child->isReadOnly() );
01637     }
01638   }
01639   return;
01640 }
01641 
01642 
01643 KMCopyCommand::KMCopyCommand( KMFolder* destFolder,
01644                               const QPtrList<KMMsgBase> &msgList )
01645 :mDestFolder( destFolder ), mMsgList( msgList )
01646 {
01647 }
01648 
01649 KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg )
01650   :mDestFolder( destFolder )
01651 {
01652   mMsgList.append( &msg->toMsgBase() );
01653 }
01654 
01655 KMCommand::Result KMCopyCommand::execute()
01656 {
01657   KMMsgBase *msgBase;
01658   KMMessage *msg, *newMsg;
01659   int idx = -1;
01660   bool isMessage;
01661   QPtrList<KMMessage> list;
01662 
01663   if (mDestFolder && mDestFolder->open() != 0)
01664     return Failed;
01665 
01666   KCursorSaver busy(KBusyPtr::busy());
01667 
01668   for (msgBase = mMsgList.first(); msgBase; msgBase = mMsgList.next() )
01669   {
01670     KMFolder *srcFolder = msgBase->parent();
01671     if (isMessage = msgBase->isMessage())
01672     {
01673       msg = static_cast<KMMessage*>(msgBase);
01674     } else {
01675       idx = srcFolder->find(msgBase);
01676       assert(idx != -1);
01677       msg = srcFolder->getMsg(idx);
01678     }
01679 
01680     if (srcFolder &&
01681         (srcFolder->folderType()== KMFolderTypeImap) &&
01682         (mDestFolder->folderType() == KMFolderTypeImap) &&
01683         (static_cast<KMFolderImap*>(srcFolder->storage())->account() ==
01684          static_cast<KMFolderImap*>(mDestFolder->storage())->account()))
01685     {
01686       list.append(msg);
01687     } else {
01688       newMsg = new KMMessage;
01689       newMsg->setComplete(msg->isComplete());
01690       // make sure the attachment state is only calculated when it's complete
01691       if (!newMsg->isComplete())
01692         newMsg->setReadyToShow(false);
01693       newMsg->fromString(msg->asString());
01694       newMsg->setStatus(msg->status());
01695 
01696       if (srcFolder && !newMsg->isComplete())
01697       {
01698         newMsg->setParent(msg->parent());
01699         FolderJob *job = srcFolder->createJob(newMsg);
01700         job->setCancellable( false );
01701         connect(job, SIGNAL(messageRetrieved(KMMessage*)),
01702                 mDestFolder, SLOT(reallyAddCopyOfMsg(KMMessage*)));
01703         // msg musn't be deleted
01704         newMsg->setTransferInProgress(true);
01705         job->start();
01706       } else {
01707         int rc, index;
01708         mDestFolder->open();
01709         rc = mDestFolder->addMsg(newMsg, &index);
01710         if (rc == 0 && index != -1)
01711           mDestFolder->unGetMsg( mDestFolder->count() - 1 );
01712         mDestFolder->close();
01713       }
01714     }
01715 
01716     if (!isMessage && list.isEmpty())
01717     {
01718       assert(idx != -1);
01719       srcFolder->unGetMsg( idx );
01720     }
01721 
01722   } // end for
01723   mDestFolder->close();
01724 
01725 //TODO: Get rid of the other cases just use this one for all types of folder
01726 //TODO: requires adding copyMsg and getFolder methods to KMFolder.h
01727 
01728   if (!list.isEmpty())
01729   {
01730     // copy the message(s); note: the list is empty afterwards!
01731     KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
01732     imapDestFolder->copyMsg(list);
01733     imapDestFolder->getFolder();
01734   }
01735 
01736   return OK;
01737 }
01738 
01739 
01740 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01741                               const QPtrList<KMMsgBase> &msgList)
01742   :mDestFolder( destFolder ), mMsgList( msgList ), mProgressItem( 0 )
01743 {
01744   setDeletesItself( true );
01745 }
01746 
01747 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01748                               KMMessage *msg )
01749   :mDestFolder( destFolder ), mProgressItem( 0 )
01750 {
01751   setDeletesItself( true );
01752   mMsgList.append( &msg->toMsgBase() );
01753 }
01754 
01755 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
01756                               KMMsgBase *msgBase )
01757   :mDestFolder( destFolder ), mProgressItem( 0 )
01758 {
01759   setDeletesItself( true );
01760   mMsgList.append( msgBase );
01761 }
01762 
01763 KMMoveCommand::KMMoveCommand( Q_UINT32 )
01764 :mProgressItem( 0 )
01765 {
01766   setDeletesItself( true );
01767 }
01768 
01769 KMCommand::Result KMMoveCommand::execute()
01770 {
01771   setEmitsCompletedItself( true );
01772   typedef QMap< KMFolder*, QPtrList<KMMessage>* > FolderToMessageListMap;
01773   FolderToMessageListMap folderDeleteList;
01774 
01775   if (mDestFolder && mDestFolder->open() != 0) {
01776     completeMove( Failed );
01777     return Failed;
01778   }
01779   KCursorSaver busy(KBusyPtr::busy());
01780 
01781   // TODO set SSL state according to source and destfolder connection?
01782   Q_ASSERT( !mProgressItem );
01783   mProgressItem =
01784      ProgressManager::createProgressItem (
01785          "move"+ProgressManager::getUniqueID(),
01786          mDestFolder ? i18n( "Moving messages" ) : i18n( "Deleting messages" ) );
01787   connect( mProgressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
01788            this, SLOT( slotMoveCanceled() ) );
01789 
01790   KMMessage *msg;
01791   KMMsgBase *msgBase;
01792   int rc = 0;
01793   int index;
01794   QPtrList<KMMessage> list;
01795   int undoId = -1;
01796 
01797   if (mDestFolder) {
01798     connect (mDestFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
01799              this, SLOT(slotMsgAddedToDestFolder(KMFolder*, Q_UINT32)));
01800 
01801   }
01802   for ( msgBase=mMsgList.first(); msgBase; msgBase=mMsgList.next() ) {
01803     mLostBoys.append( msgBase->getMsgSerNum() );
01804   }
01805   mProgressItem->setTotalItems( mMsgList.count() );
01806 
01807   for (msgBase=mMsgList.first(); msgBase && !rc; msgBase=mMsgList.next()) {
01808     KMFolder *srcFolder = msgBase->parent();
01809     if (srcFolder == mDestFolder)
01810       continue;
01811     bool undo = msgBase->enableUndo();
01812     int idx = srcFolder->find(msgBase);
01813     assert(idx != -1);
01814     if ( msgBase->isMessage() )
01815       msg = static_cast<KMMessage*>(msgBase);
01816     else
01817       msg = srcFolder->getMsg(idx);
01818 
01819     if ( msg->transferInProgress() &&
01820          srcFolder->folderType() == KMFolderTypeImap )
01821     {
01822       // cancel the download
01823       msg->setTransferInProgress( false, true );
01824       static_cast<KMFolderImap*>(srcFolder->storage())->ignoreJobsForMessage( msg );
01825     }
01826 
01827     if (mDestFolder) {
01828       if (mDestFolder->folderType() == KMFolderTypeImap) {
01829         /* If we are moving to an imap folder, connect to it's completed
01830          * signal so we notice when all the mails should have showed up in it
01831          * but haven't for some reason. */
01832         KMFolderImap *imapFolder = static_cast<KMFolderImap*> ( mDestFolder->storage() );
01833         disconnect (imapFolder, SIGNAL(folderComplete( KMFolderImap*, bool )),
01834                  this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
01835 
01836         connect (imapFolder, SIGNAL(folderComplete( KMFolderImap*, bool )),
01837                  this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
01838         list.append(msg);
01839       } else {
01840         // We are moving to a local folder.
01841         mDestFolder->open();
01842         rc = mDestFolder->moveMsg(msg, &index);
01843         if (rc == 0 && index != -1) {
01844           KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 );
01845           if (undo && mb)
01846           {
01847             if ( undoId == -1 )
01848               undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder );
01849             kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() );
01850           }
01851           mDestFolder->close();
01852         } else if (rc != 0) {
01853           // Something  went wrong. Stop processing here, it is likely that the
01854           // other moves would fail as well.
01855           completeMove( Failed );
01856           mDestFolder->close();
01857           return Failed;
01858         }
01859       }
01860     } else {
01861       // really delete messages that are already in the trash folder or if
01862       // we are really, really deleting, not just moving to trash
01863       if (srcFolder->folderType() == KMFolderTypeImap) {
01864         if (!folderDeleteList[srcFolder])
01865           folderDeleteList[srcFolder] = new QPtrList<KMMessage>;
01866         folderDeleteList[srcFolder]->append( msg );
01867       } else {
01868         srcFolder->removeMsg(idx);
01869         delete msg;
01870       }
01871     }
01872   }
01873   if (!list.isEmpty() && mDestFolder) {
01874        mDestFolder->moveMsg(list, &index);
01875   } else {
01876     FolderToMessageListMap::Iterator it;
01877     for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
01878       it.key()->removeMsg(*it.data());
01879       delete it.data();
01880     }
01881     /* The list is empty, which means that either all messages were to be
01882      * deleted, which is done above, or all of them were already in this folder.
01883      * In both cases make sure a completed() signal is emitted nonetheless. */
01884     KMFolder *srcFolder = 0;
01885     if ( mMsgList.first() ) {
01886       srcFolder = mMsgList.first()->parent();
01887       if ( mDestFolder && mDestFolder == srcFolder ) {
01888         completeMove( OK );
01889       }
01890     }
01891     if ( !mDestFolder ) {
01892       completeMove( OK );
01893     }
01894   }
01895 
01896   return OK;
01897 }
01898 
01899 void KMMoveCommand::slotImapFolderCompleted(KMFolderImap *, bool success)
01900 {
01901   if ( success ) {
01902     // the folder was checked successfully but we were still called, so check
01903     // if we are still waiting for messages to show up. If so, uidValidity
01904     // changed, or something else went wrong. Clean up.
01905 
01906     /* Unfortunately older UW imap servers change uid validity for each put job.
01907      * Yes, it is really that broken. *sigh* So we cannot report error here, I guess. */
01908     if ( !mLostBoys.isEmpty() ) {
01909       kdDebug(5006) <<  "### Not all moved messages reported back that they were " << endl
01910                     <<  "### added to the target folder. Did uidValidity change? " << endl;
01911     }
01912     completeMove( OK );
01913   } else {
01914     // Should we inform the user here or leave that to the caller?
01915     completeMove( Failed );
01916   }
01917 }
01918 
01919 void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, Q_UINT32 serNum)
01920 {
01921   if (folder != mDestFolder || !mLostBoys.contains( serNum ) ) {
01922     kdDebug(5006) << "KMMoveCommand::msgAddedToDestFolder different "
01923                      "folder or invalid serial number." << endl;
01924     return;
01925   }
01926   mLostBoys.remove(serNum);
01927   if ( mLostBoys.isEmpty() ) {
01928     // we are done. All messages transferred to the host succesfully
01929     if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) {
01930       mDestFolder->sync();
01931     }
01932     completeMove( OK );
01933   } else {
01934     mProgressItem->incCompletedItems();
01935     mProgressItem->updateProgress();
01936   }
01937 }
01938 
01939 void KMMoveCommand::completeMove( Result result )
01940 {
01941   if ( mDestFolder )
01942     mDestFolder->close();
01943   while ( !mOpenedFolders.empty() ) {
01944     KMFolder *folder = mOpenedFolders.back();
01945     mOpenedFolders.pop_back();
01946     folder->close();
01947   }
01948   if ( mProgressItem )
01949     mProgressItem->setComplete();
01950   setResult( result );
01951   emit completed( this );
01952   deleteLater();
01953 }
01954 
01955 void KMMoveCommand::slotMoveCanceled()
01956 {
01957   completeMove( Canceled );
01958 }
01959 
01960 // srcFolder doesn't make much sense for searchFolders
01961 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder,
01962   const QPtrList<KMMsgBase> &msgList )
01963 :KMMoveCommand( findTrashFolder( srcFolder ), msgList)
01964 {
01965   srcFolder->open();
01966   mOpenedFolders.push_back( srcFolder );
01967 }
01968 
01969 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
01970 :KMMoveCommand( findTrashFolder( srcFolder ), msg)
01971 {
01972   srcFolder->open();
01973   mOpenedFolders.push_back( srcFolder );
01974 }
01975 
01976 KMDeleteMsgCommand::KMDeleteMsgCommand( Q_UINT32 sernum )
01977 :KMMoveCommand( sernum )
01978 {
01979   KMFolder *srcFolder;
01980   int idx;
01981   kmkernel->msgDict()->getLocation( sernum, &srcFolder, &idx );
01982   KMMsgBase *msg = srcFolder->getMsgBase( idx );
01983   srcFolder->open();
01984   mOpenedFolders.push_back( srcFolder );
01985   addMsg( msg );
01986   setDestFolder( findTrashFolder( srcFolder ) );
01987 }
01988 
01989 KMFolder * KMDeleteMsgCommand::findTrashFolder( KMFolder * folder )
01990 {
01991   KMFolder* trash = folder->trashFolder();
01992   if( !trash )
01993     trash = kmkernel->trashFolder();
01994   if( trash != folder )
01995     return trash;
01996   return 0;
01997 }
01998 
01999 
02000 KMUrlClickedCommand::KMUrlClickedCommand( const KURL &url, uint identity,
02001   KMReaderWin *readerWin, bool htmlPref, KMMainWidget *mainWidget )
02002   :mUrl( url ), mIdentity( identity ), mReaderWin( readerWin ),
02003    mHtmlPref( htmlPref ), mMainWidget( mainWidget )
02004 {
02005 }
02006 
02007 KMCommand::Result KMUrlClickedCommand::execute()
02008 {
02009   KMComposeWin *win;
02010   KMMessage* msg;
02011 
02012   if (mUrl.protocol() == "mailto")
02013   {
02014     msg = new KMMessage;
02015     msg->initHeader(mIdentity);
02016     msg->setCharset("utf-8");
02017     msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
02018     QString query=mUrl.query();
02019     while (!query.isEmpty()) {
02020       QString queryPart;
02021       int secondQuery = query.find('?',1);
02022       if (secondQuery != -1)
02023         queryPart = query.left(secondQuery);
02024       else
02025         queryPart = query;
02026       query = query.mid(queryPart.length());
02027 
02028       if (queryPart.left(9) == "?subject=")
02029         msg->setSubject( KURL::decode_string(queryPart.mid(9)) );
02030       else if (queryPart.left(6) == "?body=")
02031         // It is correct to convert to latin1() as URL should not contain
02032         // anything except ascii.
02033         msg->setBody( KURL::decode_string(queryPart.mid(6)).latin1() );
02034       else if (queryPart.left(4) == "?cc=")
02035         msg->setCc( KURL::decode_string(queryPart.mid(4)) );
02036     }
02037 
02038     win = new KMComposeWin(msg, mIdentity);
02039     win->setCharset("", TRUE);
02040     win->show();
02041   }
02042   else if ( mUrl.protocol() == "im" )
02043   {
02044     kmkernel->imProxy()->chatWithContact( mUrl.path() );
02045   }
02046   else if ((mUrl.protocol() == "http") || (mUrl.protocol() == "https") ||
02047            (mUrl.protocol() == "ftp") || (mUrl.protocol() == "file") ||
02048            (mUrl.protocol() == "ftps") || (mUrl.protocol() == "sftp" ) ||
02049            (mUrl.protocol() == "help") || (mUrl.protocol() == "vnc") ||
02050            (mUrl.protocol() == "smb"))
02051   {
02052     KPIM::BroadcastStatus::instance()->setStatusMsg( i18n("Opening URL..."));
02053     KMimeType::Ptr mime = KMimeType::findByURL( mUrl );
02054     if (mime->name() == "application/x-desktop" ||
02055         mime->name() == "application/x-executable" ||
02056         mime->name() == "application/x-msdos-program" ||
02057         mime->name() == "application/x-shellscript" )
02058     {
02059       if (KMessageBox::warningYesNo( 0, i18n( "<qt>Do you really want to execute <b>%1</b>?</qt>" )
02060         .arg( mUrl.prettyURL() ) ) != KMessageBox::Yes)
02061         return Canceled;
02062     }
02063     (void) new KRun( mUrl );
02064   }
02065   else
02066     return Failed;
02067 
02068   return OK;
02069 }
02070 
02071 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, KMMessage *msg )
02072   : KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
02073 {
02074 }
02075 
02076 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, const QPtrList<KMMsgBase>& msgs )
02077   : KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
02078 {
02079 }
02080 
02081 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, QPtrList<partNode>& attachments,
02082                                                     KMMessage *msg, bool encoded )
02083   : KMCommand( parent, msg ), mImplicitAttachments( false ),
02084     mEncoded( encoded )
02085 {
02086   // do not load the complete message but only parts
02087   msg->setComplete( true );
02088   for ( QPtrListIterator<partNode> it( attachments ); it.current(); ++it ) {
02089     mAttachmentMap.insert( it.current(), msg );
02090   }
02091 }
02092 
02093 KMCommand::Result KMSaveAttachmentsCommand::execute()
02094 {
02095   setEmitsCompletedItself( true );
02096   if ( mImplicitAttachments ) {
02097     QPtrList<KMMessage> msgList = retrievedMsgs();
02098     KMMessage *msg;
02099     for ( QPtrListIterator<KMMessage> itr( msgList );
02100           ( msg = itr.current() );
02101           ++itr ) {
02102       partNode *rootNode = partNode::fromMessage( msg );
02103       for ( partNode *child = rootNode; child;
02104             child = child->firstChild() ) {
02105         for ( partNode *node = child; node; node = node->nextSibling() ) {
02106           if ( node->type() != DwMime::kTypeMultipart )
02107             mAttachmentMap.insert( node, msg );
02108         }
02109       }
02110     }
02111   }
02112   setDeletesItself( true );
02113   // load all parts
02114   KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachmentMap );
02115   connect( command, SIGNAL( partsRetrieved() ),
02116            this, SLOT( slotSaveAll() ) );
02117   command->start();
02118 
02119   return OK;
02120 }
02121 
02122 void KMSaveAttachmentsCommand::slotSaveAll()
02123 {
02124   // now that all message parts have been retrieved, remove all parts which
02125   // don't represent an attachment if they were not explicitely passed in the
02126   // c'tor
02127   if ( mImplicitAttachments ) {
02128     for ( PartNodeMessageMap::iterator it = mAttachmentMap.begin();
02129           it != mAttachmentMap.end(); ) {
02130       // only body parts which have a filename or a name parameter (except for
02131       // the root node for which name is set to the message's subject) are
02132       // considered attachments
02133       if ( it.key()->msgPart().fileName().stripWhiteSpace().isEmpty() &&
02134            ( it.key()->msgPart().name().stripWhiteSpace().isEmpty() ||
02135              !it.key()->parentNode() ) ) {
02136         PartNodeMessageMap::iterator delIt = it;
02137         ++it;
02138         mAttachmentMap.remove( delIt );
02139       }
02140       else
02141         ++it;
02142     }
02143     if ( mAttachmentMap.isEmpty() ) {
02144       KMessageBox::information( 0, i18n("Found no attachments to save.") );
02145       setResult( OK ); // The user has already been informed.
02146       emit completed( this );
02147       deleteLater();
02148       return;
02149     }
02150   }
02151 
02152   KURL url, dirUrl;
02153   if ( mAttachmentMap.count() > 1 ) {
02154     // get the dir
02155     KFileDialog fdlg( ":saveAttachments", QString::null, parentWidget(),
02156                       "save attachments dialog", true );
02157     fdlg.setCaption( i18n("Save Attachments To") );
02158     fdlg.setOperationMode( KFileDialog::Saving );
02159     fdlg.setMode( (unsigned int) KFile::Directory );
02160     if ( fdlg.exec() == QDialog::Rejected || !fdlg.selectedURL().isValid() ) {
02161       setResult( Canceled );
02162       emit completed( this );
02163       deleteLater();
02164       return;
02165     }
02166     dirUrl = fdlg.selectedURL();
02167   }
02168   else {
02169     // only one item, get the desired filename
02170     partNode *node = mAttachmentMap.begin().key();
02171     // replace all ':' with '_' because ':' isn't allowed on FAT volumes
02172     QString s =
02173       node->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
02174     if ( s.isEmpty() )
02175       s = node->msgPart().name().stripWhiteSpace().replace( ':', '_' );
02176     if ( s.isEmpty() )
02177       s = i18n("filename for an unnamed attachment", "attachment.1");
02178     url = KFileDialog::getSaveURL( s, QString::null, parentWidget(),
02179                                    QString::null );
02180     if ( url.isEmpty() ) {
02181       setResult( Canceled );
02182       emit completed( this );
02183       deleteLater();
02184       return;
02185     }
02186   }
02187 
02188   Result globalResult = OK;
02189   int unnamedAtmCount = 0;
02190   for ( PartNodeMessageMap::const_iterator it = mAttachmentMap.begin();
02191         it != mAttachmentMap.end();
02192         ++it ) {
02193     KURL curUrl;
02194     if ( !dirUrl.isEmpty() ) {
02195       curUrl = dirUrl;
02196       QString s =
02197         it.key()->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
02198       if ( s.isEmpty() )
02199         s = it.key()->msgPart().name().stripWhiteSpace().replace( ':', '_' );
02200       if ( s.isEmpty() ) {
02201         ++unnamedAtmCount;
02202         s = i18n("filename for the %1-th unnamed attachment",
02203                  "attachment.%1")
02204             .arg( unnamedAtmCount );
02205       }
02206       curUrl.setFileName( s );
02207     } else {
02208       curUrl = url;
02209     }
02210 
02211     if ( !curUrl.isEmpty() ) {
02212       if ( KIO::NetAccess::exists( curUrl, false, parentWidget() ) ) {
02213         if ( KMessageBox::warningContinueCancel( parentWidget(),
02214               i18n( "A file named %1 already exists. Do you want to overwrite it?" )
02215               .arg( curUrl.fileName() ),
02216               i18n( "File Already Exists" ), i18n("Overwrite") ) == KMessageBox::Cancel) {
02217           continue;
02218         }
02219       }
02220       // save
02221       const Result result = saveItem( it.key(), curUrl );
02222       if ( result != OK )
02223         globalResult = result;
02224     }
02225   }
02226   setResult( globalResult );
02227   emit completed( this );
02228   deleteLater();
02229 }
02230 
02231 KMCommand::Result KMSaveAttachmentsCommand::saveItem( partNode *node,
02232                                                       const KURL& url )
02233 {
02234   bool bSaveEncrypted = false;
02235   bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted;
02236   if( bEncryptedParts )
02237     if( KMessageBox::questionYesNo( parentWidget(),
02238           i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?" ).
02239           arg( url.fileName() ),
02240           i18n( "KMail Question" ) ) ==
02241         KMessageBox::Yes )
02242       bSaveEncrypted = true;
02243 
02244   bool bSaveWithSig = true;
02245   if( node->signatureState() != KMMsgNotSigned )
02246     if( KMessageBox::questionYesNo( parentWidget(),
02247           i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?" ).
02248           arg( url.fileName() ),
02249           i18n( "KMail Question" ) ) !=
02250         KMessageBox::Yes )
02251       bSaveWithSig = false;
02252 
02253   QByteArray data;
02254   if ( mEncoded )
02255   {
02256     // This does not decode the Message Content-Transfer-Encoding
02257     // but saves the _original_ content of the message part
02258     QCString cstr( node->msgPart().body() );
02259     data = cstr;
02260     data.resize(data.size() - 1);
02261   }
02262   else
02263   {
02264     if( bSaveEncrypted || !bEncryptedParts) {
02265       partNode *dataNode = node;
02266       QCString rawReplyString;
02267       bool gotRawReplyString = false;
02268       if( !bSaveWithSig ) {
02269         if( DwMime::kTypeMultipart == node->type() &&
02270             DwMime::kSubtypeSigned == node->subType() ){
02271           // carefully look for the part that is *not* the signature part:
02272           if( node->findType( DwMime::kTypeApplication,
02273                 DwMime::kSubtypePgpSignature,
02274                 TRUE, false ) ){
02275             dataNode = node->findTypeNot( DwMime::kTypeApplication,
02276                 DwMime::kSubtypePgpSignature,
02277                 TRUE, false );
02278           }else if( node->findType( DwMime::kTypeApplication,
02279                 DwMime::kSubtypePkcs7Mime,
02280                 TRUE, false ) ){
02281             dataNode = node->findTypeNot( DwMime::kTypeApplication,
02282                 DwMime::kSubtypePkcs7Mime,
02283                 TRUE, false );
02284           }else{
02285             dataNode = node->findTypeNot( DwMime::kTypeMultipart,
02286                 DwMime::kSubtypeUnknown,
02287                 TRUE, false );
02288           }
02289     }else{
02290       ObjectTreeParser otp( 0, 0, false, false, false );
02291 
02292       // process this node and all it's siblings and descendants
02293       dataNode->setProcessed( false, true );
02294       otp.parseObjectTree( dataNode );
02295 
02296       rawReplyString = otp.rawReplyString();
02297       gotRawReplyString = true;
02298         }
02299       }
02300       QByteArray cstr = gotRawReplyString
02301                          ? rawReplyString
02302                          : dataNode->msgPart().bodyDecodedBinary();
02303       data = cstr;
02304       size_t size = cstr.size();
02305       if ( dataNode->msgPart().type() == DwMime::kTypeText ) {
02306         // convert CRLF to LF before writing text attachments to disk
02307         size = KMFolder::crlf2lf( cstr.data(), size );
02308       }
02309       data.resize( size );
02310     }
02311   }
02312   QDataStream ds;
02313   QFile file;
02314   KTempFile tf;
02315   tf.setAutoDelete( true );
02316   if ( url.isLocalFile() )
02317   {
02318     // save directly
02319     file.setName( url.path() );
02320     if ( !file.open( IO_WriteOnly ) )
02321     {
02322       KMessageBox::error( parentWidget(),
02323           i18n( "%2 is detailed error description",
02324             "Could not write the file %1:\n%2" )
02325           .arg( file.name() )
02326           .arg( QString::fromLocal8Bit( strerror( errno ) ) ),
02327           i18n( "KMail Error" ) );
02328       return Failed;
02329     }
02330     // Don't attempt the below, it causes issues on nfs, among other things
02331     // https://intevation.de/roundup/kolab/issue856
02332     //fchmod( file.handle(), S_IRUSR | S_IWUSR );
02333     ds.setDevice( &file );
02334   } else
02335   {
02336     // tmp file for upload
02337     ds.setDevice( tf.file() );
02338   }
02339 
02340   ds.writeRawBytes( data.data(), data.size() );
02341   if ( !url.isLocalFile() )
02342   {
02343     tf.close();
02344     if ( !KIO::NetAccess::upload( tf.name(), url, parentWidget() ) )
02345     {
02346       KMessageBox::error( parentWidget(),
02347           i18n( "Could not write the file %1." )
02348           .arg( url.path() ),
02349           i18n( "KMail Error" ) );
02350       return Failed;
02351     }
02352   } else
02353     file.close();
02354   return OK;
02355 }
02356 
02357 KMLoadPartsCommand::KMLoadPartsCommand( QPtrList<partNode>& parts, KMMessage *msg )
02358   : mNeedsRetrieval( 0 )
02359 {
02360   for ( QPtrListIterator<partNode> it( parts ); it.current(); ++it ) {
02361     mPartMap.insert( it.current(), msg );
02362   }
02363 }
02364 
02365 KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
02366   : mNeedsRetrieval( 0 )
02367 {
02368   mPartMap.insert( node, msg );
02369 }
02370 
02371 KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
02372   : mNeedsRetrieval( 0 ), mPartMap( partMap )
02373 {
02374 }
02375 
02376 void KMLoadPartsCommand::slotStart()
02377 {
02378   for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
02379         it != mPartMap.end();
02380         ++it ) {
02381     if ( !it.key()->msgPart().isComplete() &&
02382          !it.key()->msgPart().partSpecifier().isEmpty() ) {
02383       // incomplete part, so retrieve it first
02384       ++mNeedsRetrieval;
02385       KMFolder* curFolder = it.data()->parent();
02386       if ( curFolder ) {
02387         FolderJob *job =
02388           curFolder->createJob( it.data(), FolderJob::tGetMessage,
02389                                 0, it.key()->msgPart().partSpecifier() );
02390         job->setCancellable( false );
02391         connect( job, SIGNAL(messageUpdated(KMMessage*, QString)),
02392                  this, SLOT(slotPartRetrieved(KMMessage*, QString)) );
02393         job->start();
02394       } else
02395         kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl;
02396     }
02397   }
02398   if ( mNeedsRetrieval == 0 )
02399     execute();
02400 }
02401 
02402 void KMLoadPartsCommand::slotPartRetrieved( KMMessage *msg,
02403                                             QString partSpecifier )
02404 {
02405   DwBodyPart *part =
02406     msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier );
02407   if ( part ) {
02408     // update the DwBodyPart in the partNode
02409     for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
02410           it != mPartMap.end();
02411           ++it ) {
02412       if ( it.key()->dwPart()->partId() == part->partId() )
02413         it.key()->setDwPart( part );
02414     }
02415   } else
02416     kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl;
02417   --mNeedsRetrieval;
02418   if ( mNeedsRetrieval == 0 )
02419     execute();
02420 }
02421 
02422 KMCommand::Result KMLoadPartsCommand::execute()
02423 {
02424   emit partsRetrieved();
02425   setResult( OK );
02426   emit completed( this );
02427   deleteLater();
02428   return OK;
02429 }
02430 
02431 KMResendMessageCommand::KMResendMessageCommand( QWidget *parent,
02432    KMMessage *msg )
02433   :KMCommand( parent, msg )
02434 {
02435 }
02436 
02437 KMCommand::Result KMResendMessageCommand::execute()
02438 {
02439   KMComposeWin *win;
02440   KMMessage *msg = retrievedMessage();
02441 
02442   KMMessage *newMsg = new KMMessage(*msg);
02443   newMsg->setCharset(msg->codec()->mimeName());
02444   // the message needs a new Message-Id
02445   newMsg->removeHeaderField( "Message-Id" );
02446   newMsg->setParent( 0 );
02447 
02448   // adds the new date to the message
02449   newMsg->removeHeaderField( "Date" );
02450 
02451   win = new KMComposeWin();
02452   win->setMsg(newMsg, false, true);
02453   win->show();
02454 
02455   return OK;
02456 }
02457 
02458 KMMailingListCommand::KMMailingListCommand( QWidget *parent, KMFolder *folder )
02459   : KMCommand( parent ), mFolder( folder )
02460 {
02461 }
02462 
02463 KMCommand::Result KMMailingListCommand::execute()
02464 {
02465   KURL::List lst = urls();
02466   QString handler = ( mFolder->mailingList().handler() == MailingList::KMail )
02467     ? "mailto" : "https";
02468 
02469   KMCommand *command = 0;
02470   for ( KURL::List::Iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
02471     if ( handler == (*itr).protocol() ) {
02472       command = new KMUrlClickedCommand( *itr, mFolder->identity(), 0, false );
02473     }
02474   }
02475   if ( !command && !lst.empty() ) {
02476     command =
02477       new KMUrlClickedCommand( lst.first(), mFolder->identity(), 0, false );
02478   }
02479   if ( command ) {
02480     connect( command, SIGNAL( completed( KMCommand * ) ),
02481              this, SLOT( commandCompleted( KMCommand * ) ) );
02482     setDeletesItself( true );
02483     setEmitsCompletedItself( true );
02484     command->start();
02485     return OK;
02486   }
02487   return Failed;
02488 }
02489 
02490 void KMMailingListCommand::commandCompleted( KMCommand *command )
02491 {
02492   setResult( command->result() );
02493   emit completed( this );
02494   deleteLater();
02495 }
02496 
02497 KMMailingListPostCommand::KMMailingListPostCommand( QWidget *parent, KMFolder *folder )
02498   : KMMailingListCommand( parent, folder )
02499 {
02500 }
02501 KURL::List KMMailingListPostCommand::urls() const
02502 {
02503   return mFolder->mailingList().postURLS();
02504 }
02505 
02506 KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( QWidget *parent, KMFolder *folder )
02507   : KMMailingListCommand( parent, folder )
02508 {
02509 }
02510 KURL::List KMMailingListSubscribeCommand::urls() const
02511 {
02512   return mFolder->mailingList().subscribeURLS();
02513 }
02514 
02515 KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( QWidget *parent, KMFolder *folder )
02516   : KMMailingListCommand( parent, folder )
02517 {
02518 }
02519 KURL::List KMMailingListUnsubscribeCommand::urls() const
02520 {
02521   return mFolder->mailingList().unsubscribeURLS();
02522 }
02523 
02524 KMMailingListArchivesCommand::KMMailingListArchivesCommand( QWidget *parent, KMFolder *folder )
02525   : KMMailingListCommand( parent, folder )
02526 {
02527 }
02528 KURL::List KMMailingListArchivesCommand::urls() const
02529 {
02530   return mFolder->mailingList().archiveURLS();
02531 }
02532 
02533 KMMailingListHelpCommand::KMMailingListHelpCommand( QWidget *parent, KMFolder *folder )
02534   : KMMailingListCommand( parent, folder )
02535 {
02536 }
02537 KURL::List KMMailingListHelpCommand::urls() const
02538 {
02539   return mFolder->mailingList().helpURLS();
02540 }
02541 
02542 KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
02543   :mUrl( url ), mMessage( msg )
02544 {
02545 }
02546 
02547 KMCommand::Result KMIMChatCommand::execute()
02548 {
02549   kdDebug( 5006 ) << k_funcinfo << " URL is: " << mUrl << endl;
02550   // find UID for mail address
02551   KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
02552   KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getEmailAddr( mUrl.path() ) ) ;
02553 
02554   // start chat
02555   if( addresses.count() == 1 ) {
02556     kmkernel->imProxy()->chatWithContact( addresses[0].uid() );
02557     return OK;
02558   }
02559   else
02560   {
02561     kdDebug( 5006 ) << "Didn't find exactly one addressee, couldn't tell who to chat to for that email address.  Count = " << addresses.count() << endl;
02562 
02563     QString apology;
02564     if ( addresses.isEmpty() )
02565       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." );
02566     else
02567     {
02568       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." );
02569       QStringList nameList;
02570       KABC::AddresseeList::const_iterator it = addresses.begin();
02571       KABC::AddresseeList::const_iterator end = addresses.end();
02572       for ( ; it != end; ++it )
02573       {
02574           nameList.append( (*it).realName() );
02575       }
02576       QString names = nameList.join( QString::fromLatin1( ",\n" ) );
02577       apology = apology.arg( names );
02578     }
02579 
02580     KMessageBox::sorry( parentWidget(), apology );
02581     return Failed;
02582   }
02583 }
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 Thu May 3 20:22:58 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003