kmail

kmfilteraction.cpp

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