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 <mimelib/message.h>
00026 #include "kmfawidgets.h"
00027 #include "folderrequester.h"
00028 using KMail::FolderRequester;
00029 #include "kmmsgbase.h"
00030 #include "templateparser.h"
00031 #include "messageproperty.h"
00032 #include "actionscheduler.h"
00033 using KMail::MessageProperty;
00034 using KMail::ActionScheduler;
00035 #include "regexplineedit.h"
00036 using KMail::RegExpLineEdit;
00037 #include <kregexp3.h>
00038 #include <ktempfile.h>
00039 #include <kdebug.h>
00040 #include <klocale.h>
00041 #include <kprocess.h>
00042 #include <kaudioplayer.h>
00043 #include <kurlrequester.h>
00044 
00045 #include <qlabel.h>
00046 #include <qlayout.h>
00047 #include <qtextcodec.h>
00048 #include <qtimer.h>
00049 #include <qobject.h>
00050 #include <qstylesheet.h>
00051 #include <assert.h>
00052 
00053 
00054 //=============================================================================
00055 //
00056 // KMFilterAction
00057 //
00058 //=============================================================================
00059 
00060 KMFilterAction::KMFilterAction( const char* aName, const QString aLabel )
00061 {
00062   mName = aName;
00063   mLabel = aLabel;
00064 }
00065 
00066 KMFilterAction::~KMFilterAction()
00067 {
00068 }
00069 
00070 void KMFilterAction::processAsync(KMMessage* msg) const
00071 {
00072   ActionScheduler *handler = MessageProperty::filterHandler( msg );
00073   ReturnCode result = process( msg );
00074   if (handler)
00075     handler->actionMessage( result );
00076 }
00077 
00078 bool KMFilterAction::requiresBody(KMMsgBase*) const
00079 {
00080   return true;
00081 }
00082 
00083 KMFilterAction* KMFilterAction::newAction()
00084 {
00085   return 0;
00086 }
00087 
00088 QWidget* KMFilterAction::createParamWidget(QWidget* parent) const
00089 {
00090   return new QWidget(parent);
00091 }
00092 
00093 void KMFilterAction::applyParamWidgetValue(QWidget*)
00094 {
00095 }
00096 
00097 void KMFilterAction::setParamWidgetValue( QWidget * ) const
00098 {
00099 }
00100 
00101 void KMFilterAction::clearParamWidget( QWidget * ) const
00102 {
00103 }
00104 
00105 bool KMFilterAction::folderRemoved(KMFolder*, KMFolder*)
00106 {
00107   return FALSE;
00108 }
00109 
00110 int KMFilterAction::tempOpenFolder(KMFolder* aFolder)
00111 {
00112   return kmkernel->filterMgr()->tempOpenFolder(aFolder);
00113 }
00114 
00115 void KMFilterAction::sendMDN( KMMessage * msg, KMime::MDN::DispositionType d,
00116                               const QValueList<KMime::MDN::DispositionModifier> & m ) {
00117   if ( !msg ) return;
00118   KMMessage * mdn = msg->createMDN( KMime::MDN::AutomaticAction, d, false, m );
00119   if ( mdn && !kmkernel->msgSender()->send( mdn, KMail::MessageSender::SendLater ) ) {
00120     kdDebug(5006) << "KMFilterAction::sendMDN(): sending failed." << endl;
00121     //delete mdn;
00122   }
00123 }
00124 
00125 
00126 //=============================================================================
00127 //
00128 // KMFilterActionWithNone
00129 //
00130 //=============================================================================
00131 
00132 KMFilterActionWithNone::KMFilterActionWithNone( const char* aName, const QString aLabel )
00133   : KMFilterAction( aName, aLabel )
00134 {
00135 }
00136 
00137 const QString KMFilterActionWithNone::displayString() const
00138 {
00139   return label();
00140 }
00141 
00142 
00143 //=============================================================================
00144 //
00145 // KMFilterActionWithUOID
00146 //
00147 //=============================================================================
00148 
00149 KMFilterActionWithUOID::KMFilterActionWithUOID( const char* aName, const QString aLabel )
00150   : KMFilterAction( aName, aLabel ), mParameter( 0 )
00151 {
00152 }
00153 
00154 void KMFilterActionWithUOID::argsFromString( const QString argsStr )
00155 {
00156   mParameter = argsStr.stripWhiteSpace().toUInt();
00157 }
00158 
00159 const QString KMFilterActionWithUOID::argsAsString() const
00160 {
00161   return QString::number( mParameter );
00162 }
00163 
00164 const QString KMFilterActionWithUOID::displayString() const
00165 {
00166   // FIXME after string freeze:
00167   // return i18n("").arg( );
00168   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
00169 }
00170 
00171 
00172 //=============================================================================
00173 //
00174 // KMFilterActionWithString
00175 //
00176 //=============================================================================
00177 
00178 KMFilterActionWithString::KMFilterActionWithString( const char* aName, const QString aLabel )
00179   : KMFilterAction( aName, aLabel )
00180 {
00181 }
00182 
00183 QWidget* KMFilterActionWithString::createParamWidget( QWidget* parent ) const
00184 {
00185   QLineEdit *le = new KLineEdit(parent);
00186   le->setText( mParameter );
00187   return le;
00188 }
00189 
00190 void KMFilterActionWithString::applyParamWidgetValue( QWidget* paramWidget )
00191 {
00192   mParameter = ((QLineEdit*)paramWidget)->text();
00193 }
00194 
00195 void KMFilterActionWithString::setParamWidgetValue( QWidget* paramWidget ) const
00196 {
00197   ((QLineEdit*)paramWidget)->setText( mParameter );
00198 }
00199 
00200 void KMFilterActionWithString::clearParamWidget( QWidget* paramWidget ) const
00201 {
00202   ((QLineEdit*)paramWidget)->clear();
00203 }
00204 
00205 void KMFilterActionWithString::argsFromString( const QString argsStr )
00206 {
00207   mParameter = argsStr;
00208 }
00209 
00210 const QString KMFilterActionWithString::argsAsString() const
00211 {
00212   return mParameter;
00213 }
00214 
00215 const QString KMFilterActionWithString::displayString() const
00216 {
00217   // FIXME after string freeze:
00218   // return i18n("").arg( );
00219   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
00220 }
00221 
00222 //=============================================================================
00223 //
00224 // class KMFilterActionWithStringList
00225 //
00226 //=============================================================================
00227 
00228 KMFilterActionWithStringList::KMFilterActionWithStringList( const char* aName, const QString aLabel )
00229   : KMFilterActionWithString( aName, aLabel )
00230 {
00231 }
00232 
00233 QWidget* KMFilterActionWithStringList::createParamWidget( QWidget* parent ) const
00234 {
00235   QComboBox *cb = new QComboBox( FALSE, parent );
00236   cb->insertStringList( mParameterList );
00237   setParamWidgetValue( cb );
00238   return cb;
00239 }
00240 
00241 void KMFilterActionWithStringList::applyParamWidgetValue( QWidget* paramWidget )
00242 {
00243   mParameter = ((QComboBox*)paramWidget)->currentText();
00244 }
00245 
00246 void KMFilterActionWithStringList::setParamWidgetValue( QWidget* paramWidget ) const
00247 {
00248   int idx = mParameterList.findIndex( mParameter );
00249   ((QComboBox*)paramWidget)->setCurrentItem( idx >= 0 ? idx : 0 );
00250 }
00251 
00252 void KMFilterActionWithStringList::clearParamWidget( QWidget* paramWidget ) const
00253 {
00254   ((QComboBox*)paramWidget)->setCurrentItem(0);
00255 }
00256 
00257 void KMFilterActionWithStringList::argsFromString( const QString argsStr )
00258 {
00259   int idx = mParameterList.findIndex( argsStr );
00260   if ( idx < 0 ) {
00261     mParameterList.append( argsStr );
00262     idx = mParameterList.count() - 1;
00263   }
00264   mParameter = *mParameterList.at( idx );
00265 }
00266 
00267 
00268 //=============================================================================
00269 //
00270 // class KMFilterActionWithFolder
00271 //
00272 //=============================================================================
00273 
00274 KMFilterActionWithFolder::KMFilterActionWithFolder( const char* aName, const QString aLabel )
00275   : KMFilterAction( aName, aLabel )
00276 {
00277   mFolder = 0;
00278 }
00279 
00280 QWidget* KMFilterActionWithFolder::createParamWidget( QWidget* parent ) const
00281 {
00282   FolderRequester *req = new FolderRequester( parent,
00283       kmkernel->getKMMainWidget()->folderTree() );
00284   setParamWidgetValue( req );
00285   return req;
00286 }
00287 
00288 void KMFilterActionWithFolder::applyParamWidgetValue( QWidget* paramWidget )
00289 {
00290   mFolder = ((FolderRequester *)paramWidget)->folder();
00291   mFolderName = ((FolderRequester *)paramWidget)->folderId();
00292 }
00293 
00294 void KMFilterActionWithFolder::setParamWidgetValue( QWidget* paramWidget ) const
00295 {
00296   if ( mFolder )
00297     ((FolderRequester *)paramWidget)->setFolder( mFolder );
00298   else
00299     ((FolderRequester *)paramWidget)->setFolder( mFolderName );
00300 }
00301 
00302 void KMFilterActionWithFolder::clearParamWidget( QWidget* paramWidget ) const
00303 {
00304   ((FolderRequester *)paramWidget)->setFolder( kmkernel->draftsFolder() );
00305 }
00306 
00307 void KMFilterActionWithFolder::argsFromString( const QString argsStr )
00308 {
00309   mFolder = kmkernel->folderMgr()->findIdString( argsStr );
00310   if (!mFolder)
00311      mFolder = kmkernel->dimapFolderMgr()->findIdString( argsStr );
00312   if (!mFolder)
00313      mFolder = kmkernel->imapFolderMgr()->findIdString( argsStr );
00314   if (mFolder)
00315      mFolderName = mFolder->idString();
00316   else
00317      mFolderName = argsStr;
00318 }
00319 
00320 const QString KMFilterActionWithFolder::argsAsString() const
00321 {
00322   QString result;
00323   if ( mFolder )
00324     result = mFolder->idString();
00325   else
00326     result = mFolderName;
00327   return result;
00328 }
00329 
00330 const QString KMFilterActionWithFolder::displayString() const
00331 {
00332   QString result;
00333   if ( mFolder )
00334     result = mFolder->prettyURL();
00335   else
00336     result = mFolderName;
00337   return label() + " \"" + QStyleSheet::escape( result ) + "\"";
00338 }
00339 
00340 bool KMFilterActionWithFolder::folderRemoved( KMFolder* aFolder, KMFolder* aNewFolder )
00341 {
00342   if ( aFolder == mFolder ) {
00343     mFolder = aNewFolder;
00344     if ( aNewFolder )
00345       mFolderName = mFolder->idString();
00346     return TRUE;
00347   } else
00348     return FALSE;
00349 }
00350 
00351 //=============================================================================
00352 //
00353 // class KMFilterActionWithAddress
00354 //
00355 //=============================================================================
00356 
00357 KMFilterActionWithAddress::KMFilterActionWithAddress( const char* aName, const QString aLabel )
00358   : KMFilterActionWithString( aName, aLabel )
00359 {
00360 }
00361 
00362 QWidget* KMFilterActionWithAddress::createParamWidget( QWidget* parent ) const
00363 {
00364   KMFilterActionWithAddressWidget *w = new KMFilterActionWithAddressWidget(parent);
00365   w->setText( mParameter );
00366   return w;
00367 }
00368 
00369 void KMFilterActionWithAddress::applyParamWidgetValue( QWidget* paramWidget )
00370 {
00371   mParameter = ((KMFilterActionWithAddressWidget*)paramWidget)->text();
00372 }
00373 
00374 void KMFilterActionWithAddress::setParamWidgetValue( QWidget* paramWidget ) const
00375 {
00376   ((KMFilterActionWithAddressWidget*)paramWidget)->setText( mParameter );
00377 }
00378 
00379 void KMFilterActionWithAddress::clearParamWidget( QWidget* paramWidget ) const
00380 {
00381   ((KMFilterActionWithAddressWidget*)paramWidget)->clear();
00382 }
00383 
00384 //=============================================================================
00385 //
00386 // class KMFilterActionWithCommand
00387 //
00388 //=============================================================================
00389 
00390 KMFilterActionWithCommand::KMFilterActionWithCommand( const char* aName, const QString aLabel )
00391   : KMFilterActionWithUrl( aName, aLabel )
00392 {
00393 }
00394 
00395 QWidget* KMFilterActionWithCommand::createParamWidget( QWidget* parent ) const
00396 {
00397   return KMFilterActionWithUrl::createParamWidget( parent );
00398 }
00399 
00400 void KMFilterActionWithCommand::applyParamWidgetValue( QWidget* paramWidget )
00401 {
00402   KMFilterActionWithUrl::applyParamWidgetValue( paramWidget );
00403 }
00404 
00405 void KMFilterActionWithCommand::setParamWidgetValue( QWidget* paramWidget ) const
00406 {
00407   KMFilterActionWithUrl::setParamWidgetValue( paramWidget );
00408 }
00409 
00410 void KMFilterActionWithCommand::clearParamWidget( QWidget* paramWidget ) const
00411 {
00412   KMFilterActionWithUrl::clearParamWidget( paramWidget );
00413 }
00414 
00415 QString KMFilterActionWithCommand::substituteCommandLineArgsFor( KMMessage *aMsg, QPtrList<KTempFile> & aTempFileList ) const
00416 {
00417   QString result = mParameter;
00418   QValueList<int> argList;
00419   QRegExp r( "%[0-9-]+" );
00420 
00421   // search for '%n'
00422   int start = -1;
00423   while ( ( start = r.search( result, start + 1 ) ) > 0 ) {
00424     int len = r.matchedLength();
00425     // and save the encountered 'n' in a list.
00426     bool OK = false;
00427     int n = result.mid( start + 1, len - 1 ).toInt( &OK );
00428     if ( OK )
00429       argList.append( n );
00430   }
00431 
00432   // sort the list of n's
00433   qHeapSort( argList );
00434 
00435   // and use QString::arg to substitute filenames for the %n's.
00436   int lastSeen = -2;
00437   QString tempFileName;
00438   for ( QValueList<int>::Iterator it = argList.begin() ; it != argList.end() ; ++it ) {
00439     // setup temp files with check for duplicate %n's
00440     if ( (*it) != lastSeen ) {
00441       KTempFile *tf = new KTempFile();
00442       if ( tf->status() != 0 ) {
00443         tf->close();
00444         delete tf;
00445         kdDebug(5006) << "KMFilterActionWithCommand: Could not create temp file!" << endl;
00446         return QString::null;
00447       }
00448       tf->setAutoDelete(TRUE);
00449       aTempFileList.append( tf );
00450       tempFileName = tf->name();
00451       if ((*it) == -1)
00452         KPIM::kCStringToFile( aMsg->asString(), tempFileName, //###
00453                           false, false, false );
00454       else if (aMsg->numBodyParts() == 0)
00455         KPIM::kByteArrayToFile( aMsg->bodyDecodedBinary(), tempFileName,
00456                           false, false, false );
00457       else {
00458         KMMessagePart msgPart;
00459         aMsg->bodyPart( (*it), &msgPart );
00460         KPIM::kByteArrayToFile( msgPart.bodyDecodedBinary(), tempFileName,
00461                           false, false, false );
00462       }
00463       tf->close();
00464     }
00465     // QString( "%0 and %1 and %1" ).arg( 0 ).arg( 1 )
00466     // returns "0 and 1 and %1", so we must call .arg as
00467     // many times as there are %n's, regardless of their multiplicity.
00468     if ((*it) == -1) result.replace( "%-1", tempFileName );
00469     else result = result.arg( tempFileName );
00470   }
00471 
00472   // And finally, replace the %{foo} with the content of the foo
00473   // header field:
00474   QRegExp header_rx( "%\\{([a-z0-9-]+)\\}", false );
00475   int idx = 0;
00476   while ( ( idx = header_rx.search( result, idx ) ) != -1 ) {
00477     QString replacement = KProcess::quote( aMsg->headerField( header_rx.cap(1).latin1() ) );
00478     result.replace( idx, header_rx.matchedLength(), replacement );
00479     idx += replacement.length();
00480   }
00481 
00482   return result;
00483 }
00484 
00485 
00486 KMFilterAction::ReturnCode KMFilterActionWithCommand::genericProcess(KMMessage* aMsg, bool withOutput) const
00487 {
00488   Q_ASSERT( aMsg );
00489 
00490   if ( mParameter.isEmpty() )
00491     return ErrorButGoOn;
00492 
00493   // KProcess doesn't support a QProcess::launch() equivalent, so
00494   // we must use a temp file :-(
00495   KTempFile * inFile = new KTempFile;
00496   inFile->setAutoDelete(TRUE);
00497 
00498   QPtrList<KTempFile> atmList;
00499   atmList.setAutoDelete(TRUE);
00500   atmList.append( inFile );
00501 
00502   QString commandLine = substituteCommandLineArgsFor( aMsg , atmList );
00503   if ( commandLine.isEmpty() )
00504     return ErrorButGoOn;
00505 
00506   // The parentheses force the creation of a subshell
00507   // in which the user-specified command is executed.
00508   // This is to really catch all output of the command as well
00509   // as to avoid clashes of our redirection with the ones
00510   // the user may have specified. In the long run, we
00511   // shouldn't be using tempfiles at all for this class, due
00512   // to security aspects. (mmutz)
00513   commandLine =  "(" + commandLine + ") <" + inFile->name();
00514 
00515   // write message to file
00516   QString tempFileName = inFile->name();
00517   KPIM::kCStringToFile( aMsg->asString(), tempFileName, //###
00518                   false, false, false );
00519   inFile->close();
00520 
00521   CollectingProcess shProc;
00522   shProc.setUseShell(true);
00523   shProc << commandLine;
00524 
00525   // run process:
00526   if ( !shProc.start( KProcess::Block,
00527                       withOutput ? KProcess::Stdout
00528                                  : KProcess::NoCommunication ) )
00529     return ErrorButGoOn;
00530 
00531   if ( !shProc.normalExit() || shProc.exitStatus() != 0 ) {
00532     return ErrorButGoOn;
00533   }
00534 
00535   if ( withOutput ) {
00536     // read altered message:
00537     QByteArray msgText = shProc.collectedStdout();
00538 
00539     if ( !msgText.isEmpty() ) {
00540     /* If the pipe through alters the message, it could very well
00541        happen that it no longer has a X-UID header afterwards. That is
00542        unfortunate, as we need to removed the original from the folder
00543        using that, and look it up in the message. When the (new) message
00544        is uploaded, the header is stripped anyhow. */
00545       QString uid = aMsg->headerField("X-UID");
00546       aMsg->fromByteArray( msgText );
00547       aMsg->setHeaderField("X-UID",uid);
00548     }
00549     else
00550       return ErrorButGoOn;
00551   }
00552   return GoOn;
00553 }
00554 
00555 
00556 //=============================================================================
00557 //
00558 //   Specific  Filter  Actions
00559 //
00560 //=============================================================================
00561 
00562 //=============================================================================
00563 // KMFilterActionSendReceipt - send receipt
00564 // Return delivery receipt.
00565 //=============================================================================
00566 class KMFilterActionSendReceipt : public KMFilterActionWithNone
00567 {
00568 public:
00569   KMFilterActionSendReceipt();
00570   virtual ReturnCode process(KMMessage* msg) const;
00571   static KMFilterAction* newAction(void);
00572 };
00573 
00574 KMFilterAction* KMFilterActionSendReceipt::newAction(void)
00575 {
00576   return (new KMFilterActionSendReceipt);
00577 }
00578 
00579 KMFilterActionSendReceipt::KMFilterActionSendReceipt()
00580   : KMFilterActionWithNone( "confirm delivery", i18n("Confirm Delivery") )
00581 {
00582 }
00583 
00584 KMFilterAction::ReturnCode KMFilterActionSendReceipt::process(KMMessage* msg) const
00585 {
00586   KMMessage *receipt = msg->createDeliveryReceipt();
00587   if ( !receipt ) return ErrorButGoOn;
00588 
00589   // Queue message. This is a) so that the user can check
00590   // the receipt before sending and b) for speed reasons.
00591   kmkernel->msgSender()->send( receipt, KMail::MessageSender::SendLater );
00592 
00593   return GoOn;
00594 }
00595 
00596 
00597 
00598 //=============================================================================
00599 // KMFilterActionSetTransport - set transport to...
00600 // Specify mail transport (smtp server) to be used when replying to a message
00601 //=============================================================================
00602 class KMFilterActionTransport: public KMFilterActionWithString
00603 {
00604 public:
00605   KMFilterActionTransport();
00606   virtual ReturnCode process(KMMessage* msg) const;
00607   static KMFilterAction* newAction(void);
00608 };
00609 
00610 KMFilterAction* KMFilterActionTransport::newAction(void)
00611 {
00612   return (new KMFilterActionTransport);
00613 }
00614 
00615 KMFilterActionTransport::KMFilterActionTransport()
00616   : KMFilterActionWithString( "set transport", i18n("Set Transport To") )
00617 {
00618 }
00619 
00620 KMFilterAction::ReturnCode KMFilterActionTransport::process(KMMessage* msg) const
00621 {
00622   if ( mParameter.isEmpty() )
00623     return ErrorButGoOn;
00624   msg->setHeaderField( "X-KMail-Transport", mParameter );
00625   return GoOn;
00626 }
00627 
00628 
00629 //=============================================================================
00630 // KMFilterActionReplyTo - set Reply-To to
00631 // Set the Reply-to header in a message
00632 //=============================================================================
00633 class KMFilterActionReplyTo: public KMFilterActionWithString
00634 {
00635 public:
00636   KMFilterActionReplyTo();
00637   virtual ReturnCode process(KMMessage* msg) const;
00638   static KMFilterAction* newAction(void);
00639 };
00640 
00641 KMFilterAction* KMFilterActionReplyTo::newAction(void)
00642 {
00643   return (new KMFilterActionReplyTo);
00644 }
00645 
00646 KMFilterActionReplyTo::KMFilterActionReplyTo()
00647   : KMFilterActionWithString( "set Reply-To", i18n("Set Reply-To To") )
00648 {
00649   mParameter = "";
00650 }
00651 
00652 KMFilterAction::ReturnCode KMFilterActionReplyTo::process(KMMessage* msg) const
00653 {
00654   msg->setHeaderField( "Reply-To", mParameter );
00655   return GoOn;
00656 }
00657 
00658 
00659 
00660 //=============================================================================
00661 // KMFilterActionIdentity - set identity to
00662 // Specify Identity to be used when replying to a message
00663 //=============================================================================
00664 class KMFilterActionIdentity: public KMFilterActionWithUOID
00665 {
00666 public:
00667   KMFilterActionIdentity();
00668   virtual ReturnCode process(KMMessage* msg) const;
00669   static KMFilterAction* newAction();
00670 
00671   QWidget * createParamWidget( QWidget * parent ) const;
00672   void applyParamWidgetValue( QWidget * parent );
00673   void setParamWidgetValue( QWidget * parent ) const;
00674   void clearParamWidget( QWidget * param ) const;
00675 };
00676 
00677 KMFilterAction* KMFilterActionIdentity::newAction()
00678 {
00679   return (new KMFilterActionIdentity);
00680 }
00681 
00682 KMFilterActionIdentity::KMFilterActionIdentity()
00683   : KMFilterActionWithUOID( "set identity", i18n("Set Identity To") )
00684 {
00685   mParameter = kmkernel->identityManager()->defaultIdentity().uoid();
00686 }
00687 
00688 KMFilterAction::ReturnCode KMFilterActionIdentity::process(KMMessage* msg) const
00689 {
00690   msg->setHeaderField( "X-KMail-Identity", QString::number( mParameter ) );
00691   return GoOn;
00692 }
00693 
00694 QWidget * KMFilterActionIdentity::createParamWidget( QWidget * parent ) const
00695 {
00696   KPIM::IdentityCombo * ic = new KPIM::IdentityCombo( kmkernel->identityManager(), parent );
00697   ic->setCurrentIdentity( mParameter );
00698   return ic;
00699 }
00700 
00701 void KMFilterActionIdentity::applyParamWidgetValue( QWidget * paramWidget )
00702 {
00703   KPIM::IdentityCombo * ic = dynamic_cast<KPIM::IdentityCombo*>( paramWidget );
00704   assert( ic );
00705   mParameter = ic->currentIdentity();
00706 }
00707 
00708 void KMFilterActionIdentity::clearParamWidget( QWidget * paramWidget ) const
00709 {
00710   KPIM::IdentityCombo * ic = dynamic_cast<KPIM::IdentityCombo*>( paramWidget );
00711   assert( ic );
00712   ic->setCurrentItem( 0 );
00713   //ic->setCurrentIdentity( kmkernel->identityManager()->defaultIdentity() );
00714 }
00715 
00716 void KMFilterActionIdentity::setParamWidgetValue( QWidget * paramWidget ) const
00717 {
00718   KPIM::IdentityCombo * ic = dynamic_cast<KPIM::IdentityCombo*>( paramWidget );
00719   assert( ic );
00720   ic->setCurrentIdentity( mParameter );
00721 }
00722 
00723 //=============================================================================
00724 // KMFilterActionSetStatus - set status to
00725 // Set the status of messages
00726 //=============================================================================
00727 class KMFilterActionSetStatus: public KMFilterActionWithStringList
00728 {
00729 public:
00730   KMFilterActionSetStatus();
00731   virtual ReturnCode process(KMMessage* msg) const;
00732   virtual bool requiresBody(KMMsgBase*) const;
00733 
00734   static KMFilterAction* newAction();
00735 
00736   virtual bool isEmpty() const { return false; }
00737 
00738   virtual void argsFromString( const QString argsStr );
00739   virtual const QString argsAsString() const;
00740   virtual const QString displayString() const;
00741 };
00742 
00743 
00744 static const KMMsgStatus stati[] =
00745 {
00746   KMMsgStatusFlag,
00747   KMMsgStatusRead,
00748   KMMsgStatusUnread,
00749   KMMsgStatusReplied,
00750   KMMsgStatusForwarded,
00751   KMMsgStatusOld,
00752   KMMsgStatusNew,
00753   KMMsgStatusWatched,
00754   KMMsgStatusIgnored,
00755   KMMsgStatusSpam,
00756   KMMsgStatusHam
00757 };
00758 static const int StatiCount = sizeof( stati ) / sizeof( KMMsgStatus );
00759 
00760 KMFilterAction* KMFilterActionSetStatus::newAction()
00761 {
00762   return (new KMFilterActionSetStatus);
00763 }
00764 
00765 KMFilterActionSetStatus::KMFilterActionSetStatus()
00766   : KMFilterActionWithStringList( "set status", i18n("Mark As") )
00767 {
00768   // if you change this list, also update
00769   // KMFilterActionSetStatus::stati above
00770   mParameterList.append( "" );
00771   mParameterList.append( i18n("msg status","Important") );
00772   mParameterList.append( i18n("msg status","Read") );
00773   mParameterList.append( i18n("msg status","Unread") );
00774   mParameterList.append( i18n("msg status","Replied") );
00775   mParameterList.append( i18n("msg status","Forwarded") );
00776   mParameterList.append( i18n("msg status","Old") );
00777   mParameterList.append( i18n("msg status","New") );
00778   mParameterList.append( i18n("msg status","Watched") );
00779   mParameterList.append( i18n("msg status","Ignored") );
00780   mParameterList.append( i18n("msg status","Spam") );
00781   mParameterList.append( i18n("msg status","Ham") );
00782 
00783   mParameter = *mParameterList.at(0);
00784 }
00785 
00786 KMFilterAction::ReturnCode KMFilterActionSetStatus::process(KMMessage* msg) const
00787 {
00788   int idx = mParameterList.findIndex( mParameter );
00789   if ( idx < 1 ) return ErrorButGoOn;
00790 
00791   KMMsgStatus status = stati[idx-1] ;
00792   msg->setStatus( status );
00793   return GoOn;
00794 }
00795 
00796 bool KMFilterActionSetStatus::requiresBody(KMMsgBase*) const
00797 {
00798   return false;
00799 }
00800 
00801 void KMFilterActionSetStatus::argsFromString( const QString argsStr )
00802 {
00803   if ( argsStr.length() == 1 ) {
00804     for ( int i = 0 ; i < StatiCount ; i++ )
00805       if ( KMMsgBase::statusToStr(stati[i])[0] == argsStr[0] ) {
00806         mParameter = *mParameterList.at(i+1);
00807         return;
00808       }
00809   }
00810   mParameter = *mParameterList.at(0);
00811 }
00812 
00813 const QString KMFilterActionSetStatus::argsAsString() const
00814 {
00815   int idx = mParameterList.findIndex( mParameter );
00816   if ( idx < 1 ) return QString::null;
00817 
00818   KMMsgStatus status = stati[idx-1];
00819   return KMMsgBase::statusToStr(status);
00820 }
00821 
00822 const QString KMFilterActionSetStatus::displayString() const
00823 {
00824   // FIXME after string freeze:
00825   // return i18n("").arg( );
00826   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
00827 }
00828 
00829 //=============================================================================
00830 // KMFilterActionFakeDisposition - send fake MDN
00831 // Sends a fake MDN or forces an ignore.
00832 //=============================================================================
00833 class KMFilterActionFakeDisposition: public KMFilterActionWithStringList
00834 {
00835 public:
00836   KMFilterActionFakeDisposition();
00837   virtual ReturnCode process(KMMessage* msg) const;
00838   static KMFilterAction* newAction() {
00839     return (new KMFilterActionFakeDisposition);
00840   }
00841 
00842   virtual bool isEmpty() const { return false; }
00843 
00844   virtual void argsFromString( const QString argsStr );
00845   virtual const QString argsAsString() const;
00846   virtual const QString displayString() const;
00847 };
00848 
00849 
00850 // if you change this list, also update
00851 // the count in argsFromString
00852 static const KMime::MDN::DispositionType mdns[] =
00853 {
00854   KMime::MDN::Displayed,
00855   KMime::MDN::Deleted,
00856   KMime::MDN::Dispatched,
00857   KMime::MDN::Processed,
00858   KMime::MDN::Denied,
00859   KMime::MDN::Failed,
00860 };
00861 static const int numMDNs = sizeof mdns / sizeof *mdns;
00862 
00863 
00864 KMFilterActionFakeDisposition::KMFilterActionFakeDisposition()
00865   : KMFilterActionWithStringList( "fake mdn", i18n("Send Fake MDN") )
00866 {
00867   // if you change this list, also update
00868   // mdns above
00869   mParameterList.append( "" );
00870   mParameterList.append( i18n("MDN type","Ignore") );
00871   mParameterList.append( i18n("MDN type","Displayed") );
00872   mParameterList.append( i18n("MDN type","Deleted") );
00873   mParameterList.append( i18n("MDN type","Dispatched") );
00874   mParameterList.append( i18n("MDN type","Processed") );
00875   mParameterList.append( i18n("MDN type","Denied") );
00876   mParameterList.append( i18n("MDN type","Failed") );
00877 
00878   mParameter = *mParameterList.at(0);
00879 }
00880 
00881 KMFilterAction::ReturnCode KMFilterActionFakeDisposition::process(KMMessage* msg) const
00882 {
00883   int idx = mParameterList.findIndex( mParameter );
00884   if ( idx < 1 ) return ErrorButGoOn;
00885 
00886   if ( idx == 1 ) // ignore
00887     msg->setMDNSentState( KMMsgMDNIgnore );
00888   else // send
00889     sendMDN( msg, mdns[idx-2] ); // skip first two entries: "" and "ignore"
00890   return GoOn;
00891 }
00892 
00893 void KMFilterActionFakeDisposition::argsFromString( const QString argsStr )
00894 {
00895   if ( argsStr.length() == 1 ) {
00896     if ( argsStr[0] == 'I' ) { // ignore
00897       mParameter = *mParameterList.at(1);
00898       return;
00899     }
00900     for ( int i = 0 ; i < numMDNs ; i++ )
00901       if ( char(mdns[i]) == argsStr[0] ) { // send
00902         mParameter = *mParameterList.at(i+2);
00903         return;
00904       }
00905   }
00906   mParameter = *mParameterList.at(0);
00907 }
00908 
00909 const QString KMFilterActionFakeDisposition::argsAsString() const
00910 {
00911   int idx = mParameterList.findIndex( mParameter );
00912   if ( idx < 1 ) return QString::null;
00913 
00914   return QString( QChar( idx < 2 ? 'I' : char(mdns[idx-2]) ) );
00915 }
00916 
00917 const QString KMFilterActionFakeDisposition::displayString() const
00918 {
00919   // FIXME after string freeze:
00920   // return i18n("").arg( );
00921   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
00922 }
00923 
00924 //=============================================================================
00925 // KMFilterActionRemoveHeader - remove header
00926 // Remove all instances of the given header field.
00927 //=============================================================================
00928 class KMFilterActionRemoveHeader: public KMFilterActionWithStringList
00929 {
00930 public:
00931   KMFilterActionRemoveHeader();
00932   virtual ReturnCode process(KMMessage* msg) const;
00933   virtual QWidget* createParamWidget( QWidget* parent ) const;
00934   virtual void setParamWidgetValue( QWidget* paramWidget ) const;
00935 
00936   static KMFilterAction* newAction();
00937 };
00938 
00939 KMFilterAction* KMFilterActionRemoveHeader::newAction()
00940 {
00941   return (new KMFilterActionRemoveHeader);
00942 }
00943 
00944 KMFilterActionRemoveHeader::KMFilterActionRemoveHeader()
00945   : KMFilterActionWithStringList( "remove header", i18n("Remove Header") )
00946 {
00947   mParameterList << ""
00948                  << "Reply-To"
00949                  << "Delivered-To"
00950                  << "X-KDE-PR-Message"
00951                  << "X-KDE-PR-Package"
00952                  << "X-KDE-PR-Keywords";
00953   mParameter = *mParameterList.at(0);
00954 }
00955 
00956 QWidget* KMFilterActionRemoveHeader::createParamWidget( QWidget* parent ) const
00957 {
00958   QComboBox *cb = new QComboBox( TRUE/*editable*/, parent );
00959   cb->setInsertionPolicy( QComboBox::AtBottom );
00960   setParamWidgetValue( cb );
00961   return cb;
00962 }
00963 
00964 KMFilterAction::ReturnCode KMFilterActionRemoveHeader::process(KMMessage* msg) const
00965 {
00966   if ( mParameter.isEmpty() ) return ErrorButGoOn;
00967 
00968   while ( !msg->headerField( mParameter.latin1() ).isEmpty() )
00969     msg->removeHeaderField( mParameter.latin1() );
00970   return GoOn;
00971 }
00972 
00973 void KMFilterActionRemoveHeader::setParamWidgetValue( QWidget* paramWidget ) const
00974 {
00975   QComboBox * cb = dynamic_cast<QComboBox*>(paramWidget);
00976   Q_ASSERT( cb );
00977 
00978   int idx = mParameterList.findIndex( mParameter );
00979   cb->clear();
00980   cb->insertStringList( mParameterList );
00981   if ( idx < 0 ) {
00982     cb->insertItem( mParameter );
00983     cb->setCurrentItem( cb->count() - 1 );
00984   } else {
00985     cb->setCurrentItem( idx );
00986   }
00987 }
00988 
00989 
00990 //=============================================================================
00991 // KMFilterActionAddHeader - add header
00992 // Add a header with the given value.
00993 //=============================================================================
00994 class KMFilterActionAddHeader: public KMFilterActionWithStringList
00995 {
00996 public:
00997   KMFilterActionAddHeader();
00998   virtual ReturnCode process(KMMessage* msg) const;
00999   virtual QWidget* createParamWidget( QWidget* parent ) const;
01000   virtual void setParamWidgetValue( QWidget* paramWidget ) const;
01001   virtual void applyParamWidgetValue( QWidget* paramWidget );
01002   virtual void clearParamWidget( QWidget* paramWidget ) const;
01003 
01004   virtual const QString argsAsString() const;
01005   virtual void argsFromString( const QString argsStr );
01006 
01007   virtual const QString displayString() const;
01008 
01009   static KMFilterAction* newAction()
01010   {
01011     return (new KMFilterActionAddHeader);
01012   }
01013 private:
01014   QString mValue;
01015 };
01016 
01017 KMFilterActionAddHeader::KMFilterActionAddHeader()
01018   : KMFilterActionWithStringList( "add header", i18n("Add Header") )
01019 {
01020   mParameterList << ""
01021                  << "Reply-To"
01022                  << "Delivered-To"
01023                  << "X-KDE-PR-Message"
01024                  << "X-KDE-PR-Package"
01025                  << "X-KDE-PR-Keywords";
01026   mParameter = *mParameterList.at(0);
01027 }
01028 
01029 KMFilterAction::ReturnCode KMFilterActionAddHeader::process(KMMessage* msg) const
01030 {
01031   if ( mParameter.isEmpty() ) return ErrorButGoOn;
01032 
01033   msg->setHeaderField( mParameter.latin1(), mValue );
01034   return GoOn;
01035 }
01036 
01037 QWidget* KMFilterActionAddHeader::createParamWidget( QWidget* parent ) const
01038 {
01039   QWidget *w = new QWidget( parent );
01040   QHBoxLayout *hbl = new QHBoxLayout( w );
01041   hbl->setSpacing( 4 );
01042   QComboBox *cb = new QComboBox( TRUE, w, "combo" );
01043   cb->setInsertionPolicy( QComboBox::AtBottom );
01044   hbl->addWidget( cb, 0 /* stretch */ );
01045   QLabel *l = new QLabel( i18n("With value:"), w );
01046   l->setFixedWidth( l->sizeHint().width() );
01047   hbl->addWidget( l, 0 );
01048   QLineEdit *le = new KLineEdit( w, "ledit" );
01049   hbl->addWidget( le, 1 );
01050   setParamWidgetValue( w );
01051   return w;
01052 }
01053 
01054 void KMFilterActionAddHeader::setParamWidgetValue( QWidget* paramWidget ) const
01055 {
01056   int idx = mParameterList.findIndex( mParameter );
01057   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01058   Q_ASSERT( cb );
01059   cb->clear();
01060   cb->insertStringList( mParameterList );
01061   if ( idx < 0 ) {
01062     cb->insertItem( mParameter );
01063     cb->setCurrentItem( cb->count() - 1 );
01064   } else {
01065     cb->setCurrentItem( idx );
01066   }
01067   QLineEdit *le = (QLineEdit*)paramWidget->child("ledit");
01068   Q_ASSERT( le );
01069   le->setText( mValue );
01070 }
01071 
01072 void KMFilterActionAddHeader::applyParamWidgetValue( QWidget* paramWidget )
01073 {
01074   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01075   Q_ASSERT( cb );
01076   mParameter = cb->currentText();
01077 
01078   QLineEdit *le = (QLineEdit*)paramWidget->child("ledit");
01079   Q_ASSERT( le );
01080   mValue = le->text();
01081 }
01082 
01083 void KMFilterActionAddHeader::clearParamWidget( QWidget* paramWidget ) const
01084 {
01085   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01086   Q_ASSERT( cb );
01087   cb->setCurrentItem(0);
01088   QLineEdit *le = (QLineEdit*)paramWidget->child("ledit");
01089   Q_ASSERT( le );
01090   le->clear();
01091 }
01092 
01093 const QString KMFilterActionAddHeader::argsAsString() const
01094 {
01095   QString result = mParameter;
01096   result += '\t';
01097   result += mValue;
01098 
01099   return result;
01100 }
01101 
01102 const QString KMFilterActionAddHeader::displayString() const
01103 {
01104   // FIXME after string freeze:
01105   // return i18n("").arg( );
01106   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
01107 }
01108 
01109 void KMFilterActionAddHeader::argsFromString( const QString argsStr )
01110 {
01111   QStringList l = QStringList::split( '\t', argsStr, TRUE /*allow empty entries*/ );
01112   QString s;
01113   if ( l.count() < 2 ) {
01114     s = l[0];
01115     mValue = "";
01116   } else {
01117     s = l[0];
01118     mValue = l[1];
01119   }
01120 
01121   int idx = mParameterList.findIndex( s );
01122   if ( idx < 0 ) {
01123     mParameterList.append( s );
01124     idx = mParameterList.count() - 1;
01125   }
01126   mParameter = *mParameterList.at( idx );
01127 }
01128 
01129 
01130 //=============================================================================
01131 // KMFilterActionRewriteHeader - rewrite header
01132 // Rewrite a header using a regexp.
01133 //=============================================================================
01134 class KMFilterActionRewriteHeader: public KMFilterActionWithStringList
01135 {
01136 public:
01137   KMFilterActionRewriteHeader();
01138   virtual ReturnCode process(KMMessage* msg) const;
01139   virtual QWidget* createParamWidget( QWidget* parent ) const;
01140   virtual void setParamWidgetValue( QWidget* paramWidget ) const;
01141   virtual void applyParamWidgetValue( QWidget* paramWidget );
01142   virtual void clearParamWidget( QWidget* paramWidget ) const;
01143 
01144   virtual const QString argsAsString() const;
01145   virtual void argsFromString( const QString argsStr );
01146 
01147   virtual const QString displayString() const;
01148 
01149   static KMFilterAction* newAction()
01150   {
01151     return (new KMFilterActionRewriteHeader);
01152   }
01153 private:
01154   KRegExp3 mRegExp;
01155   QString mReplacementString;
01156 };
01157 
01158 KMFilterActionRewriteHeader::KMFilterActionRewriteHeader()
01159   : KMFilterActionWithStringList( "rewrite header", i18n("Rewrite Header") )
01160 {
01161   mParameterList << ""
01162                  << "Subject"
01163                  << "Reply-To"
01164                  << "Delivered-To"
01165                  << "X-KDE-PR-Message"
01166                  << "X-KDE-PR-Package"
01167                  << "X-KDE-PR-Keywords";
01168   mParameter = *mParameterList.at(0);
01169 }
01170 
01171 KMFilterAction::ReturnCode KMFilterActionRewriteHeader::process(KMMessage* msg) const
01172 {
01173   if ( mParameter.isEmpty() || !mRegExp.isValid() )
01174     return ErrorButGoOn;
01175 
01176   KRegExp3 rx = mRegExp; // KRegExp3::replace is not const.
01177 
01178   QString newValue = rx.replace( msg->headerField( mParameter.latin1() ),
01179                                      mReplacementString );
01180 
01181   msg->setHeaderField( mParameter.latin1(), newValue );
01182   return GoOn;
01183 }
01184 
01185 QWidget* KMFilterActionRewriteHeader::createParamWidget( QWidget* parent ) const
01186 {
01187   QWidget *w = new QWidget( parent );
01188   QHBoxLayout *hbl = new QHBoxLayout( w );
01189   hbl->setSpacing( 4 );
01190 
01191   QComboBox *cb = new QComboBox( TRUE, w, "combo" );
01192   cb->setInsertionPolicy( QComboBox::AtBottom );
01193   hbl->addWidget( cb, 0 /* stretch */ );
01194 
01195   QLabel *l = new QLabel( i18n("Replace:"), w );
01196   l->setFixedWidth( l->sizeHint().width() );
01197   hbl->addWidget( l, 0 );
01198 
01199   RegExpLineEdit *rele = new RegExpLineEdit( w, "search" );
01200   hbl->addWidget( rele, 1 );
01201 
01202   l = new QLabel( i18n("With:"), w );
01203   l->setFixedWidth( l->sizeHint().width() );
01204   hbl->addWidget( l, 0 );
01205 
01206   QLineEdit *le = new KLineEdit( w, "replace" );
01207   hbl->addWidget( le, 1 );
01208 
01209   setParamWidgetValue( w );
01210   return w;
01211 }
01212 
01213 void KMFilterActionRewriteHeader::setParamWidgetValue( QWidget* paramWidget ) const
01214 {
01215   int idx = mParameterList.findIndex( mParameter );
01216   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01217   Q_ASSERT( cb );
01218 
01219   cb->clear();
01220   cb->insertStringList( mParameterList );
01221   if ( idx < 0 ) {
01222     cb->insertItem( mParameter );
01223     cb->setCurrentItem( cb->count() - 1 );
01224   } else {
01225     cb->setCurrentItem( idx );
01226   }
01227 
01228   RegExpLineEdit *rele = (RegExpLineEdit*)paramWidget->child("search");
01229   Q_ASSERT( rele );
01230   rele->setText( mRegExp.pattern() );
01231 
01232   QLineEdit *le = (QLineEdit*)paramWidget->child("replace");
01233   Q_ASSERT( le );
01234   le->setText( mReplacementString );
01235 }
01236 
01237 void KMFilterActionRewriteHeader::applyParamWidgetValue( QWidget* paramWidget )
01238 {
01239   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01240   Q_ASSERT( cb );
01241   mParameter = cb->currentText();
01242 
01243   RegExpLineEdit *rele = (RegExpLineEdit*)paramWidget->child("search");
01244   Q_ASSERT( rele );
01245   mRegExp.setPattern( rele->text() );
01246 
01247   QLineEdit *le = (QLineEdit*)paramWidget->child("replace");
01248   Q_ASSERT( le );
01249   mReplacementString = le->text();
01250 }
01251 
01252 void KMFilterActionRewriteHeader::clearParamWidget( QWidget* paramWidget ) const
01253 {
01254   QComboBox *cb = (QComboBox*)paramWidget->child("combo");
01255   Q_ASSERT( cb );
01256   cb->setCurrentItem(0);
01257 
01258   RegExpLineEdit *rele = (RegExpLineEdit*)paramWidget->child("search");
01259   Q_ASSERT( rele );
01260   rele->clear();
01261 
01262   QLineEdit *le = (QLineEdit*)paramWidget->child("replace");
01263   Q_ASSERT( le );
01264   le->clear();
01265 }
01266 
01267 const QString KMFilterActionRewriteHeader::argsAsString() const
01268 {
01269   QString result = mParameter;
01270   result += '\t';
01271   result += mRegExp.pattern();
01272   result += '\t';
01273   result += mReplacementString;
01274 
01275   return result;
01276 }
01277 
01278 const QString KMFilterActionRewriteHeader::displayString() const
01279 {
01280   // FIXME after string freeze:
01281   // return i18n("").arg( );
01282   return label() + " \"" + QStyleSheet::escape( argsAsString() ) + "\"";
01283 }
01284 
01285 void KMFilterActionRewriteHeader::argsFromString( const QString argsStr )
01286 {
01287   QStringList l = QStringList::split( '\t', argsStr, TRUE /*allow empty entries*/ );
01288   QString s;
01289 
01290   s = l[0];
01291   mRegExp.setPattern( l[1] );
01292   mReplacementString = l[2];
01293 
01294   int idx = mParameterList.findIndex( s );
01295   if ( idx < 0 ) {
01296     mParameterList.append( s );
01297     idx = mParameterList.count() - 1;
01298   }
01299   mParameter = *mParameterList.at( idx );
01300 }
01301 
01302 
01303 //=============================================================================
01304 // KMFilterActionMove - move into folder
01305 // File message into another mail folder
01306 //=============================================================================
01307 class KMFilterActionMove: public KMFilterActionWithFolder
01308 {
01309 public:
01310   KMFilterActionMove();
01311   virtual ReturnCode process(KMMessage* msg) const;
01312   virtual bool requiresBody(KMMsgBase*) const;
01313   static KMFilterAction* newAction(void);
01314 };
01315 
01316 KMFilterAction* KMFilterActionMove::newAction(void)
01317 {
01318   return (new KMFilterActionMove);
01319 }
01320 
01321 KMFilterActionMove::KMFilterActionMove()
01322   : KMFilterActionWithFolder( "transfer", i18n("Move Into Folder") )
01323 {
01324 }
01325 
01326 KMFilterAction::ReturnCode KMFilterActionMove::process(KMMessage* msg) const
01327 {
01328   if ( !mFolder )
01329     return ErrorButGoOn;
01330 
01331   ActionScheduler *handler = MessageProperty::filterHandler( msg );
01332   if (handler) {
01333     MessageProperty::setFilterFolder( msg, mFolder );
01334   } else {
01335     // The old filtering system does not support online imap targets.
01336     // Skip online imap targets when using the old system.
01337     KMFolder *check;
01338     check = kmkernel->imapFolderMgr()->findIdString( argsAsString() );
01339     if (mFolder && (check != mFolder)) {
01340       MessageProperty::setFilterFolder( msg, mFolder );
01341     }
01342   }
01343   return GoOn;
01344 }
01345 
01346 bool KMFilterActionMove::requiresBody(KMMsgBase*) const
01347 {
01348     return false; //iff mFolder->folderMgr == msgBase->parent()->folderMgr;
01349 }
01350 
01351 
01352 //=============================================================================
01353 // KMFilterActionCopy - copy into folder
01354 // Copy message into another mail folder
01355 //=============================================================================
01356 class KMFilterActionCopy: public KMFilterActionWithFolder
01357 {
01358 public:
01359   KMFilterActionCopy();
01360   virtual ReturnCode process(KMMessage* msg) const;
01361   virtual void processAsync(KMMessage* msg) const;
01362   virtual bool requiresBody(KMMsgBase*) const;
01363   static KMFilterAction* newAction(void);
01364 };
01365 
01366 KMFilterAction* KMFilterActionCopy::newAction(void)
01367 {
01368   return (new KMFilterActionCopy);
01369 }
01370 
01371 KMFilterActionCopy::KMFilterActionCopy()
01372   : KMFilterActionWithFolder( "copy", i18n("Copy Into Folder") )
01373 {
01374 }
01375 
01376 KMFilterAction::ReturnCode KMFilterActionCopy::process(KMMessage* msg) const
01377 {
01378   // TODO opening and closing the folder is a trade off.
01379   // Perhaps Copy is a seldomly used action for now,
01380   // but I gonna look at improvements ASAP.
01381   if ( !mFolder && mFolder->open() != 0 )
01382     return ErrorButGoOn;
01383 
01384   // copy the message 1:1
01385   KMMessage* msgCopy = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
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