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