kmail

kmfilteraction.cpp

Go to the documentation of this file.
00001 // kmfilteraction.cpp
00002 // The process methods really should use an enum instead of an int
00003 // -1 -> status unchanged, 0 -> success, 1 -> failure, 2-> critical failure
00004 // (GoOn),                 (Ok),         (ErrorButGoOn), (CriticalError)
00005 
00006 #ifdef HAVE_CONFIG_H
00007 #include <config.h>
00008 #endif
00009 
00010 #include "kmfilteraction.h"
00011 
00012 #include "kmcommands.h"
00013 #include "kmmsgpart.h"
00014 #include "kmfiltermgr.h"
00015 #include "kmfolderindex.h"
00016 #include "kmfoldermgr.h"
00017 #include "messagesender.h"
00018 #include "kmmainwidget.h"
00019 #include <libkpimidentities/identity.h>
00020 #include <libkpimidentities/identitymanager.h>
00021 #include <libkpimidentities/identitycombo.h>
00022 #include <libkdepim/kfileio.h>
00023 #include <libkdepim/collectingprocess.h>
00024 using KPIM::CollectingProcess;
00025 #include <mimelib/message.h>
00026 #include "kmfawidgets.h"
00027 #include "folderrequester.h"
00028 using KMail::FolderRequester;
00029 #include "kmmsgbase.h"
00030 #include "templateparser.h"
00031 #include "messageproperty.h"
00032 #include "actionscheduler.h"
00033 using KMail::MessageProperty;
00034 using KMail::ActionScheduler;
00035 #include "regexplineedit.h"
00036 using KMail::RegExpLineEdit;
00037 #include <kregexp3.h>
00038 #include <ktempfile.h>
00039 #include <kdebug.h>
00040 #include <klocale.h>
00041 #include <kprocess.h>
00042 #include <kaudioplayer.h>
00043 #include <kurlrequester.h>
00044 
00045 #include <qlabel.h>
00046 #include <qlayout.h>
00047 #include <qtextcodec.h>
00048 #include <qtimer.h>
00049 #include <qobject.h>
00050 #include <qstylesheet.h>
00051 #include <assert.h>
00052 
00053 
00054 //=============================================================================
00055 //
00056 // KMFilterAction
00057 //
00058 //=============================================================================
00059 
00060 KMFilterAction::KMFilterAction( const char* aName, const QString aLabel )
00061 {
00062   mName = aName;
00063   mLabel = aLabel;
00064 }
00065 
00066 KMFilterAction::~KMFilterAction()
00067 {
00068 }
00069 
00070 void KMFilterAction::processAsync(KMMessage* msg) const
00071 {
00072   ActionScheduler *handler = MessageProperty::filterHandler( msg );
00073   ReturnCode result = process( msg );
00074   if (handler)
00075     handler->actionMessage( result );
00076 }
00077 
00078 bool KMFilterAction::requiresBody(KMMsgBase*) const
00079 {
00080   return true;
00081 }
00082 
00083 KMFilterAction* KMFilterAction::newAction()
00084 {
00085   return 0;
00086 }
00087 
00088 QWidget* KMFilterAction::createParamWidget(QWidget* parent) const
00089 {
00090   return new QWidget(parent);
00091 }
00092 
00093 void KMFilterAction::applyParamWidgetValue(QWidget*)
00094 {
00095 }
00096 
00097 void KMFilterAction::setParamWidgetValue( QWidget * ) const
00098 {
00099 }
00100 
00101 void KMFilterAction::clearParamWidget( QWidget * ) const
00102 {
00103 }
00104 
00105 bool KMFilterAction::folderRemoved(KMFolder*, KMFolder*)
00106 {
00107   return false;
00108 }
00109 
00110 int KMFilterAction::tempOpenFolder(KMFolder* aFolder)
00111 {
00112   return kmkernel->filterMgr()->tempOpenFolder(aFolder);
00113 }
00114 
00115 void KMFilterAction::sendMDN( KMMessage * msg, KMime::MDN::DispositionType d,
00116                               const QValueList<KMime::MDN::DispositionModifier> & m ) {
00117   if ( !msg ) return;
00118 
00119   /* createMDN requires Return-Path and Disposition-Notification-To
00120    * if it is not set in the message we assume that the notification should go to the
00121    * sender
00122    */
00123   const QString returnPath = msg->headerField( "Return-Path" );
00124   const QString dispNoteTo = msg->headerField( "Disposition-Notification-To" );
00125   if ( returnPath.isEmpty() )
00126     msg->setHeaderField( "Return-Path", msg->from() );
00127   if ( dispNoteTo.isEmpty() )
00128     msg->setHeaderField( "Disposition-Notification-To", msg->from() );
00129 
00130   KMMessage * mdn = msg->createMDN( KMime::MDN::AutomaticAction, d, false, m );
00131   if ( mdn && !kmkernel->msgSender()->send( mdn, KMail::MessageSender::SendLater ) ) {
00132     kdDebug(5006) << "KMFilterAction::sendMDN(): sending failed." << endl;
00133     //delete mdn;
00134   }
00135 
00136   //restore orignial header
00137   if ( returnPath.isEmpty() )
00138     msg->removeHeaderField( "Return-Path" );
00139   if ( dispNoteTo.isEmpty() )
00140     msg->removeHeaderField( "Disposition-Notification-To" );
00141 }
00142 
00143 
00144 //=============================================================================
00145 //
00146 // KMFilterActionWithNone
00147 //
00148 //=============================================================================
00149 
00150 KMFilterActionWithNone::KMFilterActionWithNone( const char* aName, const QString aLabel )
00151   : KMFilterAction( aName, aLabel )
00152 {
00153 }
00154 
00155 const QString KMFilterActionWithNone::displayString() const
00156 {
00157   return label();
00158 }
00159 
00160 
00161 //=============================================================================
00162 //
00163 // KMFilterActionWithUOID
00164 //
00165 //=============================================================================
00166 
00167 KMFilterActionWithUOID::KMFilterActionWithUOID( const char* aName, const QString aLabel )
00168   : KMFilterAction( aName, aLabel ), mParameter( 0 )
00169 {
00170 }
00171 
00172 void KMFilterActionWithUOID::argsFromString( const QString argsStr )
00173 {
00174   mParameter = argsStr.stripWhiteSpace().toUInt();
00175 }
00176 
00177 const QString KMFilterActionWithUOID::argsAsString() const
00178 {
00179   return QString::number( mParameter );
00180 }
00181 
00182 const QString KMFilterActionWithUOID::displayString() const
00183 {
00184   // FIXME after string freeze:
00185   // return i18n("").arg( );
00186   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
00187 }
00188 
00189 
00190 //=============================================================================
00191 //
00192 // KMFilterActionWithString
00193 //
00194 //=============================================================================
00195 
00196 KMFilterActionWithString::KMFilterActionWithString( const char* aName, const QString aLabel )
00197   : KMFilterAction( aName, aLabel )
00198 {
00199 }
00200 
00201 QWidget* KMFilterActionWithString::createParamWidget( QWidget* parent ) const
00202 {
00203   QLineEdit *le = new KLineEdit(parent);
00204   le->setText( mParameter );
00205   return le;
00206 }
00207 
00208 void KMFilterActionWithString::applyParamWidgetValue( QWidget* paramWidget )
00209 {
00210   mParameter = ((QLineEdit*)paramWidget)->text();
00211 }
00212 
00213 void KMFilterActionWithString::setParamWidgetValue( QWidget* paramWidget ) const
00214 {
00215   ((QLineEdit*)paramWidget)->setText( mParameter );
00216 }
00217 
00218 void KMFilterActionWithString::clearParamWidget( QWidget* paramWidget ) const
00219 {
00220   ((QLineEdit*)paramWidget)->clear();
00221 }
00222 
00223 void KMFilterActionWithString::argsFromString( const QString argsStr )
00224 {
00225   mParameter = argsStr;
00226 }
00227 
00228 const QString KMFilterActionWithString::argsAsString() const
00229 {
00230   return mParameter;
00231 }
00232 
00233 const QString KMFilterActionWithString::displayString() const
00234 {
00235   // FIXME after string freeze:
00236   // return i18n("").arg( );
00237   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
00238 }
00239 
00240 //=============================================================================
00241 //
00242 // class KMFilterActionWithStringList
00243 //
00244 //=============================================================================
00245 
00246 KMFilterActionWithStringList::KMFilterActionWithStringList( const char* aName, const QString aLabel )
00247   : KMFilterActionWithString( aName, aLabel )
00248 {
00249 }
00250 
00251 QWidget* KMFilterActionWithStringList::createParamWidget( QWidget* parent ) const
00252 {
00253   QComboBox *cb = new QComboBox( false, parent );
00254   cb->insertStringList( mParameterList );
00255   setParamWidgetValue( cb );
00256   return cb;
00257 }
00258 
00259 void KMFilterActionWithStringList::applyParamWidgetValue( QWidget* paramWidget )
00260 {
00261   mParameter = ((QComboBox*)paramWidget)->currentText();
00262 }
00263 
00264 void KMFilterActionWithStringList::setParamWidgetValue( QWidget* paramWidget ) const
00265 {
00266   int idx = mParameterList.findIndex( mParameter );
00267   ((QComboBox*)paramWidget)->setCurrentItem( idx >= 0 ? idx : 0 );
00268 }
00269 
00270 void KMFilterActionWithStringList::clearParamWidget( QWidget* paramWidget ) const
00271 {
00272   ((QComboBox*)paramWidget)->setCurrentItem(0);
00273 }
00274 
00275 void KMFilterActionWithStringList::argsFromString( const QString argsStr )
00276 {
00277   int idx = mParameterList.findIndex( argsStr );
00278   if ( idx < 0 ) {
00279     mParameterList.append( argsStr );
00280     idx = mParameterList.count() - 1;
00281   }
00282   mParameter = *mParameterList.at( idx );
00283 }
00284 
00285 
00286 //=============================================================================
00287 //
00288 // class KMFilterActionWithFolder
00289 //
00290 //=============================================================================
00291 
00292 KMFilterActionWithFolder::KMFilterActionWithFolder( const char* aName, const QString aLabel )
00293   : KMFilterAction( aName, aLabel )
00294 {
00295   mFolder = 0;
00296 }
00297 
00298 QWidget* KMFilterActionWithFolder::createParamWidget( QWidget* parent ) const
00299 {
00300   FolderRequester *req = new FolderRequester( parent,
00301       kmkernel->getKMMainWidget()->folderTree() );
00302   setParamWidgetValue( req );
00303   return req;
00304 }
00305 
00306 void KMFilterActionWithFolder::applyParamWidgetValue( QWidget* paramWidget )
00307 {
00308   mFolder = ((FolderRequester *)paramWidget)->folder();
00309   mFolderName = ((FolderRequester *)paramWidget)->folderId();
00310 }
00311 
00312 void KMFilterActionWithFolder::setParamWidgetValue( QWidget* paramWidget ) const
00313 {
00314   if ( mFolder )
00315     ((FolderRequester *)paramWidget)->setFolder( mFolder );
00316   else
00317     ((FolderRequester *)paramWidget)->setFolder( mFolderName );
00318 }
00319 
00320 void KMFilterActionWithFolder::clearParamWidget( QWidget* paramWidget ) const
00321 {
00322   ((FolderRequester *)paramWidget)->setFolder( kmkernel->draftsFolder() );
00323 }
00324 
00325 void KMFilterActionWithFolder::argsFromString( const QString argsStr )
00326 {
00327   mFolder = kmkernel->folderMgr()->findIdString( argsStr );
00328   if (!mFolder)
00329      mFolder = kmkernel->dimapFolderMgr()->findIdString( argsStr );
00330   if (!mFolder)
00331      mFolder = kmkernel->imapFolderMgr()->findIdString( argsStr );
00332   if (mFolder)
00333      mFolderName = mFolder->idString();
00334   else
00335      mFolderName = argsStr;
00336 }
00337 
00338 const QString KMFilterActionWithFolder::argsAsString() const
00339 {
00340   QString result;
00341   if ( mFolder )
00342     result = mFolder->idString();
00343   else
00344     result = mFolderName;
00345   return result;
00346 }
00347 
00348 const QString KMFilterActionWithFolder::displayString() const
00349 {
00350   QString result;
00351   if ( mFolder )
00352     result = mFolder->prettyURL();
00353   else
00354     result = mFolderName;
00355   return label() + " \"" + QStyleSheet::escape( result ) + "\"";
00356 }
00357 
00358 bool KMFilterActionWithFolder::folderRemoved( KMFolder* aFolder, KMFolder* aNewFolder )
00359 {
00360   if ( aFolder == mFolder ) {
00361     mFolder = aNewFolder;
00362     if ( aNewFolder )
00363       mFolderName = mFolder->idString();
00364     return true;
00365   } else
00366     return false;
00367 }
00368 
00369 //=============================================================================
00370 //
00371 // class KMFilterActionWithAddress
00372 //
00373 //=============================================================================
00374 
00375 KMFilterActionWithAddress::KMFilterActionWithAddress( const char* aName, const QString aLabel )
00376   : KMFilterActionWithString( aName, aLabel )
00377 {
00378 }
00379 
00380 QWidget* KMFilterActionWithAddress::createParamWidget( QWidget* parent ) const
00381 {
00382   KMFilterActionWithAddressWidget *w = new KMFilterActionWithAddressWidget(parent);
00383   w->setText( mParameter );
00384   return w;
00385 }
00386 
00387 void KMFilterActionWithAddress::applyParamWidgetValue( QWidget* paramWidget )
00388 {
00389   mParameter = ((KMFilterActionWithAddressWidget*)paramWidget)->text();
00390 }
00391 
00392 void KMFilterActionWithAddress::setParamWidgetValue( QWidget* paramWidget ) const
00393 {
00394   ((KMFilterActionWithAddressWidget*)paramWidget)->setText( mParameter );
00395 }
00396 
00397 void KMFilterActionWithAddress::clearParamWidget( QWidget* paramWidget ) const
00398 {
00399   ((KMFilterActionWithAddressWidget*)paramWidget)->clear();
00400 }
00401 
00402 //=============================================================================
00403 //
00404 // class KMFilterActionWithCommand
00405 //
00406 //=============================================================================
00407 
00408 KMFilterActionWithCommand::KMFilterActionWithCommand( const char* aName, const QString aLabel )
00409   : KMFilterActionWithUrl( aName, aLabel )
00410 {
00411 }
00412 
00413 QWidget* KMFilterActionWithCommand::createParamWidget( QWidget* parent ) const
00414 {
00415   return KMFilterActionWithUrl::createParamWidget( parent );
00416 }
00417 
00418 void KMFilterActionWithCommand::applyParamWidgetValue( QWidget* paramWidget )
00419 {
00420   KMFilterActionWithUrl::applyParamWidgetValue( paramWidget );
00421 }
00422 
00423 void KMFilterActionWithCommand::setParamWidgetValue( QWidget* paramWidget ) const
00424 {
00425   KMFilterActionWithUrl::setParamWidgetValue( paramWidget );
00426 }
00427 
00428 void KMFilterActionWithCommand::clearParamWidget( QWidget* paramWidget ) const
00429 {
00430   KMFilterActionWithUrl::clearParamWidget( paramWidget );
00431 }
00432 
00433 QString KMFilterActionWithCommand::substituteCommandLineArgsFor( KMMessage *aMsg, QPtrList<KTempFile> & aTempFileList ) const
00434 {
00435   QString result = mParameter;
00436   QValueList<int> argList;
00437   QRegExp r( "%[0-9-]+" );
00438 
00439   // search for '%n'
00440   int start = -1;
00441   while ( ( start = r.search( result, start + 1 ) ) > 0 ) {
00442     int len = r.matchedLength();
00443     // and save the encountered 'n' in a list.
00444     bool OK = false;
00445     int n = result.mid( start + 1, len - 1 ).toInt( &OK );
00446     if ( OK )
00447       argList.append( n );
00448   }
00449 
00450   // sort the list of n's
00451   qHeapSort( argList );
00452 
00453   // and use QString::arg to substitute filenames for the %n's.
00454   int lastSeen = -2;
00455   QString tempFileName;
00456   for ( QValueList<int>::Iterator it = argList.begin() ; it != argList.end() ; ++it ) {
00457     // setup temp files with check for duplicate %n's
00458     if ( (*it) != lastSeen ) {
00459       KTempFile *tf = new KTempFile();
00460       if ( tf->status() != 0 ) {
00461         tf->close();
00462         delete tf;
00463         kdDebug(5006) << "KMFilterActionWithCommand: Could not create temp file!" << endl;
00464         return QString::null;
00465       }
00466       tf->setAutoDelete(true);
00467       aTempFileList.append( tf );
00468       tempFileName = tf->name();
00469       if ((*it) == -1)
00470         KPIM::kCStringToFile( aMsg->asString(), tempFileName, //###
00471                           false, false, false );
00472       else if (aMsg->numBodyParts() == 0)
00473         KPIM::kByteArrayToFile( aMsg->bodyDecodedBinary(), tempFileName,
00474                           false, false, false );
00475       else {
00476         KMMessagePart msgPart;
00477         aMsg->bodyPart( (*it), &msgPart );
00478         KPIM::kByteArrayToFile( msgPart.bodyDecodedBinary(), tempFileName,
00479                           false, false, false );
00480       }
00481       tf->close();
00482     }
00483     // QString( "%0 and %1 and %1" ).arg( 0 ).arg( 1 )
00484     // returns "0 and 1 and %1", so we must call .arg as
00485     // many times as there are %n's, regardless of their multiplicity.
00486     if ((*it) == -1) result.replace( "%-1", tempFileName );
00487     else result = result.arg( tempFileName );
00488   }
00489 
00490   // And finally, replace the %{foo} with the content of the foo
00491   // header field:
00492   QRegExp header_rx( "%\\{([a-z0-9-]+)\\}", false );
00493   int idx = 0;
00494   while ( ( idx = header_rx.search( result, idx ) ) != -1 ) {
00495     QString replacement = KProcess::quote( aMsg->headerField( header_rx.cap(1).latin1() ) );
00496     result.replace( idx, header_rx.matchedLength(), replacement );
00497     idx += replacement.length();
00498   }
00499 
00500   return result;
00501 }
00502 
00503 
00504 KMFilterAction::ReturnCode KMFilterActionWithCommand::genericProcess(KMMessage* aMsg, bool withOutput) const
00505 {
00506   Q_ASSERT( aMsg );
00507 
00508   if ( mParameter.isEmpty() )
00509     return ErrorButGoOn;
00510 
00511   // KProcess doesn't support a QProcess::launch() equivalent, so
00512   // we must use a temp file :-(
00513   KTempFile * inFile = new KTempFile;
00514   inFile->setAutoDelete(true);
00515 
00516   QPtrList<KTempFile> atmList;
00517   atmList.setAutoDelete(true);
00518   atmList.append( inFile );
00519 
00520   QString commandLine = substituteCommandLineArgsFor( aMsg , atmList );
00521   if ( commandLine.isEmpty() )
00522     return ErrorButGoOn;
00523 
00524   // The parentheses force the creation of a subshell
00525   // in which the user-specified command is executed.
00526   // This is to really catch all output of the command as well
00527   // as to avoid clashes of our redirection with the ones
00528   // the user may have specified. In the long run, we
00529   // shouldn't be using tempfiles at all for this class, due
00530   // to security aspects. (mmutz)
00531   commandLine =  "(" + commandLine + ") <" + inFile->name();
00532 
00533   // write message to file
00534   QString tempFileName = inFile->name();
00535   KPIM::kCStringToFile( aMsg->asString(), tempFileName, //###
00536                   false, false, false );
00537   inFile->close();
00538 
00539   CollectingProcess shProc;
00540   shProc.setUseShell(true);
00541   shProc << commandLine;
00542 
00543   // run process:
00544   if ( !shProc.start( KProcess::Block,
00545                       withOutput ? KProcess::Stdout
00546                                  : KProcess::NoCommunication ) )
00547     return ErrorButGoOn;
00548 
00549   if ( !shProc.normalExit() || shProc.exitStatus() != 0 ) {
00550     return ErrorButGoOn;
00551   }
00552 
00553   if ( withOutput ) {
00554     // read altered message:
00555     QByteArray msgText = shProc.collectedStdout();
00556 
00557     if ( !msgText.isEmpty() ) {
00558     /* If the pipe through alters the message, it could very well
00559        happen that it no longer has a X-UID header afterwards. That is
00560        unfortunate, as we need to removed the original from the folder
00561        using that, and look it up in the message. When the (new) message
00562        is uploaded, the header is stripped anyhow. */
00563       QString uid = aMsg->headerField("X-UID");
00564       aMsg->fromByteArray( msgText );
00565       aMsg->setHeaderField("X-UID",uid);
00566     }
00567     else
00568       return ErrorButGoOn;
00569   }
00570   return GoOn;
00571 }
00572 
00573 
00574 //=============================================================================
00575 //
00576 //   Specific  Filter  Actions
00577 //
00578 //=============================================================================
00579 
00580 //=============================================================================
00581 // KMFilterActionSendReceipt - send receipt
00582 // Return delivery receipt.
00583 //=============================================================================
00584 class KMFilterActionSendReceipt : public KMFilterActionWithNone
00585 {
00586 public:
00587   KMFilterActionSendReceipt();
00588   virtual ReturnCode process(KMMessage* msg) const;
00589   static KMFilterAction* newAction(void);
00590 };
00591 
00592 KMFilterAction* KMFilterActionSendReceipt::newAction(void)
00593 {
00594   return (new KMFilterActionSendReceipt);
00595 }
00596 
00597 KMFilterActionSendReceipt::KMFilterActionSendReceipt()
00598   : KMFilterActionWithNone( "confirm delivery", i18n("Confirm Delivery") )
00599 {
00600 }
00601 
00602 KMFilterAction::ReturnCode KMFilterActionSendReceipt::process(KMMessage* msg) const
00603 {
00604   KMMessage *receipt = msg->createDeliveryReceipt();
00605   if ( !receipt ) return ErrorButGoOn;
00606 
00607   // Queue message. This is a) so that the user can check
00608   // the receipt before sending and b) for speed reasons.
00609   kmkernel->msgSender()->send( receipt, KMail::MessageSender::SendLater );
00610 
00611   return GoOn;
00612 }
00613 
00614 
00615 
00616 //=============================================================================
00617 // KMFilterActionSetTransport - set transport to...
00618 // Specify mail transport (smtp server) to be used when replying to a message
00619 //=============================================================================
00620 class KMFilterActionTransport: public KMFilterActionWithString
00621 {
00622 public:
00623   KMFilterActionTransport();
00624   virtual ReturnCode process(KMMessage* msg) const;
00625   static KMFilterAction* newAction(void);
00626 };
00627 
00628 KMFilterAction* KMFilterActionTransport::newAction(void)
00629 {
00630   return (new KMFilterActionTransport);
00631 }
00632 
00633 KMFilterActionTransport::KMFilterActionTransport()
00634   : KMFilterActionWithString( "set transport", i18n("Set Transport To") )
00635 {
00636 }
00637 
00638 KMFilterAction::ReturnCode KMFilterActionTransport::process(KMMessage* msg) const
00639 {
00640   if ( mParameter.isEmpty() )
00641     return ErrorButGoOn;
00642   msg->setHeaderField( "X-KMail-Transport", mParameter );
00643   return GoOn;
00644 }
00645 
00646 
00647 //=============================================================================
00648 // KMFilterActionReplyTo - set Reply-To to
00649 // Set the Reply-to header in a message
00650 //=============================================================================
00651 class KMFilterActionReplyTo: public KMFilterActionWithString
00652 {
00653 public:
00654   KMFilterActionReplyTo();
00655   virtual ReturnCode process(KMMessage* msg) const;
00656   static KMFilterAction* newAction(void);
00657 };
00658 
00659 KMFilterAction* KMFilterActionReplyTo::newAction(void)
00660 {
00661   return (new KMFilterActionReplyTo);
00662 }
00663 
00664 KMFilterActionReplyTo::KMFilterActionReplyTo()
00665   : KMFilterActionWithString( "set Reply-To", i18n("Set Reply-To To") )
00666 {
00667   mParameter = "";
00668 }
00669 
00670 KMFilterAction::ReturnCode KMFilterActionReplyTo::process(KMMessage* msg) const
00671 {
00672   msg->setHeaderField( "Reply-To", mParameter );
00673   return GoOn;
00674 }
00675 
00676 
00677 
00678 //=============================================================================
00679 // KMFilterActionIdentity - set identity to
00680 // Specify Identity to be used when replying to a message
00681 //=============================================================================
00682 class KMFilterActionIdentity: public KMFilterActionWithUOID
00683 {
00684 public:
00685   KMFilterActionIdentity();
00686   virtual ReturnCode process(KMMessage* msg) const;
00687   static KMFilterAction* newAction();
00688 
00689   QWidget * createParamWidget( QWidget * parent ) const;
00690   void applyParamWidgetValue( QWidget * parent );
00691   void setParamWidgetValue( QWidget * parent ) const;
00692   void clearParamWidget( QWidget * param ) const;
00693 };
00694 
00695 KMFilterAction* KMFilterActionIdentity::newAction()
00696 {
00697   return (new KMFilterActionIdentity);
00698 }
00699 
00700 KMFilterActionIdentity::KMFilterActionIdentity()
00701   : KMFilterActionWithUOID( "set identity", i18n("Set Identity To") )
00702 {
00703   mParameter = kmkernel->identityManager()->defaultIdentity().uoid();
00704 }
00705 
00706 KMFilterAction::ReturnCode KMFilterActionIdentity::process(KMMessage* msg) const
00707 {
00708   msg->setHeaderField( "X-KMail-Identity", QString::number( mParameter ) );
00709   return GoOn;
00710 }
00711 
00712 QWidget * KMFilterActionIdentity::createParamWidget( QWidget * parent ) const
00713 {
00714   KPIM::IdentityCombo * ic = new KPIM::IdentityCombo( kmkernel->identityManager(), parent );
00715   ic->setCurrentIdentity( mParameter );
00716   return ic;
00717 }
00718 
00719 void KMFilterActionIdentity::applyParamWidgetValue( QWidget * paramWidget )
00720 {
00721   KPIM::IdentityCombo * ic = dynamic_cast<KPIM::IdentityCombo*>( paramWidget );
00722   assert( ic );
00723   mParameter = ic->currentIdentity();
00724 }
00725 
00726 void KMFilterActionIdentity::clearParamWidget( QWidget * paramWidget ) const
00727 {
00728   KPIM::IdentityCombo * ic = dynamic_cast<KPIM::IdentityCombo*>( paramWidget );
00729   assert( ic );
00730   ic->setCurrentItem( 0 );
00731   //ic->setCurrentIdentity( kmkernel->identityManager()->defaultIdentity() );
00732 }
00733 
00734 void KMFilterActionIdentity::setParamWidgetValue( QWidget * paramWidget ) const
00735 {
00736   KPIM::IdentityCombo * ic = dynamic_cast<KPIM::IdentityCombo*>( paramWidget );
00737   assert( ic );
00738   ic->setCurrentIdentity( mParameter );
00739 }
00740 
00741 //=============================================================================
00742 // KMFilterActionSetStatus - set status to
00743 // Set the status of messages
00744 //=============================================================================
00745 class KMFilterActionSetStatus: public KMFilterActionWithStringList
00746 {
00747 public:
00748   KMFilterActionSetStatus();
00749   virtual ReturnCode process(KMMessage* msg) const;
00750   virtual bool requiresBody(KMMsgBase*) const;
00751 
00752   static KMFilterAction* newAction();
00753 
00754   virtual bool isEmpty() const { return false; }
00755 
00756   virtual void argsFromString( const QString argsStr );
00757   virtual const QString argsAsString() const;
00758   virtual const QString displayString() const;
00759 };
00760 
00761 
00762 static const KMMsgStatus stati[] =
00763 {
00764   KMMsgStatusFlag,
00765   KMMsgStatusRead,
00766   KMMsgStatusUnread,
00767   KMMsgStatusReplied,
00768   KMMsgStatusForwarded,
00769   KMMsgStatusOld,
00770   KMMsgStatusNew,
00771   KMMsgStatusWatched,
00772   KMMsgStatusIgnored,
00773   KMMsgStatusSpam,
00774   KMMsgStatusHam
00775 };
00776 static const int StatiCount = sizeof( stati ) / sizeof( KMMsgStatus );
00777 
00778 KMFilterAction* KMFilterActionSetStatus::newAction()
00779 {
00780   return (new KMFilterActionSetStatus);
00781 }
00782 
00783 KMFilterActionSetStatus::KMFilterActionSetStatus()
00784   : KMFilterActionWithStringList( "set status", i18n("Mark As") )
00785 {
00786   // if you change this list, also update
00787   // KMFilterActionSetStatus::stati above
00788   mParameterList.append( "" );
00789   mParameterList.append( i18n("msg status","Important") );
00790   mParameterList.append( i18n("msg status","Read") );
00791   mParameterList.append( i18n("msg status","Unread") );
00792   mParameterList.append( i18n("msg status","Replied") );
00793   mParameterList.append( i18n("msg status","Forwarded") );
00794   mParameterList.append( i18n("msg status","Old") );
00795   mParameterList.append( i18n("msg status","New") );
00796   mParameterList.append( i18n("msg status","Watched") );
00797   mParameterList.append( i18n("msg status","Ignored") );
00798   mParameterList.append( i18n("msg status","Spam") );
00799   mParameterList.append( i18n("msg status","Ham") );
00800 
00801   mParameter = *mParameterList.at(0);
00802 }
00803 
00804 KMFilterAction::ReturnCode KMFilterActionSetStatus::process(KMMessage* msg) const
00805 {
00806   int idx = mParameterList.findIndex( mParameter );
00807   if ( idx < 1 ) return ErrorButGoOn;
00808 
00809   KMMsgStatus status = stati[idx-1] ;
00810   msg->setStatus( status );
00811   return GoOn;
00812 }
00813 
00814 bool KMFilterActionSetStatus::requiresBody(KMMsgBase*) const
00815 {
00816   return false;
00817 }
00818 
00819 void KMFilterActionSetStatus::argsFromString( const QString argsStr )
00820 {
00821   if ( argsStr.length() == 1 ) {
00822     for ( int i = 0 ; i < StatiCount ; i++ )
00823       if ( KMMsgBase::statusToStr(stati[i])[0] == argsStr[0] ) {
00824         mParameter = *mParameterList.at(i+1);
00825         return;
00826       }
00827   }
00828   mParameter = *mParameterList.at(0);
00829 }
00830 
00831 const QString KMFilterActionSetStatus::argsAsString() const
00832 {
00833   int idx = mParameterList.findIndex( mParameter );
00834   if ( idx < 1 ) return QString::null;
00835 
00836   KMMsgStatus status = stati[idx-1];
00837   return KMMsgBase::statusToStr(status);
00838 }
00839 
00840 const QString KMFilterActionSetStatus::displayString() const
00841 {
00842   // FIXME after string freeze:
00843   // return i18n("").arg( );
00844   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
00845 }
00846 
00847 //=============================================================================
00848 // KMFilterActionFakeDisposition - send fake MDN
00849 // Sends a fake MDN or forces an ignore.
00850 //=============================================================================
00851 class KMFilterActionFakeDisposition: public KMFilterActionWithStringList
00852 {
00853 public:
00854   KMFilterActionFakeDisposition();
00855   virtual ReturnCode process(KMMessage* msg) const;
00856   static KMFilterAction* newAction() {
00857     return (new KMFilterActionFakeDisposition);
00858   }
00859 
00860   virtual bool isEmpty() const { return false; }
00861 
00862   virtual void argsFromString( const QString argsStr );
00863   virtual const QString argsAsString() const;
00864   virtual const QString displayString() const;
00865 };
00866 
00867 
00868 // if you change this list, also update
00869 // the count in argsFromString
00870 static const KMime::MDN::DispositionType mdns[] =
00871 {
00872   KMime::MDN::Displayed,
00873   KMime::MDN::Deleted,
00874   KMime::MDN::Dispatched,
00875   KMime::MDN::Processed,
00876   KMime::MDN::Denied,
00877   KMime::MDN::Failed,
00878 };
00879 static const int numMDNs = sizeof mdns / sizeof *mdns;
00880 
00881 
00882 KMFilterActionFakeDisposition::KMFilterActionFakeDisposition()
00883   : KMFilterActionWithStringList( "fake mdn", i18n("Send Fake MDN") )
00884 {
00885   // if you change this list, also update
00886   // mdns above
00887   mParameterList.append( "" );
00888   mParameterList.append( i18n("MDN type","Ignore") );
00889   mParameterList.append( i18n("MDN type","Displayed") );
00890   mParameterList.append( i18n("MDN type","Deleted") );
00891   mParameterList.append( i18n("MDN type","Dispatched") );
00892   mParameterList.append( i18n("MDN type","Processed") );
00893   mParameterList.append( i18n("MDN type","Denied") );
00894   mParameterList.append( i18n("MDN type","Failed") );
00895 
00896   mParameter = *mParameterList.at(0);
00897 }
00898 
00899 KMFilterAction::ReturnCode KMFilterActionFakeDisposition::process(KMMessage* msg) const
00900 {
00901   int idx = mParameterList.findIndex( mParameter );
00902   if ( idx < 1 ) return ErrorButGoOn;
00903 
00904   if ( idx == 1 ) // ignore
00905     msg->setMDNSentState( KMMsgMDNIgnore );
00906   else // send
00907     sendMDN( msg, mdns[idx-2] ); // skip first two entries: "" and "ignore"
00908   return GoOn;
00909 }
00910 
00911 void KMFilterActionFakeDisposition::argsFromString( const QString argsStr )
00912 {
00913   if ( argsStr.length() == 1 ) {
00914     if ( argsStr[0] == 'I' ) { // ignore
00915       mParameter = *mParameterList.at(1);
00916       return;
00917     }
00918     for ( int i = 0 ; i < numMDNs ; i++ )
00919       if ( char(mdns[i]) == argsStr[0] ) { // send
00920         mParameter = *mParameterList.at(i+2);
00921         return;
00922       }
00923   }
00924   mParameter = *mParameterList.at(0);
00925 }
00926 
00927 const QString KMFilterActionFakeDisposition::argsAsString() const
00928 {
00929   int idx = mParameterList.findIndex( mParameter );
00930   if ( idx < 1 ) return QString::null;
00931 
00932   return QString( QChar( idx < 2 ? 'I' : char(mdns[idx-2]) ) );
00933 }
00934 
00935 const QString KMFilterActionFakeDisposition::displayString() const
00936 {
00937   // FIXME after string freeze:
00938   // return i18n("").arg( );
00939   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
00940 }
00941 
00942 //=============================================================================
00943 // KMFilterActionRemoveHeader - remove header
00944 // Remove all instances of the given header field.
00945 //=============================================================================
00946 class KMFilterActionRemoveHeader: public KMFilterActionWithStringList
00947 {
00948 public:
00949   KMFilterActionRemoveHeader();
00950   virtual ReturnCode process(KMMessage* msg) const;
00951   virtual QWidget* createParamWidget( QWidget* parent ) const;
00952   virtual void setParamWidgetValue( QWidget* paramWidget ) const;
00953 
00954   static KMFilterAction* newAction();
00955 };
00956 
00957 KMFilterAction* KMFilterActionRemoveHeader::newAction()
00958 {
00959   return (new KMFilterActionRemoveHeader);
00960 }
00961 
00962 KMFilterActionRemoveHeader::KMFilterActionRemoveHeader()
00963   : KMFilterActionWithStringList( "remove header", i18n("Remove Header") )
00964 {
00965   mParameterList << ""
00966                  << "Reply-To"
00967                  << "Delivered-To"
00968                  << "X-KDE-PR-Message"
00969                  << "X-KDE-PR-Package"
00970                  << "X-KDE-PR-Keywords";
00971   mParameter = *mParameterList.at(0);
00972 }
00973 
00974 QWidget* KMFilterActionRemoveHeader::createParamWidget( QWidget* parent ) const
00975 {
00976   QComboBox *cb = new QComboBox( true/*editable*/, parent );
00977   cb->setInsertionPolicy( QComboBox::AtBottom );
00978   setParamWidgetValue( cb );
00979   return cb;
00980 }
00981 
00982 KMFilterAction::ReturnCode KMFilterActionRemoveHeader::process(KMMessage* msg) const
00983 {
00984   if ( mParameter.isEmpty() ) return ErrorButGoOn;
00985 
00986   while ( !msg->headerField( mParameter.latin1() ).isEmpty() )
00987     msg->removeHeaderField( mParameter.latin1() );
00988   return GoOn;
00989 }
00990 
00991 void KMFilterActionRemoveHeader::setParamWidgetValue( QWidget* paramWidget ) const
00992 {
00993   QComboBox * cb = dynamic_cast<QComboBox*>(paramWidget);
00994   Q_ASSERT( cb );
00995 
00996   int idx = mParameterList.findIndex( mParameter );
00997   cb->clear();
00998   cb->insertStringList( mParameterList );
00999   if ( idx < 0 ) {
01000     cb->insertItem( mParameter );
01001     cb->setCurrentItem( cb->count() - 1 );
01002   } else {
01003     cb->setCurrentItem( idx );
01004   }
01005 }
01006 
01007 
01008 //=============================================================================
01009 // KMFilterActionAddHeader - add header
01010 // Add a header with the given value.
01011 //=============================================================================
01012 class KMFilterActionAddHeader: public KMFilterActionWithStringList
01013 {
01014 public:
01015   KMFilterActionAddHeader();
01016   virtual ReturnCode process(KMMessage* msg) const;
01017   virtual QWidget* createParamWidget( QWidget* parent ) const;
01018   virtual void setParamWidgetValue( QWidget* paramWidget ) const;
01019   virtual void applyParamWidgetValue( QWidget* paramWidget );
01020   virtual void clearParamWidget( QWidget* paramWidget ) const;
01021 
01022   virtual const QString argsAsString() const;
01023   virtual void argsFromString( const QString argsStr );
01024 
01025   virtual const QString displayString() const;
01026 
01027   static KMFilterAction* newAction()
01028   {
01029     return (new KMFilterActionAddHeader);
01030   }
01031 private:
01032   QString mValue;
01033 };
01034 
01035 KMFilterActionAddHeader::KMFilterActionAddHeader()
01036   : KMFilterActionWithStringList( "add header", i18n("Add Header") )
01037 {
01038   mParameterList << ""
01039                  << "Reply-To"
01040                  << "Delivered-To"
01041                  << "X-KDE-PR-Message"
01042                  << "X-KDE-PR-Package"
01043                  << "X-KDE-PR-Keywords";
01044   mParameter = *mParameterList.at(0);
01045 }
01046 
01047 KMFilterAction::ReturnCode KMFilterActionAddHeader::process(KMMessage* msg) const
01048 {
01049   if ( mParameter.isEmpty() ) return ErrorButGoOn;
01050 
01051   msg->setHeaderField( mParameter.latin1(), mValue );
01052   return GoOn;
01053 }
01054 
01055 QWidget* KMFilterActionAddHeader::createParamWidget( QWidget* parent ) const
01056 {
01057   QWidget *w = new QWidget( parent );
01058   QHBoxLayout *hbl = new QHBoxLayout( w );
01059   hbl->setSpacing( 4 );
01060   QComboBox *cb = new QComboBox( true, w, "combo" );
01061   cb->setInsertionPolicy( QComboBox::AtBottom );
01062   hbl->addWidget( cb, 0 /* stretch */ );
01063   QLabel *l = new QLabel( i18n("With value:"), w );
01064   l->setFixedWidth( l->sizeHint().width() );
01065   hbl->addWidget( l, 0 );
01066   QLineEdit *le = new KLineEdit( w, "ledit" );
01067   hbl->addWidget( le, 1 );
01068   setParamWidgetValue( w );
01069   return w;
01070 }
01071 
01072 void KMFilterActionAddHeader::setParamWidgetValue( QWidget* paramWidget ) const
01073 {
01074   int idx = mParameterList.findIndex( mParameter );
01075   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01076   Q_ASSERT( cb );
01077   cb->clear();
01078   cb->insertStringList( mParameterList );
01079   if ( idx < 0 ) {
01080     cb->insertItem( mParameter );
01081     cb->setCurrentItem( cb->count() - 1 );
01082   } else {
01083     cb->setCurrentItem( idx );
01084   }
01085   QLineEdit *le = (QLineEdit*)paramWidget->child("ledit");
01086   Q_ASSERT( le );
01087   le->setText( mValue );
01088 }
01089 
01090 void KMFilterActionAddHeader::applyParamWidgetValue( QWidget* paramWidget )
01091 {
01092   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01093   Q_ASSERT( cb );
01094   mParameter = cb->currentText();
01095 
01096   QLineEdit *le = (QLineEdit*)paramWidget->child("ledit");
01097   Q_ASSERT( le );
01098   mValue = le->text();
01099 }
01100 
01101 void KMFilterActionAddHeader::clearParamWidget( QWidget* paramWidget ) const
01102 {
01103   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01104   Q_ASSERT( cb );
01105   cb->setCurrentItem(0);
01106   QLineEdit *le = (QLineEdit*)paramWidget->child("ledit");
01107   Q_ASSERT( le );
01108   le->clear();
01109 }
01110 
01111 const QString KMFilterActionAddHeader::argsAsString() const
01112 {
01113   QString result = mParameter;
01114   result += '\t';
01115   result += mValue;
01116 
01117   return result;
01118 }
01119 
01120 const QString KMFilterActionAddHeader::displayString() const
01121 {
01122   // FIXME after string freeze:
01123   // return i18n("").arg( );
01124   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
01125 }
01126 
01127 void KMFilterActionAddHeader::argsFromString( const QString argsStr )
01128 {
01129   QStringList l = QStringList::split( '\t', argsStr, true /*allow empty entries*/ );
01130   QString s;
01131   if ( l.count() < 2 ) {
01132     s = l[0];
01133     mValue = "";
01134   } else {
01135     s = l[0];
01136     mValue = l[1];
01137   }
01138 
01139   int idx = mParameterList.findIndex( s );
01140   if ( idx < 0 ) {
01141     mParameterList.append( s );
01142     idx = mParameterList.count() - 1;
01143   }
01144   mParameter = *mParameterList.at( idx );
01145 }
01146 
01147 
01148 //=============================================================================
01149 // KMFilterActionRewriteHeader - rewrite header
01150 // Rewrite a header using a regexp.
01151 //=============================================================================
01152 class KMFilterActionRewriteHeader: public KMFilterActionWithStringList
01153 {
01154 public:
01155   KMFilterActionRewriteHeader();
01156   virtual ReturnCode process(KMMessage* msg) const;
01157   virtual QWidget* createParamWidget( QWidget* parent ) const;
01158   virtual void setParamWidgetValue( QWidget* paramWidget ) const;
01159   virtual void applyParamWidgetValue( QWidget* paramWidget );
01160   virtual void clearParamWidget( QWidget* paramWidget ) const;
01161 
01162   virtual const QString argsAsString() const;
01163   virtual void argsFromString( const QString argsStr );
01164 
01165   virtual const QString displayString() const;
01166 
01167   static KMFilterAction* newAction()
01168   {
01169     return (new KMFilterActionRewriteHeader);
01170   }
01171 private:
01172   KRegExp3 mRegExp;
01173   QString mReplacementString;
01174 };
01175 
01176 KMFilterActionRewriteHeader::KMFilterActionRewriteHeader()
01177   : KMFilterActionWithStringList( "rewrite header", i18n("Rewrite Header") )
01178 {
01179   mParameterList << ""
01180                  << "Subject"
01181                  << "Reply-To"
01182                  << "Delivered-To"
01183                  << "X-KDE-PR-Message"
01184                  << "X-KDE-PR-Package"
01185                  << "X-KDE-PR-Keywords";
01186   mParameter = *mParameterList.at(0);
01187 }
01188 
01189 KMFilterAction::ReturnCode KMFilterActionRewriteHeader::process(KMMessage* msg) const
01190 {
01191   if ( mParameter.isEmpty() || !mRegExp.isValid() )
01192     return ErrorButGoOn;
01193 
01194   KRegExp3 rx = mRegExp; // KRegExp3::replace is not const.
01195 
01196   QString newValue = rx.replace( msg->headerField( mParameter.latin1() ),
01197                                      mReplacementString );
01198 
01199   msg->setHeaderField( mParameter.latin1(), newValue );
01200   return GoOn;
01201 }
01202 
01203 QWidget* KMFilterActionRewriteHeader::createParamWidget( QWidget* parent ) const
01204 {
01205   QWidget *w = new QWidget( parent );
01206   QHBoxLayout *hbl = new QHBoxLayout( w );
01207   hbl->setSpacing( 4 );
01208 
01209   QComboBox *cb = new QComboBox( true, w, "combo" );
01210   cb->setInsertionPolicy( QComboBox::AtBottom );
01211   hbl->addWidget( cb, 0 /* stretch */ );
01212 
01213   QLabel *l = new QLabel( i18n("Replace:"), w );
01214   l->setFixedWidth( l->sizeHint().width() );
01215   hbl->addWidget( l, 0 );
01216 
01217   RegExpLineEdit *rele = new RegExpLineEdit( w, "search" );
01218   hbl->addWidget( rele, 1 );
01219 
01220   l = new QLabel( i18n("With:"), w );
01221   l->setFixedWidth( l->sizeHint().width() );
01222   hbl->addWidget( l, 0 );
01223 
01224   QLineEdit *le = new KLineEdit( w, "replace" );
01225   hbl->addWidget( le, 1 );
01226 
01227   setParamWidgetValue( w );
01228   return w;
01229 }
01230 
01231 void KMFilterActionRewriteHeader::setParamWidgetValue( QWidget* paramWidget ) const
01232 {
01233   int idx = mParameterList.findIndex( mParameter );
01234   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01235   Q_ASSERT( cb );
01236 
01237   cb->clear();
01238   cb->insertStringList( mParameterList );
01239   if ( idx < 0 ) {
01240     cb->insertItem( mParameter );
01241     cb->setCurrentItem( cb->count() - 1 );
01242   } else {
01243     cb->setCurrentItem( idx );
01244   }
01245 
01246   RegExpLineEdit *rele = (RegExpLineEdit*)paramWidget->child("search");
01247   Q_ASSERT( rele );
01248   rele->setText( mRegExp.pattern() );
01249 
01250   QLineEdit *le = (QLineEdit*)paramWidget->child("replace");
01251   Q_ASSERT( le );
01252   le->setText( mReplacementString );
01253 }
01254 
01255 void KMFilterActionRewriteHeader::applyParamWidgetValue( QWidget* paramWidget )
01256 {
01257   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01258   Q_ASSERT( cb );
01259   mParameter = cb->currentText();
01260 
01261   RegExpLineEdit *rele = (RegExpLineEdit*)paramWidget->child("search");
01262   Q_ASSERT( rele );
01263   mRegExp.setPattern( rele->text() );
01264 
01265   QLineEdit *le = (QLineEdit*)paramWidget->child("replace");
01266   Q_ASSERT( le );
01267   mReplacementString = le->text();
01268 }
01269 
01270 void KMFilterActionRewriteHeader::clearParamWidget( QWidget* paramWidget ) const
01271 {
01272   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01273   Q_ASSERT( cb );
01274   cb->setCurrentItem(0);
01275 
01276   RegExpLineEdit *rele = (RegExpLineEdit*)paramWidget->child("search");
01277   Q_ASSERT( rele );
01278   rele->clear();
01279 
01280   QLineEdit *le = (QLineEdit*)paramWidget->child("replace");
01281   Q_ASSERT( le );
01282   le->clear();
01283 }
01284 
01285 const QString KMFilterActionRewriteHeader::argsAsString() const
01286 {
01287   QString result = mParameter;
01288   result += '\t';
01289   result += mRegExp.pattern();
01290   result += '\t';
01291   result += mReplacementString;
01292 
01293   return result;
01294 }
01295 
01296 const QString KMFilterActionRewriteHeader::displayString() const
01297 {
01298   // FIXME after string freeze:
01299   // return i18n("").arg( );
01300   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
01301 }
01302 
01303 void KMFilterActionRewriteHeader::argsFromString( const QString argsStr )
01304 {
01305   QStringList l = QStringList::split( '\t', argsStr, true /*allow empty entries*/ );
01306   QString s;
01307 
01308   s = l[0];
01309   mRegExp.setPattern( l[1] );
01310   mReplacementString = l[2];
01311 
01312   int idx = mParameterList.findIndex( s );
01313   if ( idx < 0 ) {
01314     mParameterList.append( s );
01315     idx = mParameterList.count() - 1;
01316   }
01317   mParameter = *mParameterList.at( idx );
01318 }
01319 
01320 
01321 //=============================================================================
01322 // KMFilterActionMove - move into folder
01323 // File message into another mail folder
01324 //=============================================================================
01325 class KMFilterActionMove: public KMFilterActionWithFolder
01326 {
01327 public:
01328   KMFilterActionMove();
01329   virtual ReturnCode process(KMMessage* msg) const;
01330   virtual bool requiresBody(KMMsgBase*) const;
01331   static KMFilterAction* newAction(void);
01332 };
01333 
01334 KMFilterAction* KMFilterActionMove::newAction(void)
01335 {
01336   return (new KMFilterActionMove);
01337 }
01338 
01339 KMFilterActionMove::KMFilterActionMove()
01340   : KMFilterActionWithFolder( "transfer", i18n("Move Into Folder") )
01341 {
01342 }
01343 
01344 KMFilterAction::ReturnCode KMFilterActionMove::process(KMMessage* msg) const
01345 {
01346   if ( !mFolder )
01347     return ErrorButGoOn;
01348 
01349   ActionScheduler *handler = MessageProperty::filterHandler( msg );
01350   if (handler) {
01351     MessageProperty::setFilterFolder( msg, mFolder );
01352   } else {
01353     // The old filtering system does not support online imap targets.
01354     // Skip online imap targets when using the old system.
01355     KMFolder *check;
01356     check = kmkernel->imapFolderMgr()->findIdString( argsAsString() );
01357     if (mFolder && (check != mFolder)) {
01358       MessageProperty::setFilterFolder( msg, mFolder );
01359     }
01360   }
01361   return GoOn;
01362 }
01363 
01364 bool KMFilterActionMove::requiresBody(KMMsgBase*) const
01365 {
01366     return false; //iff mFolder->folderMgr == msgBase->parent()->folderMgr;
01367 }
01368 
01369 
01370 //=============================================================================
01371 // KMFilterActionCopy - copy into folder
01372 // Copy message into another mail folder
01373 //=============================================================================
01374 class KMFilterActionCopy: public KMFilterActionWithFolder
01375 {
01376 public:
01377   KMFilterActionCopy();
01378   virtual ReturnCode process(KMMessage* msg) const;
01379   virtual void processAsync(KMMessage* msg) const;
01380   virtual bool requiresBody(KMMsgBase*) const;
01381   static KMFilterAction* newAction(void);
01382 };
01383 
01384 KMFilterAction* KMFilterActionCopy::newAction(void)
01385 {
01386   return (new KMFilterActionCopy);
01387 }
01388 
01389 KMFilterActionCopy::KMFilterActionCopy()
01390   : KMFilterActionWithFolder( "copy", i18n("Copy Into Folder") )
01391 {
01392 }
01393 
01394 KMFilterAction::ReturnCode KMFilterActionCopy::process(KMMessage* msg) const
01395 {
01396   // TODO opening and closing the folder is a trade off.
01397   // Perhaps Copy is a seldomly used action for now,
01398   // but I gonna look at improvements ASAP.
01399   if ( !mFolder )
01400     return ErrorButGoOn;
01401   if ( mFolder && mFolder->open( "filtercopy" ) != 0 )
01402     return ErrorButGoOn;
01403 
01404   // copy the message 1:1
01405   KMMessage* msgCopy = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
01406 
01407   int index;
01408   int rc = mFolder->addMsg(msgCopy, &index);
01409   if (rc == 0 && index != -1)
01410     mFolder->unGetMsg( index );
01411   mFolder->close("filtercopy");
01412 
01413   return GoOn;
01414 }
01415 
01416 void KMFilterActionCopy::processAsync(KMMessage* msg) const
01417 {
01418   // FIXME remove the debug output
01419   kdDebug(5006) << "##### KMFilterActionCopy::processAsync(KMMessage* msg)" << endl;
01420   ActionScheduler *handler = MessageProperty::filterHandler( msg );
01421 
01422   KMCommand *cmd = new KMCopyCommand( mFolder, msg );
01423   QObject::connect( cmd, SIGNAL( completed( KMCommand * ) ),
01424                     handler, SLOT( copyMessageFinished( KMCommand * ) ) );
01425   cmd->start();
01426 }
01427 
01428 bool KMFilterActionCopy::requiresBody(KMMsgBase*) const
01429 {
01430     return true;
01431 }
01432 
01433 
01434 //=============================================================================
01435 // KMFilterActionForward - forward to
01436 // Forward message to another user
01437 //=============================================================================
01438 class KMFilterActionForward: public KMFilterActionWithAddress
01439 {
01440 public:
01441   KMFilterActionForward();
01442   virtual ReturnCode process(KMMessage* msg) const;
01443   static KMFilterAction* newAction(void);
01444 };
01445 
01446 KMFilterAction* KMFilterActionForward::newAction(void)
01447 {
01448   return (new KMFilterActionForward);
01449 }
01450 
01451 KMFilterActionForward::KMFilterActionForward()
01452   : KMFilterActionWithAddress( "forward", i18n("Forward To") )
01453 {
01454 }
01455 
01456 KMFilterAction::ReturnCode KMFilterActionForward::process(KMMessage* aMsg) const
01457 {
01458   if ( mParameter.isEmpty() )
01459     return ErrorButGoOn;
01460 
01461   // avoid endless loops when this action is used in a filter
01462   // which applies to sent messages
01463   if ( KMMessage::addressIsInAddressList( mParameter, aMsg->to() ) )
01464     return ErrorButGoOn;
01465 
01466   // Create the forwarded message by hand to make forwarding of messages with
01467   // attachments work.
01468   // Note: This duplicates a lot of code from KMMessage::createForward() and
01469   //       KMComposeWin::applyChanges().
01470   // ### FIXME: Remove the code duplication again.
01471 
01472   KMMessage* msg = new KMMessage;
01473 
01474   msg->initFromMessage( aMsg );
01475 
01476   // QString st = QString::fromUtf8( aMsg->createForwardBody() );
01477 
01478   TemplateParser parser( msg, TemplateParser::Forward,
01479     aMsg->body(), false, false, false, false);
01480   parser.process( aMsg );
01481 
01482   QCString
01483     encoding = KMMsgBase::autoDetectCharset( aMsg->charset(),
01484                                              KMMessage::preferredCharsets(),
01485                                              msg->body() );
01486   if( encoding.isEmpty() )
01487     encoding = "utf-8";
01488   QCString str = KMMsgBase::codecForName( encoding )->fromUnicode( msg->body() );
01489 
01490   msg->setCharset( encoding );
01491   msg->setTo( mParameter );
01492   msg->setSubject( "Fwd: " + aMsg->subject() );
01493 
01494   bool isQP = kmkernel->msgSender()->sendQuotedPrintable();
01495 
01496   if( aMsg->numBodyParts() == 0 )
01497   {
01498     msg->setAutomaticFields( true );
01499     msg->setHeaderField( "Content-Type", "text/plain" );
01500     // msg->setCteStr( isQP ? "quoted-printable": "8bit" );
01501     QValueList<int> dummy;
01502     msg->setBodyAndGuessCte(str, dummy, !isQP);
01503     msg->setCharset( encoding );
01504     if( isQP )
01505       msg->setBodyEncoded( str );
01506     else
01507       msg->setBody( str );
01508   }
01509   else
01510   {
01511     KMMessagePart bodyPart, msgPart;
01512 
01513     msg->removeHeaderField( "Content-Type" );
01514     msg->removeHeaderField( "Content-Transfer-Encoding" );
01515     msg->setAutomaticFields( true );
01516     msg->setBody( "This message is in MIME format.\n\n" );
01517 
01518     bodyPart.setTypeStr( "text" );
01519     bodyPart.setSubtypeStr( "plain" );
01520     // bodyPart.setCteStr( isQP ? "quoted-printable": "8bit" );
01521     QValueList<int> dummy;
01522     bodyPart.setBodyAndGuessCte(str, dummy, !isQP);
01523     bodyPart.setCharset( encoding );
01524     bodyPart.setBodyEncoded( str );
01525     msg->addBodyPart( &bodyPart );
01526 
01527     for( int i = 0; i < aMsg->numBodyParts(); i++ )
01528     {
01529       aMsg->bodyPart( i, &msgPart );
01530       if( i > 0 || qstricmp( msgPart.typeStr(), "text" ) != 0 )
01531         msg->addBodyPart( &msgPart );
01532     }
01533   }
01534   msg->cleanupHeader();
01535   msg->link( aMsg, KMMsgStatusForwarded );
01536 
01537   sendMDN( aMsg, KMime::MDN::Dispatched );
01538 
01539   if ( !kmkernel->msgSender()->send( msg, KMail::MessageSender::SendLater ) ) {
01540     kdDebug(5006) << "KMFilterAction: could not forward message (sending failed)" << endl;
01541     return ErrorButGoOn; // error: couldn't send
01542   }
01543   return GoOn;
01544 }
01545 
01546 
01547 //=============================================================================
01548 // KMFilterActionRedirect - redirect to
01549 // Redirect message to another user
01550 //=============================================================================
01551 class KMFilterActionRedirect: public KMFilterActionWithAddress
01552 {
01553 public:
01554   KMFilterActionRedirect();
01555   virtual ReturnCode process(KMMessage* msg) const;
01556   static KMFilterAction* newAction(void);
01557 };
01558 
01559 KMFilterAction* KMFilterActionRedirect::newAction(void)
01560 {
01561   return (new KMFilterActionRedirect);
01562 }
01563 
01564 KMFilterActionRedirect::KMFilterActionRedirect()
01565   : KMFilterActionWithAddress( "redirect", i18n("Redirect To") )
01566 {
01567 }
01568 
01569 KMFilterAction::ReturnCode KMFilterActionRedirect::process(KMMessage* aMsg) const
01570 {
01571   KMMessage* msg;
01572   if ( mParameter.isEmpty() )
01573     return ErrorButGoOn;
01574 
01575   msg = aMsg->createRedirect( mParameter );
01576 
01577   sendMDN( aMsg, KMime::MDN::Dispatched );
01578 
01579   if ( !kmkernel->msgSender()->send( msg, KMail::MessageSender::SendLater ) ) {
01580     kdDebug(5006) << "KMFilterAction: could not redirect message (sending failed)" << endl;
01581     return ErrorButGoOn; // error: couldn't send
01582   }
01583   return GoOn;
01584 }
01585 
01586 
01587 //=============================================================================
01588 // KMFilterActionExec - execute command
01589 // Execute a shell command
01590 //=============================================================================
01591 class KMFilterActionExec : public KMFilterActionWithCommand
01592 {
01593 public:
01594   KMFilterActionExec();
01595   virtual ReturnCode process(KMMessage* msg) const;
01596   static KMFilterAction* newAction(void);
01597 };
01598 
01599 KMFilterAction* KMFilterActionExec::newAction(void)
01600 {
01601   return (new KMFilterActionExec());
01602 }
01603 
01604 KMFilterActionExec::KMFilterActionExec()
01605   : KMFilterActionWithCommand( "execute", i18n("Execute Command") )
01606 {
01607 }
01608 
01609 KMFilterAction::ReturnCode KMFilterActionExec::process(KMMessage *aMsg) const
01610 {
01611   return KMFilterActionWithCommand::genericProcess( aMsg, false ); // ignore output
01612 }
01613 
01614 //=============================================================================
01615 // KMFilterActionExtFilter - use external filter app
01616 // External message filter: executes a shell command with message
01617 // on stdin; altered message is expected on stdout.
01618 //=============================================================================
01619 
01620 #include <weaver.h>
01621 class PipeJob : public KPIM::ThreadWeaver::Job
01622 {
01623   public:
01624     PipeJob(QObject* parent = 0 , const char* name = 0, KMMessage* aMsg = 0, QString cmd = 0, QString tempFileName = 0 )
01625       : Job (parent, name),
01626         mTempFileName(tempFileName),
01627         mCmd(cmd),
01628         mMsg( aMsg )
01629     {
01630     }
01631 
01632     ~PipeJob() {}
01633     virtual void processEvent( KPIM::ThreadWeaver::Event *ev )
01634     {
01635       KPIM::ThreadWeaver::Job::processEvent( ev );
01636       if ( ev->action() == KPIM::ThreadWeaver::Event::JobFinished )
01637         deleteLater( );
01638     }
01639   protected:
01640     void run()
01641     {
01642       KPIM::ThreadWeaver::debug (1, "PipeJob::run: doing it .\n");
01643       FILE *p;
01644       QByteArray ba;
01645 
01646       // backup the serial number in case the header gets lost
01647       QString origSerNum = mMsg->headerField( "X-KMail-Filtered" );
01648 
01649       p = popen(QFile::encodeName(mCmd), "r");
01650       int len =100;
01651       char buffer[100];
01652       // append data to ba:
01653       while (true)  {
01654         if (! fgets( buffer, len, p ) ) break;
01655         int oldsize = ba.size();
01656         ba.resize( oldsize + strlen(buffer) );
01657         qmemmove( ba.begin() + oldsize, buffer, strlen(buffer) );
01658       }
01659       pclose(p);
01660       if ( !ba.isEmpty() ) {
01661         KPIM::ThreadWeaver::debug (1, "PipeJob::run: %s", QString(ba).latin1() );
01662         KMFolder *filterFolder =  mMsg->parent();
01663         ActionScheduler *handler = MessageProperty::filterHandler( mMsg->getMsgSerNum() );
01664 
01665         mMsg->fromByteArray( ba );
01666         if ( !origSerNum.isEmpty() )
01667           mMsg->setHeaderField( "X-KMail-Filtered", origSerNum );
01668         if ( filterFolder && handler ) {
01669           bool oldStatus = handler->ignoreChanges( true );
01670           filterFolder->take( filterFolder->find( mMsg ) );
01671           filterFolder->addMsg( mMsg );
01672           handler->ignoreChanges( oldStatus );
01673         } else {
01674           kdDebug(5006) << "Warning: Cannot refresh the message from the external filter." << endl;
01675         }
01676       }
01677 
01678       KPIM::ThreadWeaver::debug (1, "PipeJob::run: done.\n" );
01679       // unlink the tempFile
01680       QFile::remove(mTempFileName);
01681     }
01682     QString mTempFileName;
01683     QString mCmd;
01684     KMMessage *mMsg;
01685 };
01686 
01687 class KMFilterActionExtFilter: public KMFilterActionWithCommand
01688 {
01689 public:
01690   KMFilterActionExtFilter();
01691   virtual ReturnCode process(KMMessage* msg) const;
01692   virtual void processAsync(KMMessage* msg) const;
01693   static KMFilterAction* newAction(void);
01694 };
01695 
01696 KMFilterAction* KMFilterActionExtFilter::newAction(void)
01697 {
01698   return (new KMFilterActionExtFilter);
01699 }
01700 
01701 KMFilterActionExtFilter::KMFilterActionExtFilter()
01702   : KMFilterActionWithCommand( "filter app", i18n("Pipe Through") )
01703 {
01704 }
01705 KMFilterAction::ReturnCode KMFilterActionExtFilter::process(KMMessage* aMsg) const
01706 {
01707   return KMFilterActionWithCommand::genericProcess( aMsg, true ); // use output
01708 }
01709 
01710 void KMFilterActionExtFilter::processAsync(KMMessage* aMsg) const
01711 {
01712 
01713   ActionScheduler *handler = MessageProperty::filterHandler( aMsg->getMsgSerNum() );
01714   KTempFile * inFile = new KTempFile;
01715   inFile->setAutoDelete(false);
01716 
01717   QPtrList<KTempFile> atmList;
01718   atmList.setAutoDelete(true);
01719   atmList.append( inFile );
01720 
01721   QString commandLine = substituteCommandLineArgsFor( aMsg , atmList );
01722   if ( commandLine.isEmpty() )
01723     handler->actionMessage( ErrorButGoOn );
01724 
01725   // The parentheses force the creation of a subshell
01726   // in which the user-specified command is executed.
01727   // This is to really catch all output of the command as well
01728   // as to avoid clashes of our redirection with the ones
01729   // the user may have specified. In the long run, we
01730   // shouldn't be using tempfiles at all for this class, due
01731   // to security aspects. (mmutz)
01732   commandLine =  "(" + commandLine + ") <" + inFile->name();
01733 
01734   // write message to file
01735   QString tempFileName = inFile->name();
01736   KPIM::kCStringToFile( aMsg->asString(), tempFileName, //###
01737       false, false, false );
01738   inFile->close();
01739 
01740   PipeJob *job = new PipeJob(0, 0, aMsg, commandLine, tempFileName);
01741   QObject::connect ( job, SIGNAL( done() ), handler, SLOT( actionMessage() ) );
01742   kmkernel->weaver()->enqueue(job);
01743 }
01744 
01745 //=============================================================================
01746 // KMFilterActionExecSound - execute command
01747 // Execute a sound
01748 //=============================================================================
01749 class KMFilterActionExecSound : public KMFilterActionWithTest
01750 {
01751 public:
01752   KMFilterActionExecSound();
01753   virtual ReturnCode process(KMMessage* msg) const;
01754   virtual bool requiresBody(KMMsgBase*) const;
01755   static KMFilterAction* newAction(void);
01756 };
01757 
01758 KMFilterActionWithTest::KMFilterActionWithTest( const char* aName, const QString aLabel )
01759   : KMFilterAction( aName, aLabel )
01760 {
01761 }
01762 
01763 KMFilterActionWithTest::~KMFilterActionWithTest()
01764 {
01765 }
01766 
01767 QWidget* KMFilterActionWithTest::createParamWidget( QWidget* parent ) const
01768 {
01769   KMSoundTestWidget *le = new KMSoundTestWidget(parent);
01770   le->setUrl( mParameter );
01771   return le;
01772 }
01773 
01774 
01775 void KMFilterActionWithTest::applyParamWidgetValue( QWidget* paramWidget )
01776 {
01777   mParameter = ((KMSoundTestWidget*)paramWidget)->url();
01778 }
01779 
01780 void KMFilterActionWithTest::setParamWidgetValue( QWidget* paramWidget ) const
01781 {
01782   ((KMSoundTestWidget*)paramWidget)->setUrl( mParameter );
01783 }
01784 
01785 void KMFilterActionWithTest::clearParamWidget( QWidget* paramWidget ) const
01786 {
01787   ((KMSoundTestWidget*)paramWidget)->clear();
01788 }
01789 
01790 void KMFilterActionWithTest::argsFromString( const QString argsStr )
01791 {
01792   mParameter = argsStr;
01793 }
01794 
01795 const QString KMFilterActionWithTest::argsAsString() const
01796 {
01797   return mParameter;
01798 }
01799 
01800 const QString KMFilterActionWithTest::displayString() const
01801 {
01802   // FIXME after string freeze:
01803   // return i18n("").arg( );
01804   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
01805 }
01806 
01807 
01808 KMFilterActionExecSound::KMFilterActionExecSound()
01809   : KMFilterActionWithTest( "play sound", i18n("Play Sound") )
01810 {
01811 }
01812 
01813 KMFilterAction* KMFilterActionExecSound::newAction(void)
01814 {
01815   return (new KMFilterActionExecSound());
01816 }
01817 
01818 KMFilterAction::ReturnCode KMFilterActionExecSound::process(KMMessage*) const
01819 {
01820   if ( mParameter.isEmpty() )
01821     return ErrorButGoOn;
01822   QString play = mParameter;
01823   QString file = QString::fromLatin1("file:");
01824   if (mParameter.startsWith(file))
01825     play = mParameter.mid(file.length());
01826   KAudioPlayer::play(QFile::encodeName(play));
01827   return GoOn;
01828 }
01829 
01830 bool KMFilterActionExecSound::requiresBody(KMMsgBase*) const
01831 {
01832   return false;
01833 }
01834 
01835 KMFilterActionWithUrl::KMFilterActionWithUrl( const char* aName, const QString aLabel )
01836   : KMFilterAction( aName, aLabel )
01837 {
01838 }
01839 
01840 KMFilterActionWithUrl::~KMFilterActionWithUrl()
01841 {
01842 }
01843 
01844 QWidget* KMFilterActionWithUrl::createParamWidget( QWidget* parent ) const
01845 {
01846   KURLRequester *le = new KURLRequester(parent);
01847   le->setURL( mParameter );
01848   return le;
01849 }
01850 
01851 
01852 void KMFilterActionWithUrl::applyParamWidgetValue( QWidget* paramWidget )
01853 {
01854   mParameter = ((KURLRequester*)paramWidget)->url();
01855 }
01856 
01857 void KMFilterActionWithUrl::setParamWidgetValue( QWidget* paramWidget ) const
01858 {
01859   ((KURLRequester*)paramWidget)->setURL( mParameter );
01860 }
01861 
01862 void KMFilterActionWithUrl::clearParamWidget( QWidget* paramWidget ) const
01863 {
01864   ((KURLRequester*)paramWidget)->clear();
01865 }
01866 
01867 void KMFilterActionWithUrl::argsFromString( const QString argsStr )
01868 {
01869   mParameter = argsStr;
01870 }
01871 
01872 const QString KMFilterActionWithUrl::argsAsString() const
01873 {
01874   return mParameter;
01875 }
01876 
01877 const QString KMFilterActionWithUrl::displayString() const
01878 {
01879   // FIXME after string freeze:
01880   // return i18n("").arg( );
01881   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
01882 }
01883 
01884 
01885 //=============================================================================
01886 //
01887 //   Filter  Action  Dictionary
01888 //
01889 //=============================================================================
01890 void KMFilterActionDict::init(void)
01891 {
01892   insert( KMFilterActionMove::newAction );
01893   insert( KMFilterActionCopy::newAction );
01894   insert( KMFilterActionIdentity::newAction );
01895   insert( KMFilterActionSetStatus::newAction );
01896   insert( KMFilterActionFakeDisposition::newAction );
01897   insert( KMFilterActionTransport::newAction );
01898   insert( KMFilterActionReplyTo::newAction );
01899   insert( KMFilterActionForward::newAction );
01900   insert( KMFilterActionRedirect::newAction );
01901   insert( KMFilterActionSendReceipt::newAction );
01902   insert( KMFilterActionExec::newAction );
01903   insert( KMFilterActionExtFilter::newAction );
01904   insert( KMFilterActionRemoveHeader::newAction );
01905   insert( KMFilterActionAddHeader::newAction );
01906   insert( KMFilterActionRewriteHeader::newAction );
01907   insert( KMFilterActionExecSound::newAction );
01908   // Register custom filter actions below this line.
01909 }
01910 // The int in the QDict constructor (41) must be a prime
01911 // and should be greater than the double number of KMFilterAction types
01912 KMFilterActionDict::KMFilterActionDict()
01913   : QDict<KMFilterActionDesc>(41)
01914 {
01915   mList.setAutoDelete(true);
01916   init();
01917 }
01918 
01919 void KMFilterActionDict::insert( KMFilterActionNewFunc aNewFunc )
01920 {
01921   KMFilterAction *action = aNewFunc();
01922   KMFilterActionDesc* desc = new KMFilterActionDesc;
01923   desc->name = action->name();
01924   desc->label = action->label();
01925   desc->create = aNewFunc;
01926   QDict<KMFilterActionDesc>::insert( desc->name, desc );
01927   QDict<KMFilterActionDesc>::insert( desc->label, desc );
01928   mList.append( desc );
01929   delete action;
01930 }