[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kmail-devel
Subject:    KMCommands
From:       Don Sanders <sanders () trolltech ! com>
Date:       2002-07-29 5:44:06
[Download RAW message or body]

Attached are the kmcommand header and implementation files I have been 
working on.

The files contain various classes I have been working on based on the 
command pattern. These classes are based on an asynchronous version 
of the command pattern so instead of having only a virtual execute 
method the base command class has a non-virtual start method that is 
responsible for performing necessary async operations and then 
calling the virtual execute method.

The force behind implementing these classes is to make message 
operations independent of the kmmainwin gui class. This will enable 
these operations to be performed by other main windows that show 
messages, such as top level reader windows, the search window and 
possibly the composer window (for the list of attachments)

These commands classes may also be useful for improving undo/redo. 
Some commands may be undone by implementing an undo() or unExecute() 
method. Then undo and redo stacks can be kept, this technique has 
been used to good effect in KAddressBook.

Another possible use is for disconnected imap operation. When offline 
commands that require a connection to the imap server may be kept in 
a queue so that they can be executed when the connection to the 
server is reestablished.


I have modified other files but only included kmcommands.*, the other 
files are not ready for public display yet. As an example commands 
may be used like so:

KMAsyncCommand *command = new KMForwardAttachedCommand(this,
   *mHeaders->selectMsgs(), mFolder);
command->start();

In the kmcommands.* files, I've currently called the base class 
KMAsyncCommand, but I've decided this verbosity is unnecessary and 
intend to rename the class KMCommand.

Because KMAsyncCommand based classes are asynchronous I've decided 
it's best if they delete themselves. Hence no explicit deletion is 
required and KMAsyncCommands should not be created on the stack.

There are three different types of commands defined in kmcommands.*:
1) Synchronous commands, these don't really even need start(), as 
execute() could be called directly.
2) Async commands that retrieve a single message then operate on it.
3) Async commands that retrieve multiple messsages then operate on 
them.

Currently KMAsyncCommand has 3 different constructors one to handle 
each of the above cases. In the future I might split things up into 3 
different classes.

KMAsyncCommand is implemented in terms of transferSelectedMsgs and 
related methods that previously were implemented in kmmainwin.cpp.

I have several concerns about this transferSelectedMsgs code.

I suspect the code is buggy and won't handle multiple main windows 
(File->"New Mail Client") correctly. For instance if I select 
messages on an imap server,  forward them as attachments and while 
that operation is in progress open up an additional main window and 
read messages that have been selected for forwarding I expect 
dangling pointers to be created and KMail to crash. To fix this 
transferSelectedMsgs and related methods should be modified to use 
serial numbers instead of KMMsgBase*, but we need a reliable serial 
number dict before this change should be made.

Even when working with a list of messages to be retrieved 
transferSelectedMsgs works with the concept of a single folder. This 
is restrictive because in the search dialog messages shown may come 
from multiple folders.

transferSelectedMsgs shows a toplevel progress dialog (which is why 
KMAsyncCommand constructors take a mainWin argument, to use as a 
parent for the dialog). Instead it would be better to show the 
progress in the mainWin status bar. If other status bar using 
operations are in progress then the combined progress for all pending 
operations related to that main window should be shown in the status 
bar.

transferSelectedMsgs checks for protocol == "imap", and if so creates 
KMImapJobs as necessary. I would prefer it if the KMImapJob helper 
class was based on a virtual base class that was implemented by all 
folder classes. Then the non-imap branch in transferSelectedMsgs 
would be eliminated and all folders would be treated the same as imap 
folders currently are.

transferSelectedMsgs loads all messages operated on into memory at 
once. This is a problem that cannot be easily fixed due to 
limitations in mimelib. I'll attempt to fix mimelib after I'm 
satisfied with kmcommands.*

I have not yet completed implementing commands. The delete, move and 
copy commands have yet to be completed.

Currently commands are indepedent of KActions. I may add static 
factory methods to commands to generate a KAction related to the 
command. I would do this to avoid duplication of some action strings 
(specifically the name and accel key strings). For a substantial 
amount of time I tried to make KMCommands a factory class for 
KActions. This would mean client classes like KMMainWin would not 
have to define slots for each action. Instead each KMCommand class 
would create an action and connect the action to a slot of its own. 
I've given up this idea finding it required to much rigidity in the 
command container classes.

The commands are not fully tested. I have tested all the commands but 
have made signficant changes to the base class KMAsyncCommand since 
then.

Some commands (AddrAddrBook, OpenAddrBook, urlOpen, toggleFixedFont, 
setStatus) are trivial and exist only for the sake of consistency.

The source code is not currently commented. I'll do that before 
committing. I also haven't bothered making parameters that should be 
constant const or using references where appropriate.

Don.

["kmcommands.h" (text/x-chdr)]

#ifndef KMCommands_h
#define KMCommands_h

#include <qptrlist.h>
#include <kio/job.h>
#include "kmmsgbase.h" // for KMMsgStatus


class QTextCodec;
class KIO::Job;
class KMainWindow;
class KProgressDialog;
class KMFolder;
class KMHeaders;
class KMMessage;
class KMMsgBase;
class KMMainWin;
class KMReaderWin;

class KMAsyncCommand : public QObject
{
  Q_OBJECT

public:
  KMAsyncCommand( QWidget *parent = 0 );
  KMAsyncCommand( QWidget *parent, QPtrList<KMMsgBase> msgList, 
		  KMFolder *folder );
  KMAsyncCommand( QWidget *parent, KMMsgBase *msgBase );
  virtual ~KMAsyncCommand();
  void start();

protected:
  QPtrList<KMMessage> *retrievedMsgs();
  KMMessage *retrievedMessage();

private:
  virtual void execute() = 0;

  void preTransfer();
  void transferSelectedMsgs();

private slots:
  void slotPostTransfer(bool);
  void slotMsgTransfered(KMMessage* msg);
  void slotJobFinished();
  void slotTransferCancelled();

signals:
  void messagesTransfered(bool);

private:
  // ProgressDialog for transfering messages
  KProgressDialog* mProgressDialog;
  //Currently only one async command allowed at a time
  static int mCountJobs;
  int mCountMsgs;

  QWidget *mParent;
  QPtrList<KMMessage> mRetrievedMsgs;
  QPtrList<KMMsgBase> mMsgList;
  KMFolder *mFolder;
};

class KMMailtoComposeCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMMailtoComposeCommand( KURL url, KMMsgBase *msgBase = 0 );

private:
  virtual void execute();

  KURL mUrl;
  KMMsgBase *mMsgBase;
};

class KMMailtoReplyCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMMailtoReplyCommand( KMainWindow *parent, KURL url, KMMsgBase *msgBase, 
                        QString selection );

private:
  virtual void execute();

  KURL mUrl;
  QString mSelection;
};

class KMMailtoForwardCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMMailtoForwardCommand( KMainWindow *parent, KURL url, KMMsgBase *msgBase );

private:
  virtual void execute();

  KURL mUrl;
};

class KMMailtoAddAddrBookCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMMailtoAddAddrBookCommand( KURL url, QWidget *parent );

private:
  virtual void execute();

  KURL mUrl;
  QWidget *mParent;
};

class KMMailtoOpenAddrBookCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMMailtoOpenAddrBookCommand( KURL url, QWidget *parent );

private:
  virtual void execute();

  KURL mUrl;
  QWidget *mParent;
};

class KMUrlCopyCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMUrlCopyCommand( KURL url, KMMainWin *mainWin = 0 );

private:
  virtual void execute();

  KURL mUrl;
  KMMainWin *mMainWin;
};

class KMUrlOpenCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMUrlOpenCommand( KURL url, KMReaderWin *readerWin );

private:
  virtual void execute();

  KURL mUrl;
  KMReaderWin *mReaderWin;
};

class KMUrlSaveCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMUrlSaveCommand( KURL url, QWidget *parent );

private slots:
  void slotUrlSaveResult( KIO::Job *job );

private:
  virtual void execute();

  KURL mUrl;
  QWidget *mParent;
};

class KMEditMsgCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMEditMsgCommand( KMainWindow *parent, KMMsgBase *msgBase );

private:
  virtual void execute();
};

class KMShowMsgSrcCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMShowMsgSrcCommand( KMainWindow *parent, KMMsgBase *msgBase, 
		       QTextCodec *codec, bool fixedFont );
  virtual void execute();

private:
  QTextCodec *mCodec;
  bool mFixedFont;
};

class KMSaveMsgCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMSaveMsgCommand( KMainWindow *parent, QPtrList<KMMsgBase> msgList, 
		    KMFolder *folder );
  KURL url();

private:
  virtual void execute();

private:
  KURL mUrl;
};

class KMDeleteMsgCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMDeleteMsgCommand( KMMsgBase *msgBase );
  virtual void execute();

private:
  KMMsgBase *mMsgBase;
};

class KMReplyToCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMReplyToCommand( KMainWindow *parent, KMMsgBase *msgBase, 
		    QString selection );

private:
  virtual void execute();

private:
  QString mSelection;
};


class KMReplyToAllCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMReplyToAllCommand( KMainWindow *parent, KMMsgBase *msgBase, 
		       QString selection );

private:
  virtual void execute();

private:
  QString mSelection;
};

class KMForwardCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMForwardCommand( KMainWindow *parent, QPtrList<KMMsgBase> msgList, 
		    KMFolder *folder );

private:
  virtual void execute();

private:
  QWidget *mParent;
  KMFolder *mFolder;
};

class KMForwardAttachedCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMForwardAttachedCommand( KMainWindow *parent, QPtrList<KMMsgBase> msgList, 
			    KMFolder *folder );

private:
  virtual void execute();

  KMFolder *mFolder;
};

class KMRedirectCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMRedirectCommand( KMainWindow *parent, KMMsgBase *msgBase );

private:
  virtual void execute();
};

class KMBounceCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMBounceCommand( KMainWindow *parent, KMMsgBase *msgBase );

private:
  virtual void execute();
};

class KMToggleFixedCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMToggleFixedCommand( KMReaderWin *readerWin );

private:
  virtual void execute();

  KMReaderWin *mReaderWin;
};

class KMPrintCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMPrintCommand( KMainWindow *parent, KMMsgBase *msgBase );

private:
  virtual void execute();
};

class KMSetStatusCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMSetStatusCommand( KMMsgStatus status, QValueList<int> ids, 
		      KMFolder *folder );

private:
  virtual void execute();

  KMMsgStatus mStatus;
  QValueList<int> mIds;
  KMFolder *mFolder;
};


class KMFilterCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMFilterCommand( QCString field, QString value );

private:
  virtual void execute();

  QCString mField;
  QString mValue;
};


class KMMailingListFilterCommand : public KMAsyncCommand
{
  Q_OBJECT

public:
  KMMailingListFilterCommand( KMMainWin *win, KMMsgBase *msgBase );

private:
  virtual void execute();
};


/*
delete
move
copy
*/

#endif /*KMCommands_h*/

["kmcommands.cpp" (text/x-c++src)]

#include <mimelib/enum.h>
#include <mimelib/field.h>
#include <mimelib/mimepp.h>
#include <qptrlist.h>
#include <qregexp.h>
#include <qtextcodec.h>
#include <kfiledialog.h>
#include <kio/netaccess.h>
#include <kio/job.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kparts/browserextension.h>
#include <kprogress.h>

#include "kbusyptr.h"
#include "mailinglist-magic.h"
#include "kmaddrbook.h"
#include "kmcomposewin.h"
#include "kmfiltermgr.h"
#include "kmfolder.h"
#include "kmfolderimap.h"
#include "kmheaders.h"
#include "kmkernel.h"
#include "kmmainwin.h"
#include "kmmessage.h"
#include "kmreaderwin.h"
#include "kmsender.h"

#include "kmcommands.h"
#include "kmcommands.moc"

#define IDENTITY_UOIDs

KMAsyncCommand::KMAsyncCommand( QWidget *parent )
  :mParent( parent ), mFolder( 0 )
{
}

KMAsyncCommand::KMAsyncCommand( QWidget *parent, QPtrList<KMMsgBase> msgList, 
				KMFolder *folder )
  :mParent( parent ), mMsgList( msgList ), mFolder( folder )
{
}

KMAsyncCommand::KMAsyncCommand( QWidget *parent, KMMsgBase *msgBase )
  :mParent( parent ), mFolder( msgBase->parent() )
{
  QPtrList< KMMsgBase > msgList;
  msgList.append( msgBase );
  mMsgList = msgList;
}

KMAsyncCommand::~KMAsyncCommand()
{
}

void KMAsyncCommand::start()
{
  preTransfer();    
}


QPtrList<KMMessage> *KMAsyncCommand::retrievedMsgs()
{
  return &mRetrievedMsgs;
}

KMMessage *KMAsyncCommand::retrievedMessage()
{
  return mRetrievedMsgs.getFirst();
}

int KMAsyncCommand::mCountJobs = 0;

void KMAsyncCommand::preTransfer()
{
  connect(this, SIGNAL(messagesTransfered(bool)),
	  this, SLOT(slotPostTransfer(bool)));
  if ( (mMsgList.count() > 0) && !mFolder) {
    emit messagesTransfered(false);
    return;
  }
  
  // transfer the selected messages first
  transferSelectedMsgs();
}

void KMAsyncCommand::slotPostTransfer(bool success)
{
  disconnect(this, SIGNAL(messagesTransfered(bool)),
	     this, SLOT(slotPostTransfer(bool)));
  if (success)
    execute();
  delete this;
}

void KMAsyncCommand::transferSelectedMsgs()
{
  // make sure no other transfer is active
  if (KMAsyncCommand::mCountJobs > 0) {
    emit messagesTransfered(false);
    return;
  }

  bool complete = true;
  KMAsyncCommand::mCountJobs = 0;
  mCountMsgs = 0;
  mRetrievedMsgs.clear();
  mCountMsgs = mMsgList.count();
  // the KProgressDialog for the user-feedback
  mProgressDialog = new KProgressDialog(mParent, "transferProgress",
      i18n("Please wait"),
      i18n("Please wait while the message is transferred",
        "Please wait while the %n messages are transferred", mMsgList.count()),
      true);
  mProgressDialog->setMinimumDuration(1000);
  for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
  {
    // check if all messages are complete
    int idx = mFolder->find(mb);
    if (idx < 0) continue;
    KMMessage *thisMsg = mFolder->getMsg(idx);
    if (!thisMsg) continue;

    if (thisMsg->parent() && thisMsg->parent()->protocol() == "imap" &&
        !thisMsg->isComplete() && !mProgressDialog->wasCancelled())
    {
      qDebug( "2" );
      // the message needs to be transferred first
      complete = false;
      KMAsyncCommand::mCountJobs++;
      KMImapJob *imapJob = new KMImapJob(thisMsg);
      // emitted when the message was transferred successfully
      connect(imapJob, SIGNAL(messageRetrieved(KMMessage*)),
          this, SLOT(slotMsgTransfered(KMMessage*)));
      // emitted when the job is destroyed
      connect(imapJob, SIGNAL(finished()),
          this, SLOT(slotJobFinished()));
      // msg musn't be deleted
      thisMsg->setTransferInProgress(true);
    } else {
      mRetrievedMsgs.append(thisMsg);
    }
  }

  if (complete)
  {
      qDebug( "1" );
    delete mProgressDialog;
    emit messagesTransfered(true);
  } else {
    // wait for the transfer and tell the progressBar the necessary steps
    connect(mProgressDialog, SIGNAL(cancelClicked()),
        this, SLOT(slotTransferCancelled()));
    mProgressDialog->progressBar()->setTotalSteps(KMAsyncCommand::mCountJobs);
  }
}

void KMAsyncCommand::slotMsgTransfered(KMMessage* msg)
{
  msg->setTransferInProgress(false);
  if (mProgressDialog->wasCancelled()) {
    emit messagesTransfered(false);
    return;
  }
  
  // save the complete messages
  mRetrievedMsgs.append(msg);
}

void KMAsyncCommand::slotJobFinished()
{
  // the job is finished (with / without error)
  KMAsyncCommand::mCountJobs--;

  if (mProgressDialog->wasCancelled()) return;

  if ( (mCountMsgs - static_cast<int>(mRetrievedMsgs.count())) > KMAsyncCommand::mCountJobs )
  {
    // the message wasn't retrieved before => error
    mProgressDialog->hide();
    slotTransferCancelled();
    return;
  }
  // update the progressbar
  mProgressDialog->progressBar()->advance(1);
  mProgressDialog->setLabel(i18n("Please wait while the message is transferred",
          "Please wait while the %n messages are transferred", KMAsyncCommand::mCountJobs));
  if (KMAsyncCommand::mCountJobs == 0)
  {
    // all done
    delete mProgressDialog;
    emit messagesTransfered(true);
  }
}

void KMAsyncCommand::slotTransferCancelled()
{
  if (mFolder->protocol() != "imap") {
    emit messagesTransfered(false);
    return;
  }

  // kill the pending jobs
  KMAcctImap* acct = static_cast<KMFolderImap*>(mFolder)->account();
  if (acct)
  {
    acct->killAllJobs();
    acct->setIdle(true);
  }

  KMAsyncCommand::mCountJobs = 0;
  mCountMsgs = 0;
  // unget the transfered messages
  QPtrListIterator<KMMessage> it( mRetrievedMsgs );
  KMMessage* msg;
  while ( (msg = it.current()) != 0 )
  {
    ++it;
    int idx = mFolder->find(msg);
    if (idx > 0) mFolder->unGetMsg(idx);
  }
  mRetrievedMsgs.clear();
  // unget the selected messages
  for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
  {
    if (mb->isMessage())
    {
      int idx = mFolder->find(mb);
      if (idx > 0) mFolder->unGetMsg(idx);
    }
  }
  emit messagesTransfered(false);
}

KMMailtoComposeCommand::KMMailtoComposeCommand( KURL url, KMMsgBase *msgBase )
  :mUrl( url ), mMsgBase( msgBase )
{
}

void KMMailtoComposeCommand::execute()
{
  KMComposeWin *win;
  KMMessage *msg = new KMMessage;
#ifdef IDENTITY_UOIDs
  uint id = 0;
#else
  QString id = "";
#endif

  if ( mMsgBase && mMsgBase->parent() )
    id = mMsgBase->parent()->identity();
  
  msg->initHeader(id);
  msg->setCharset("utf-8");
  msg->setTo(mUrl.path());

  win = new KMComposeWin(msg, id);
  win->setCharset("", TRUE);
  win->show();
}


KMMailtoReplyCommand::KMMailtoReplyCommand( KMainWindow *parent, KURL url, 
   KMMsgBase *msgBase, QString selection ) 
  :KMAsyncCommand( parent, msgBase ), mUrl( url ), mSelection( selection  )
{
}

void KMMailtoReplyCommand::execute()
{
  //TODO : consider factoring createReply into this method.
  KMMessage *msg = retrievedMessage();    
  KMComposeWin *win;
  KMMessage *rmsg = msg->createReply(FALSE, FALSE, mSelection );
  rmsg->setTo(mUrl.path());

#ifdef IDENTITY_UOIDs
  win = new KMComposeWin(rmsg, 0);
#else
  win = new KMComposeWin(rmsg, QString::null);
#endif
  win->setCharset(msg->codec()->mimeName(), TRUE);
  win->setReplyFocus();
  win->show();
}


KMMailtoForwardCommand::KMMailtoForwardCommand( KMainWindow *parent, KURL url, 
   KMMsgBase *msgBase )
  :KMAsyncCommand( parent, msgBase ), mUrl( url )
{
}

void KMMailtoForwardCommand::execute()
{
  //TODO : consider factoring createForward into this method.
  KMMessage *msg = retrievedMessage();
  KMComposeWin *win;
  KMMessage *fmsg = msg->createForward();
  fmsg->setTo(mUrl.path());

  win = new KMComposeWin(fmsg);
  win->setCharset(msg->codec()->mimeName(), TRUE);
  win->show();
}


KMMailtoAddAddrBookCommand::KMMailtoAddAddrBookCommand( KURL url,
   QWidget *parent )
  :mUrl( url ), mParent( parent )
{
}

void KMMailtoAddAddrBookCommand::execute()
{
  KMAddrBookExternal::addEmail(mUrl.path(), mParent );
}


KMMailtoOpenAddrBookCommand::KMMailtoOpenAddrBookCommand( KURL url,
   QWidget *parent )
  :mUrl( url ), mParent( parent )
{
}

void KMMailtoOpenAddrBookCommand::execute()
{
  KMAddrBookExternal::openEmail(mUrl.path(), mParent );
}


KMUrlCopyCommand::KMUrlCopyCommand( KURL url, KMMainWin *mainWin )
  :mUrl( url ), mMainWin( mainWin )
{
}

void KMUrlCopyCommand::execute()
{
  QClipboard* clip = QApplication::clipboard();

  if (mUrl.protocol() == "mailto") {
    // put the url into the mouse selection and the clipboard
    clip->setSelectionMode( true );
    clip->setText( mUrl.path() );
    clip->setSelectionMode( false );
    clip->setText( mUrl.path() );
    if (mMainWin)
      mMainWin->statusMsg( i18n( "Address copied to clipboard." ));
  } else {
    // put the url into the mouse selection and the clipboard
    clip->setSelectionMode( true );
    clip->setText( mUrl.url() );
    clip->setSelectionMode( false );
    clip->setText( mUrl.url() );
    if ( mMainWin )
      mMainWin->statusMsg( i18n( "URL copied to clipboard." ));
  }
}


KMUrlOpenCommand::KMUrlOpenCommand( KURL url, KMReaderWin *readerWin )
  :mUrl( url ), mReaderWin( readerWin )
{
}

void KMUrlOpenCommand::execute()
{
  if (mUrl.isEmpty()) return;
  mReaderWin->slotUrlOpen( mUrl, KParts::URLArgs() );
}


KMUrlSaveCommand::KMUrlSaveCommand( KURL url, QWidget *parent )
  :mUrl( url ), mParent( parent )
{
}

void KMUrlSaveCommand::execute()
{
  if (mUrl.isEmpty()) return;
  KURL saveUrl = KFileDialog::getSaveURL(mUrl.fileName(), QString::null,
    mParent);
  if (saveUrl.isEmpty()) return;
  if (KIO::NetAccess::exists(saveUrl))
  {
    if (KMessageBox::warningContinueCancel(0,
        i18n("File %1 exists.\nDo you want to replace it?")
        .arg(saveUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
        != KMessageBox::Continue)
      return;
  }
  KIO::Job *job = KIO::file_copy(mUrl, saveUrl, -1, true);
  connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotUrlSaveResult(KIO::Job*)));
}

void KMUrlSaveCommand::slotUrlSaveResult( KIO::Job *job )
{
  if (job->error()) job->showErrorDialog();
}


KMEditMsgCommand::KMEditMsgCommand( KMainWindow *parent, KMMsgBase *msgBase )
  :KMAsyncCommand( parent, msgBase )
{
}

void KMEditMsgCommand::execute()
{
  KMMessage *msg = retrievedMessage();    
  if (!msg || !msg->parent() ||
      !kernel->folderIsDraftOrOutbox( msg->parent() ))
    return;
  msg->parent()->removeMsg(msg);
#if 0
  // Useful?
  mHeaders->setSelected(mHeaders->currentItem(), TRUE);
  mHeaders->highlightMessage(mHeaders->currentItem(), true);
#endif

  KMComposeWin *win = new KMComposeWin();
#if 0
  // FIXME: Poor solution, won't work for multiple readerwins should use kmkernel as an observer
  QObject::connect( win, SIGNAL( messageQueuedOrDrafted()),
		    this, SLOT( slotMessageQueuedOrDrafted()) );
#endif
  win->setMsg(msg, FALSE, TRUE);
  win->setFolder( msg->parent() );
  win->show();
}


KMShowMsgSrcCommand::KMShowMsgSrcCommand( KMainWindow *parent, 
  KMMsgBase *msgBase, QTextCodec *codec, bool fixedFont )
  :KMAsyncCommand( parent, msgBase ), mCodec( codec ), mFixedFont( fixedFont )
{
}

void KMShowMsgSrcCommand::execute()
{
  //TODO: move KMMessage::viewSource to here
  KMMessage *msg = retrievedMessage();    
  if (!mCodec) //this is Auto setting
  {
    QCString cset = msg->charset();
    if (!cset.isEmpty())
      mCodec = KMMsgBase::codecForName( cset );
  }
  msg->viewSource( i18n("Message as Plain Text"), mCodec,
		   mFixedFont );
}

KMSaveMsgCommand::KMSaveMsgCommand( KMainWindow *parent,
  QPtrList<KMMsgBase> msgList, KMFolder *folder )
  :KMAsyncCommand( parent, msgList, folder )
{
  if (!msgList.getFirst())
    return;
  KMMsgBase *msgBase = msgList.getFirst();
  QString subject = msgBase->subject();
  while (subject.find(':') != -1)
    subject = subject.mid(subject.find(':') + 1).stripWhiteSpace();
  subject.replace(QRegExp(QChar(QDir::separator())), "_");
  mUrl = KFileDialog::getSaveURL(subject, QString::null);
}

KURL KMSaveMsgCommand::url()
{
  return mUrl;
}

void KMSaveMsgCommand::execute()
{
//TODO: Handle messages one by one
  QPtrList<KMMessage> *msgList = retrievedMsgs();
  QCString str;

  for (KMMessage *msg = msgList->first(); msg; msg = msgList->next()) {
    str += "From " + msg->fromEmail() + " " + msg->dateShortStr() + "\n";
    str += msg->asString();
    str += "\n";
  }

  QByteArray ba = str;
  ba.resize(ba.size() - 1);
  kernel->byteArrayToRemoteFile(ba, mUrl);
}

KMDeleteMsgCommand::KMDeleteMsgCommand( KMMsgBase *msgBase )
  :mMsgBase( msgBase )
{
}

void KMDeleteMsgCommand::execute()
{
}


KMReplyToCommand::KMReplyToCommand( KMainWindow *parent, KMMsgBase *msgBase,
				    QString selection )
  : KMAsyncCommand( parent, msgBase ), mSelection( selection )
{
}

void KMReplyToCommand::execute()
{
  kernel->kbp()->busy();
  KMMessage *msg = retrievedMessage();
  KMMessage *reply = msg->createReply( FALSE, FALSE, mSelection );
  KMComposeWin *win = new KMComposeWin( reply );
  win->setCharset( msg->codec()->mimeName(), TRUE );
  win->setReplyFocus();
  win->show();
  kernel->kbp()->idle();
}


KMReplyToAllCommand::KMReplyToAllCommand( KMainWindow *parent,
  KMMsgBase *msgBase, QString selection )
  :KMAsyncCommand( parent, msgBase ), mSelection( selection )
{
}

void KMReplyToAllCommand::execute()
{
  kernel->kbp()->busy();
  KMMessage *msg = retrievedMessage();
  KMMessage *reply = msg->createReply( TRUE, FALSE, mSelection );
  KMComposeWin *win = new KMComposeWin( reply );
  win->setCharset( msg->codec()->mimeName(), TRUE );
  win->setReplyFocus();
  win->show();
  kernel->kbp()->idle();
}


KMForwardCommand::KMForwardCommand( KMainWindow *parent,
  QPtrList<KMMsgBase> msgList, KMFolder *folder )
  : KMAsyncCommand( parent, msgList, folder ),
    mParent( parent ), mFolder( folder )
{
}

void KMForwardCommand::execute()
{
  KMComposeWin *win;
  QPtrList<KMMessage> *msgList = retrievedMsgs();
  
  if (msgList->count() >= 2) {
    // ask if they want a mime digest forward

    if (KMessageBox::questionYesNo(mParent, i18n("Forward selected messages as"
						 " a MIME digest?"))
	== KMessageBox::Yes) {
      // we default to the first identity to save prompting the user
      // (the messages could have different identities)
      uint id = 0;
      KMMessage *fwdMsg = new KMMessage;
      KMMessagePart *msgPart = new KMMessagePart;
      QString msgPartText;
      int msgCnt = 0; // incase there are some we can't forward for some reason

      fwdMsg->initHeader(id);
      fwdMsg->setAutomaticFields(true);
      fwdMsg->mMsg->Headers().ContentType().CreateBoundary(1);
      msgPartText = i18n("\nThis is a MIME digest forward. The content of the"
                         " message is contained in the attachment(s).\n\n\n"
                         "--\n");
      // iterate through all the messages to be forwarded
      for (KMMessage *msg = msgList->first(); msg; msg = msgList->next()) {
        // set the identity
        if (id == 0)
          id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
        // set the part header
        msgPartText += "--";
        msgPartText += fwdMsg->mMsg->Headers().ContentType().Boundary().c_str();
        msgPartText += "\nContent-Type: MESSAGE/RFC822";
        msgPartText += QString("; CHARSET=%1").arg(msg->charset());
        msgPartText += "\n";
        DwHeaders dwh;
        dwh.MessageId().CreateDefault();
        msgPartText += QString("Content-ID: %1\n").arg(dwh.MessageId().AsString().c_str());
        msgPartText += QString("Content-Description: %1").arg(msg->subject());
        if (!msg->subject().contains("(fwd)"))
          msgPartText += " (fwd)";
        msgPartText += "\n\n";
        // set the part
        msgPartText += msg->headerAsString();
        msgPartText += "\n";
        msgPartText += msg->body();
        msgPartText += "\n";     // eot
        msgCnt++;
        fwdMsg->link(msg, KMMsgStatusForwarded);
      }
      QCString tmp;
      msgPart->setTypeStr("MULTIPART");
      tmp.sprintf( "Digest; boundary=\"%s\"",
		   fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() );
      msgPart->setSubtypeStr( tmp );
      msgPart->setName("unnamed");
      msgPart->setCte(DwMime::kCte7bit);   // does it have to be 7bit?
      msgPart->setContentDescription(QString("Digest of %1 messages.").arg(msgCnt));
      // THIS HAS TO BE AFTER setCte()!!!!
      msgPart->setBodyEncoded(QCString(msgPartText.ascii()));
      kernel->kbp()->busy();
      win = new KMComposeWin(fwdMsg, id);
      win->addAttach(msgPart);
      win->show();
      kernel->kbp()->idle();
      return;
    } else {            // NO MIME DIGEST, Multiple forward
      uint id = 0;
      QCString msgText = "";
      QPtrList<KMMessage> linklist;
      for (KMMessage *msg = msgList->first(); msg; msg = msgList->next()) {
        // set the identity
        if (id == 0)
          id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();

        msgText += msg->createForwardBody();
        linklist.append(msg);
      }

      KMMessage *fwdMsg = new KMMessage;
      fwdMsg->initHeader(id);
      fwdMsg->setAutomaticFields(true);
      fwdMsg->setCharset("utf-8");
      fwdMsg->setBody(msgText);

      for (KMMessage *msg = linklist.first(); msg; msg = linklist.next())
        fwdMsg->link(msg, KMMsgStatusForwarded);

      kernel->kbp()->busy();
      win = new KMComposeWin(fwdMsg, id);
      win->setCharset("");
      win->show();
      kernel->kbp()->idle();
      return;
    }
  }

  // forward a single message at most.

  KMMessage *msg = msgList->getFirst();
  if (!msg || !msg->codec()) return;

  kernel->kbp()->busy();
  win = new KMComposeWin(msg->createForward());
  win->setCharset(msg->codec()->mimeName(), TRUE);
  win->show();
  kernel->kbp()->idle();
}


KMForwardAttachedCommand::KMForwardAttachedCommand( KMainWindow *parent,
  QPtrList<KMMsgBase> msgList, KMFolder *folder )
  : KMAsyncCommand( parent, msgList, folder ), mFolder( folder )
{
}

void KMForwardAttachedCommand::execute()
{
  QPtrList<KMMessage> *msgList = retrievedMsgs();
  KMComposeWin *win;
  uint id = 0;
  KMMessage *fwdMsg = new KMMessage;

  if (msgList->count() >= 2) {
    // don't respect X-KMail-Identity headers because they might differ for
    // the selected mails
    id = mFolder->identity();
    fwdMsg->initHeader(id);
  }
  else if (msgList->count() == 1) {
    KMMessage *msg = msgList->getFirst();
    fwdMsg->initFromMessage(msg);
  }

  fwdMsg->setAutomaticFields(true);

  kernel->kbp()->busy();
  win = new KMComposeWin(fwdMsg, id);

  // iterate through all the messages to be forwarded
  for (KMMessage *msg = msgList->first(); msg; msg = msgList->next()) {
    // set the part
    KMMessagePart *msgPart = new KMMessagePart;
    msgPart->setTypeStr("message");
    msgPart->setSubtypeStr("rfc822");
    msgPart->setCharset(msg->charset());
    msgPart->setName("forwarded message");
    msgPart->setCte(DwMime::kCte8bit);   // is 8bit O.K.?
    msgPart->setContentDescription(msg->from()+": "+msg->subject());
    // THIS HAS TO BE AFTER setCte()!!!!
    msgPart->setBodyEncoded(msg->asString());
    msgPart->setCharset("");

    fwdMsg->link(msg, KMMsgStatusForwarded);
    win->addAttach(msgPart);
  }

  win->show();
  kernel->kbp()->idle();
}


KMRedirectCommand::KMRedirectCommand( KMainWindow *parent,
  KMMsgBase *msgBase )
  : KMAsyncCommand( parent, msgBase )
{
}

void KMRedirectCommand::execute()
{
  //TODO: move KMMessage::createRedirect to here
  KMComposeWin *win;
  KMMessage *msg = retrievedMessage();
  if (!msg || !msg->codec()) return;

  kernel->kbp()->busy();
  win = new KMComposeWin();
  win->setMsg(msg->createRedirect(), FALSE);
  win->setCharset(msg->codec()->mimeName());
  win->show();
  kernel->kbp()->idle();
}


KMBounceCommand::KMBounceCommand( KMainWindow *parent,
  KMMsgBase *msgBase )
  : KMAsyncCommand( parent, msgBase )
{
}

void KMBounceCommand::execute()
{
  KMMessage *msg = retrievedMessage();
  KMMessage *newMsg = msg->createBounce( TRUE /* with UI */);
  if (newMsg)
    kernel->msgSender()->send(newMsg, kernel->msgSender()->sendImmediate());
}


KMToggleFixedCommand::KMToggleFixedCommand( KMReaderWin *readerWin )
  : KMAsyncCommand(), mReaderWin( readerWin )
{
}

void KMToggleFixedCommand::execute()
{
  mReaderWin->slotToggleFixedFont();
}


KMPrintCommand::KMPrintCommand( KMainWindow *parent, 
  KMMsgBase *msgBase )
  : KMAsyncCommand( parent, msgBase)
{
}

void KMPrintCommand::execute()
{
  KMReaderWin printWin;
  printWin.setPrinting(TRUE);
  printWin.readConfig();
  printWin.setMsg(retrievedMessage(), TRUE);
  printWin.printMsg();
}


//TODO: Use serial numbers
KMSetStatusCommand::KMSetStatusCommand( KMMsgStatus status, 
  QValueList<int> ids, KMFolder *folder )
  : mStatus( status ), mIds( ids ), mFolder( folder )
{
}

void KMSetStatusCommand::execute()
{
   mFolder->setStatus( mIds, mStatus );
}


KMFilterCommand::KMFilterCommand( QCString field, QString value )
  : mField( field ), mValue( value )
{
}

void KMFilterCommand::execute()
{
  kernel->filterMgr()->createFilter( mField, mValue );
}


KMMailingListFilterCommand::KMMailingListFilterCommand( KMMainWin *win,
  KMMsgBase *msgBase )
  : KMAsyncCommand( win, msgBase )
{
}

void KMMailingListFilterCommand::execute()
{
  QCString name;
  QString value;
  KMMessage *msg = retrievedMessage();
  if (!msg)
    return;

  if (!KMMLInfo::name( msg, name, value ).isNull())
    kernel->filterMgr()->createFilter( name, value );
}


_______________________________________________
KMail Developers mailing list
kmail@mail.kde.org
http://mail.kde.org/mailman/listinfo/kmail

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic