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