kcmshell renamed to kcmshell4 to fix co-installability between kdelibs3 and kdebase4...
[kdepim.git] / kmail / kmfilteraction.cpp
blob4d5d06a26852bb7c3d8ed9ae1ffbc49994b2b1bb
1 // kmfilteraction.cpp
3 #include "kmfilteraction.h"
5 // other KMail headers:
6 #include "kmcommands.h"
7 #include "kmmsgpart.h"
8 #include "kmfiltermgr.h"
9 #include "kmfolderindex.h"
10 #include "kmfoldermgr.h"
11 #include "messagesender.h"
12 #include "kmmainwidget.h"
13 #include <kpimidentities/identity.h>
14 #include <kpimidentities/identitymanager.h>
15 #include <kpimidentities/identitycombo.h>
16 #include <kpimutils/kfileio.h>
17 #include <mimelib/message.h>
18 #include "kmfawidgets.h"
19 #include "folderrequester.h"
20 using KMail::FolderRequester;
21 #include "kmmsgbase.h"
22 #include "templateparser.h"
23 using KMail::TemplateParser;
24 #include "messageproperty.h"
25 #include "actionscheduler.h"
26 using KMail::MessageProperty;
27 using KMail::ActionScheduler;
28 #include "regexplineedit.h"
29 using KMail::RegExpLineEdit;
31 #include <ktemporaryfile.h>
32 #include <kdebug.h>
33 #include <klocale.h>
34 #include <kurlrequester.h>
35 #include <Phonon/MediaObject>
36 #include <kshell.h>
37 #include <kprocess.h>
39 // Qt headers:
40 #include <QTextCodec>
41 #include <QTextDocument>
43 // other headers:
44 #include <assert.h>
47 //=============================================================================
49 // KMFilterAction
51 //=============================================================================
53 KMFilterAction::KMFilterAction( const char* aName, const QString &aLabel )
55 mName = aName;
56 mLabel = aLabel;
59 KMFilterAction::~KMFilterAction()
63 void KMFilterAction::processAsync(KMMessage* msg) const
65 ActionScheduler *handler = MessageProperty::filterHandler( msg );
66 ReturnCode result = process( msg );
67 if (handler)
68 handler->actionMessage( result );
71 bool KMFilterAction::requiresBody(KMMsgBase*) const
73 return true;
76 KMFilterAction* KMFilterAction::newAction()
78 return 0;
81 QWidget* KMFilterAction::createParamWidget(QWidget* parent) const
83 return new QWidget(parent);
86 void KMFilterAction::applyParamWidgetValue(QWidget*)
90 void KMFilterAction::setParamWidgetValue( QWidget * ) const
94 void KMFilterAction::clearParamWidget( QWidget * ) const
98 bool KMFilterAction::folderRemoved(KMFolder*, KMFolder*)
100 return false;
103 int KMFilterAction::tempOpenFolder(KMFolder* aFolder)
105 return kmkernel->filterMgr()->tempOpenFolder(aFolder);
108 void KMFilterAction::sendMDN( KMMessage * msg, KMime::MDN::DispositionType d,
109 const QList<KMime::MDN::DispositionModifier> & m ) {
110 if ( !msg ) return;
112 /* createMDN requires Return-Path and Disposition-Notification-To
113 * if it is not set in the message we assume that the notification should go to the
114 * sender
116 const QString returnPath = msg->headerField( "Return-Path" );
117 const QString dispNoteTo = msg->headerField( "Disposition-Notification-To" );
118 if ( returnPath.isEmpty() )
119 msg->setHeaderField( "Return-Path", msg->from() );
120 if ( dispNoteTo.isEmpty() )
121 msg->setHeaderField( "Disposition-Notification-To", msg->from() );
123 KMMessage * mdn = msg->createMDN( KMime::MDN::AutomaticAction, d, false, m );
124 if ( mdn && !kmkernel->msgSender()->send( mdn, KMail::MessageSender::SendLater ) ) {
125 kDebug(5006) <<"KMFilterAction::sendMDN(): sending failed.";
126 //delete mdn;
129 //restore orignial header
130 if ( returnPath.isEmpty() )
131 msg->removeHeaderField( "Return-Path" );
132 if ( dispNoteTo.isEmpty() )
133 msg->removeHeaderField( "Disposition-Notification-To" );
137 //=============================================================================
139 // KMFilterActionWithNone
141 //=============================================================================
143 KMFilterActionWithNone::KMFilterActionWithNone( const char* aName, const QString &aLabel )
144 : KMFilterAction( aName, aLabel )
148 const QString KMFilterActionWithNone::displayString() const
150 return label();
154 //=============================================================================
156 // KMFilterActionWithUOID
158 //=============================================================================
160 KMFilterActionWithUOID::KMFilterActionWithUOID( const char* aName, const QString &aLabel )
161 : KMFilterAction( aName, aLabel ), mParameter( 0 )
165 void KMFilterActionWithUOID::argsFromString( const QString &argsStr )
167 mParameter = argsStr.trimmed().toUInt();
170 const QString KMFilterActionWithUOID::argsAsString() const
172 return QString::number( mParameter );
175 const QString KMFilterActionWithUOID::displayString() const
177 // FIXME after string freeze:
178 // return i18n("").arg( );
179 return label() + " \"" + Qt::escape( argsAsString() ) + "\"";
183 //=============================================================================
185 // KMFilterActionWithString
187 //=============================================================================
189 KMFilterActionWithString::KMFilterActionWithString( const char* aName, const QString &aLabel )
190 : KMFilterAction( aName, aLabel )
194 QWidget* KMFilterActionWithString::createParamWidget( QWidget* parent ) const
196 QLineEdit *le = new KLineEdit(parent);
197 le->setText( mParameter );
198 return le;
201 void KMFilterActionWithString::applyParamWidgetValue( QWidget* paramWidget )
203 mParameter = ((QLineEdit*)paramWidget)->text();
206 void KMFilterActionWithString::setParamWidgetValue( QWidget* paramWidget ) const
208 ((QLineEdit*)paramWidget)->setText( mParameter );
211 void KMFilterActionWithString::clearParamWidget( QWidget* paramWidget ) const
213 ((QLineEdit*)paramWidget)->clear();
216 void KMFilterActionWithString::argsFromString( const QString &argsStr )
218 mParameter = argsStr;
221 const QString KMFilterActionWithString::argsAsString() const
223 return mParameter;
226 const QString KMFilterActionWithString::displayString() const
228 // FIXME after string freeze:
229 // return i18n("").arg( );
230 return label() + " \"" + Qt::escape( argsAsString() ) + "\"";
233 //=============================================================================
235 // class KMFilterActionWithStringList
237 //=============================================================================
239 KMFilterActionWithStringList::KMFilterActionWithStringList( const char* aName, const QString &aLabel )
240 : KMFilterActionWithString( aName, aLabel )
244 QWidget* KMFilterActionWithStringList::createParamWidget( QWidget* parent ) const
246 QComboBox *cb = new QComboBox( parent );
247 cb->setEditable( false );
248 cb->addItems( mParameterList );
249 setParamWidgetValue( cb );
250 return cb;
253 void KMFilterActionWithStringList::applyParamWidgetValue( QWidget* paramWidget )
255 mParameter = ((QComboBox*)paramWidget)->currentText();
258 void KMFilterActionWithStringList::setParamWidgetValue( QWidget* paramWidget ) const
260 int idx = mParameterList.indexOf( mParameter );
261 ((QComboBox*)paramWidget)->setCurrentIndex( idx >= 0 ? idx : 0 );
264 void KMFilterActionWithStringList::clearParamWidget( QWidget* paramWidget ) const
266 ((QComboBox*)paramWidget)->setCurrentIndex(0);
269 void KMFilterActionWithStringList::argsFromString( const QString &argsStr )
271 int idx = mParameterList.indexOf( argsStr );
272 if ( idx < 0 ) {
273 mParameterList.append( argsStr );
274 idx = mParameterList.count() - 1;
276 mParameter = mParameterList.at( idx );
280 //=============================================================================
282 // class KMFilterActionWithFolder
284 //=============================================================================
286 KMFilterActionWithFolder::KMFilterActionWithFolder( const char* aName, const QString &aLabel )
287 : KMFilterAction( aName, aLabel )
289 mFolder = 0;
292 QWidget* KMFilterActionWithFolder::createParamWidget( QWidget* parent ) const
294 FolderRequester *req = new FolderRequester( parent,
295 kmkernel->getKMMainWidget()->folderTree() );
296 setParamWidgetValue( req );
297 return req;
300 void KMFilterActionWithFolder::applyParamWidgetValue( QWidget* paramWidget )
302 mFolder = ((FolderRequester *)paramWidget)->folder();
303 mFolderName = ((FolderRequester *)paramWidget)->folderId();
306 void KMFilterActionWithFolder::setParamWidgetValue( QWidget* paramWidget ) const
308 if ( mFolder )
309 ((FolderRequester *)paramWidget)->setFolder( mFolder );
310 else
311 ((FolderRequester *)paramWidget)->setFolder( mFolderName );
314 void KMFilterActionWithFolder::clearParamWidget( QWidget* paramWidget ) const
316 ((FolderRequester *)paramWidget)->setFolder( kmkernel->draftsFolder() );
319 void KMFilterActionWithFolder::argsFromString( const QString &argsStr )
321 mFolder = kmkernel->folderMgr()->findIdString( argsStr );
322 if (!mFolder)
323 mFolder = kmkernel->dimapFolderMgr()->findIdString( argsStr );
324 if (!mFolder)
325 mFolder = kmkernel->imapFolderMgr()->findIdString( argsStr );
326 if (mFolder)
327 mFolderName = mFolder->idString();
328 else
329 mFolderName = argsStr;
332 const QString KMFilterActionWithFolder::argsAsString() const
334 QString result;
335 if ( mFolder )
336 result = mFolder->idString();
337 else
338 result = mFolderName;
339 return result;
342 const QString KMFilterActionWithFolder::displayString() const
344 QString result;
345 if ( mFolder )
346 result = mFolder->prettyUrl();
347 else
348 result = mFolderName;
349 return label() + " \"" + Qt::escape( result ) + "\"";
352 bool KMFilterActionWithFolder::folderRemoved( KMFolder* aFolder, KMFolder* aNewFolder )
354 if ( aFolder == mFolder ) {
355 mFolder = aNewFolder;
356 if ( aNewFolder )
357 mFolderName = mFolder->idString();
358 return true;
359 } else
360 return false;
363 //=============================================================================
365 // class KMFilterActionWithAddress
367 //=============================================================================
369 KMFilterActionWithAddress::KMFilterActionWithAddress( const char* aName, const QString &aLabel )
370 : KMFilterActionWithString( aName, aLabel )
374 QWidget* KMFilterActionWithAddress::createParamWidget( QWidget* parent ) const
376 KMFilterActionWithAddressWidget *w = new KMFilterActionWithAddressWidget(parent);
377 w->setText( mParameter );
378 return w;
381 void KMFilterActionWithAddress::applyParamWidgetValue( QWidget* paramWidget )
383 mParameter = ((KMFilterActionWithAddressWidget*)paramWidget)->text();
386 void KMFilterActionWithAddress::setParamWidgetValue( QWidget* paramWidget ) const
388 ((KMFilterActionWithAddressWidget*)paramWidget)->setText( mParameter );
391 void KMFilterActionWithAddress::clearParamWidget( QWidget* paramWidget ) const
393 ((KMFilterActionWithAddressWidget*)paramWidget)->clear();
396 //=============================================================================
398 // class KMFilterActionWithCommand
400 //=============================================================================
402 KMFilterActionWithCommand::KMFilterActionWithCommand( const char* aName, const QString &aLabel )
403 : KMFilterActionWithUrl( aName, aLabel )
407 QWidget* KMFilterActionWithCommand::createParamWidget( QWidget* parent ) const
409 return KMFilterActionWithUrl::createParamWidget( parent );
412 void KMFilterActionWithCommand::applyParamWidgetValue( QWidget* paramWidget )
414 KMFilterActionWithUrl::applyParamWidgetValue( paramWidget );
417 void KMFilterActionWithCommand::setParamWidgetValue( QWidget* paramWidget ) const
419 KMFilterActionWithUrl::setParamWidgetValue( paramWidget );
422 void KMFilterActionWithCommand::clearParamWidget( QWidget* paramWidget ) const
424 KMFilterActionWithUrl::clearParamWidget( paramWidget );
427 QString KMFilterActionWithCommand::substituteCommandLineArgsFor( KMMessage *aMsg, QList<KTemporaryFile*> & aTempFileList ) const
429 QString result = mParameter;
430 QList<int> argList;
431 QRegExp r( "%[0-9-]+" );
433 // search for '%n'
434 int start = -1;
435 while ( ( start = r.indexIn( result, start + 1 ) ) > 0 ) {
436 int len = r.matchedLength();
437 // and save the encountered 'n' in a list.
438 bool OK = false;
439 int n = result.mid( start + 1, len - 1 ).toInt( &OK );
440 if ( OK )
441 argList.append( n );
444 // sort the list of n's
445 qSort( argList );
447 // and use QString::arg to substitute filenames for the %n's.
448 int lastSeen = -2;
449 QString tempFileName;
450 for ( QList<int>::Iterator it = argList.begin() ; it != argList.end() ; ++it ) {
451 // setup temp files with check for duplicate %n's
452 if ( (*it) != lastSeen ) {
453 KTemporaryFile *tf = new KTemporaryFile();
454 if ( !tf->open() ) {
455 delete tf;
456 kDebug(5006) <<"KMFilterActionWithCommand: Could not create temp file!";
457 return QString();
459 aTempFileList.append( tf );
460 tempFileName = tf->fileName();
461 if ((*it) == -1)
462 KPIMUtils::kByteArrayToFile( aMsg->asString(), tempFileName, //###
463 false, false, false );
464 else if (aMsg->numBodyParts() == 0)
465 KPIMUtils::kByteArrayToFile( aMsg->bodyDecodedBinary(), tempFileName,
466 false, false, false );
467 else {
468 KMMessagePart msgPart;
469 aMsg->bodyPart( (*it), &msgPart );
470 KPIMUtils::kByteArrayToFile( msgPart.bodyDecodedBinary(), tempFileName,
471 false, false, false );
473 tf->close();
475 // QString( "%0 and %1 and %1" ).arg( 0 ).arg( 1 )
476 // returns "0 and 1 and %1", so we must call .arg as
477 // many times as there are %n's, regardless of their multiplicity.
478 if ((*it) == -1) result.replace( "%-1", tempFileName );
479 else result = result.arg( tempFileName );
482 // And finally, replace the %{foo} with the content of the foo
483 // header field:
484 QRegExp header_rx( "%\\{([a-z0-9-]+)\\}", Qt::CaseInsensitive );
485 int idx = 0;
486 while ( ( idx = header_rx.indexIn( result, idx ) ) != -1 ) {
487 QString replacement = KShell::quoteArg( aMsg->headerField( header_rx.cap(1).toLatin1() ) );
488 result.replace( idx, header_rx.matchedLength(), replacement );
489 idx += replacement.length();
492 return result;
496 KMFilterAction::ReturnCode KMFilterActionWithCommand::genericProcess(KMMessage* aMsg, bool withOutput) const
498 Q_ASSERT( aMsg );
500 if ( mParameter.isEmpty() )
501 return ErrorButGoOn;
503 // K3Process doesn't support a QProcess::launch() equivalent, so
504 // we must use a temp file :-(
505 KTemporaryFile * inFile = new KTemporaryFile;
506 inFile->open();
508 QList<KTemporaryFile*> atmList;
509 atmList.append( inFile );
511 QString commandLine = substituteCommandLineArgsFor( aMsg , atmList );
512 if ( commandLine.isEmpty() )
513 return ErrorButGoOn;
515 // The parentheses force the creation of a subshell
516 // in which the user-specified command is executed.
517 // This is to really catch all output of the command as well
518 // as to avoid clashes of our redirection with the ones
519 // the user may have specified. In the long run, we
520 // shouldn't be using tempfiles at all for this class, due
521 // to security aspects. (mmutz)
522 commandLine = '(' + commandLine + ") <" + inFile->fileName();
524 // write message to file
525 QString tempFileName = inFile->fileName();
526 KPIMUtils::kByteArrayToFile( aMsg->asString(), tempFileName, //###
527 false, false, false );
528 inFile->close();
530 KProcess shProc;
531 shProc.setOutputChannelMode( KProcess::SeparateChannels );
532 shProc.setShellCommand( commandLine );
533 int result = shProc.execute();
535 if ( result != 0 ) {
536 qDeleteAll( atmList );
537 atmList.clear();
538 return ErrorButGoOn;
541 if ( withOutput ) {
542 // read altered message:
543 QByteArray msgText = shProc.readAllStandardOutput();
545 if ( !msgText.isEmpty() ) {
546 /* If the pipe through alters the message, it could very well
547 happen that it no longer has a X-UID header afterwards. That is
548 unfortunate, as we need to removed the original from the folder
549 using that, and look it up in the message. When the (new) message
550 is uploaded, the header is stripped anyhow. */
551 QString uid = aMsg->headerField("X-UID");
552 aMsg->fromString( msgText );
553 aMsg->setHeaderField("X-UID",uid);
555 else {
556 qDeleteAll( atmList );
557 atmList.clear();
558 return ErrorButGoOn;
561 qDeleteAll( atmList );
562 atmList.clear();
563 return GoOn;
567 //=============================================================================
569 // Specific Filter Actions
571 //=============================================================================
573 //=============================================================================
574 // KMFilterActionSendReceipt - send receipt
575 // Return delivery receipt.
576 //=============================================================================
577 class KMFilterActionSendReceipt : public KMFilterActionWithNone
579 public:
580 KMFilterActionSendReceipt();
581 virtual ReturnCode process(KMMessage* msg) const;
582 static KMFilterAction* newAction(void);
585 KMFilterAction* KMFilterActionSendReceipt::newAction(void)
587 return (new KMFilterActionSendReceipt);
590 KMFilterActionSendReceipt::KMFilterActionSendReceipt()
591 : KMFilterActionWithNone( "confirm delivery", i18n("Confirm Delivery") )
595 KMFilterAction::ReturnCode KMFilterActionSendReceipt::process(KMMessage* msg) const
597 KMMessage *receipt = msg->createDeliveryReceipt();
598 if ( !receipt ) return ErrorButGoOn;
600 // Queue message. This is a) so that the user can check
601 // the receipt before sending and b) for speed reasons.
602 kmkernel->msgSender()->send( receipt, KMail::MessageSender::SendLater );
604 return GoOn;
609 //=============================================================================
610 // KMFilterActionSetTransport - set transport to...
611 // Specify mail transport (smtp server) to be used when replying to a message
612 // TODO: use TransportComboBox so the user does not enter an invalid transport
613 //=============================================================================
614 class KMFilterActionTransport: public KMFilterActionWithString
616 public:
617 KMFilterActionTransport();
618 virtual ReturnCode process(KMMessage* msg) const;
619 static KMFilterAction* newAction(void);
622 KMFilterAction* KMFilterActionTransport::newAction(void)
624 return (new KMFilterActionTransport);
627 KMFilterActionTransport::KMFilterActionTransport()
628 : KMFilterActionWithString( "set transport", i18n("Set Transport To") )
632 KMFilterAction::ReturnCode KMFilterActionTransport::process(KMMessage* msg) const
634 if ( mParameter.isEmpty() )
635 return ErrorButGoOn;
636 msg->setHeaderField( "X-KMail-Transport", mParameter );
637 return GoOn;
641 //=============================================================================
642 // KMFilterActionReplyTo - set Reply-To to
643 // Set the Reply-to header in a message
644 //=============================================================================
645 class KMFilterActionReplyTo: public KMFilterActionWithString
647 public:
648 KMFilterActionReplyTo();
649 virtual ReturnCode process(KMMessage* msg) const;
650 static KMFilterAction* newAction(void);
653 KMFilterAction* KMFilterActionReplyTo::newAction(void)
655 return (new KMFilterActionReplyTo);
658 KMFilterActionReplyTo::KMFilterActionReplyTo()
659 : KMFilterActionWithString( "set Reply-To", i18n("Set Reply-To To") )
661 mParameter = "";
664 KMFilterAction::ReturnCode KMFilterActionReplyTo::process(KMMessage* msg) const
666 msg->setHeaderField( "Reply-To", mParameter );
667 return GoOn;
672 //=============================================================================
673 // KMFilterActionIdentity - set identity to
674 // Specify Identity to be used when replying to a message
675 //=============================================================================
676 class KMFilterActionIdentity: public KMFilterActionWithUOID
678 public:
679 KMFilterActionIdentity();
680 virtual ReturnCode process(KMMessage* msg) const;
681 static KMFilterAction* newAction();
683 QWidget * createParamWidget( QWidget * parent ) const;
684 void applyParamWidgetValue( QWidget * parent );
685 void setParamWidgetValue( QWidget * parent ) const;
686 void clearParamWidget( QWidget * param ) const;
689 KMFilterAction* KMFilterActionIdentity::newAction()
691 return (new KMFilterActionIdentity);
694 KMFilterActionIdentity::KMFilterActionIdentity()
695 : KMFilterActionWithUOID( "set identity", i18n("Set Identity To") )
697 mParameter = kmkernel->identityManager()->defaultIdentity().uoid();
700 KMFilterAction::ReturnCode KMFilterActionIdentity::process(KMMessage* msg) const
702 msg->setHeaderField( "X-KMail-Identity", QString::number( mParameter ) );
703 return GoOn;
706 QWidget * KMFilterActionIdentity::createParamWidget( QWidget * parent ) const
708 KPIMIdentities::IdentityCombo * ic = new KPIMIdentities::IdentityCombo( kmkernel->identityManager(), parent );
709 ic->setCurrentIdentity( mParameter );
710 return ic;
713 void KMFilterActionIdentity::applyParamWidgetValue( QWidget * paramWidget )
715 KPIMIdentities::IdentityCombo * ic = dynamic_cast<KPIMIdentities::IdentityCombo*>( paramWidget );
716 assert( ic );
717 mParameter = ic->currentIdentity();
720 void KMFilterActionIdentity::clearParamWidget( QWidget * paramWidget ) const
722 KPIMIdentities::IdentityCombo * ic = dynamic_cast<KPIMIdentities::IdentityCombo*>( paramWidget );
723 assert( ic );
724 ic->setCurrentIndex( 0 );
725 //ic->setCurrentIdentity( kmkernel->identityManager()->defaultIdentity() );
728 void KMFilterActionIdentity::setParamWidgetValue( QWidget * paramWidget ) const
730 KPIMIdentities::IdentityCombo * ic = dynamic_cast<KPIMIdentities::IdentityCombo*>( paramWidget );
731 assert( ic );
732 ic->setCurrentIdentity( mParameter );
735 //=============================================================================
736 // KMFilterActionSetStatus - set status to
737 // Set the status of messages
738 //=============================================================================
739 class KMFilterActionSetStatus: public KMFilterActionWithStringList
741 public:
742 KMFilterActionSetStatus();
743 virtual ReturnCode process(KMMessage* msg) const;
744 virtual bool requiresBody(KMMsgBase*) const;
746 static KMFilterAction* newAction();
748 virtual bool isEmpty() const { return false; }
750 virtual void argsFromString( const QString &argsStr );
751 virtual const QString argsAsString() const;
752 virtual const QString displayString() const;
756 static const MessageStatus stati[] =
758 MessageStatus::statusImportant(),
759 MessageStatus::statusRead(),
760 MessageStatus::statusUnread(),
761 MessageStatus::statusReplied(),
762 MessageStatus::statusForwarded(),
763 MessageStatus::statusOld(),
764 MessageStatus::statusNew(),
765 MessageStatus::statusWatched(),
766 MessageStatus::statusIgnored(),
767 MessageStatus::statusSpam(),
768 MessageStatus::statusHam()
770 static const int StatiCount = sizeof( stati ) / sizeof( MessageStatus );
772 KMFilterAction* KMFilterActionSetStatus::newAction()
774 return (new KMFilterActionSetStatus);
777 KMFilterActionSetStatus::KMFilterActionSetStatus()
778 : KMFilterActionWithStringList( "set status", i18n("Mark As") )
780 // if you change this list, also update
781 // KMFilterActionSetStatus::stati above
782 mParameterList.append( "" );
783 mParameterList.append( i18nc("msg status","Important") );
784 mParameterList.append( i18nc("msg status","Read") );
785 mParameterList.append( i18nc("msg status","Unread") );
786 mParameterList.append( i18nc("msg status","Replied") );
787 mParameterList.append( i18nc("msg status","Forwarded") );
788 mParameterList.append( i18nc("msg status","Old") );
789 mParameterList.append( i18nc("msg status","New") );
790 mParameterList.append( i18nc("msg status","Watched") );
791 mParameterList.append( i18nc("msg status","Ignored") );
792 mParameterList.append( i18nc("msg status","Spam") );
793 mParameterList.append( i18nc("msg status","Ham") );
795 mParameter = mParameterList.at(0);
798 KMFilterAction::ReturnCode KMFilterActionSetStatus::process(KMMessage* msg) const
800 int idx = mParameterList.indexOf( mParameter );
801 if ( idx < 1 ) return ErrorButGoOn;
803 msg->setStatus( stati[idx-1] );
804 return GoOn;
807 bool KMFilterActionSetStatus::requiresBody(KMMsgBase*) const
809 return false;
812 void KMFilterActionSetStatus::argsFromString( const QString &argsStr )
814 if ( argsStr.length() == 1 ) {
815 MessageStatus status;
816 int i;
817 for ( i = 0 ; i < StatiCount ; i++ )
819 status = stati[i];
820 if ( status.getStatusStr()[0] == argsStr[0].toLatin1() ) {
821 mParameter = mParameterList.at(i+1);
822 return;
826 mParameter = mParameterList.at(0);
829 const QString KMFilterActionSetStatus::argsAsString() const
831 int idx = mParameterList.indexOf( mParameter );
832 if ( idx < 1 ) return QString();
834 return stati[idx-1].getStatusStr();
837 const QString KMFilterActionSetStatus::displayString() const
839 // FIXME after string freeze:
840 // return i18n("").arg( );
841 return label() + " \"" + Qt::escape( argsAsString() ) + "\"";
844 //=============================================================================
845 // KMFilterActionFakeDisposition - send fake MDN
846 // Sends a fake MDN or forces an ignore.
847 //=============================================================================
848 class KMFilterActionFakeDisposition: public KMFilterActionWithStringList
850 public:
851 KMFilterActionFakeDisposition();
852 virtual ReturnCode process(KMMessage* msg) const;
853 static KMFilterAction* newAction() {
854 return (new KMFilterActionFakeDisposition);
857 virtual bool isEmpty() const { return false; }
859 virtual void argsFromString( const QString &argsStr );
860 virtual const QString argsAsString() const;
861 virtual const QString displayString() const;
865 // if you change this list, also update
866 // the count in argsFromString
867 static const KMime::MDN::DispositionType mdns[] =
869 KMime::MDN::Displayed,
870 KMime::MDN::Deleted,
871 KMime::MDN::Dispatched,
872 KMime::MDN::Processed,
873 KMime::MDN::Denied,
874 KMime::MDN::Failed,
876 static const int numMDNs = sizeof mdns / sizeof *mdns;
879 KMFilterActionFakeDisposition::KMFilterActionFakeDisposition()
880 : KMFilterActionWithStringList( "fake mdn", i18n("Send Fake MDN") )
882 // if you change this list, also update
883 // mdns above
884 mParameterList.append( "" );
885 mParameterList.append( i18nc("MDN type","Ignore") );
886 mParameterList.append( i18nc("MDN type","Displayed") );
887 mParameterList.append( i18nc("MDN type","Deleted") );
888 mParameterList.append( i18nc("MDN type","Dispatched") );
889 mParameterList.append( i18nc("MDN type","Processed") );
890 mParameterList.append( i18nc("MDN type","Denied") );
891 mParameterList.append( i18nc("MDN type","Failed") );
893 mParameter = mParameterList.at(0);
896 KMFilterAction::ReturnCode KMFilterActionFakeDisposition::process(KMMessage* msg) const
898 int idx = mParameterList.indexOf( mParameter );
899 if ( idx < 1 ) return ErrorButGoOn;
901 if ( idx == 1 ) // ignore
902 msg->setMDNSentState( KMMsgMDNIgnore );
903 else // send
904 sendMDN( msg, mdns[idx-2] ); // skip first two entries: "" and "ignore"
905 return GoOn;
908 void KMFilterActionFakeDisposition::argsFromString( const QString &argsStr )
910 if ( argsStr.length() == 1 ) {
911 if ( argsStr[0] == 'I' ) { // ignore
912 mParameter = mParameterList.at(1);
913 return;
915 for ( int i = 0 ; i < numMDNs ; i++ )
916 if ( char(mdns[i]) == argsStr[0] ) { // send
917 mParameter = mParameterList.at(i+2);
918 return;
921 mParameter = mParameterList.at(0);
924 const QString KMFilterActionFakeDisposition::argsAsString() const
926 int idx = mParameterList.indexOf( mParameter );
927 if ( idx < 1 ) return QString();
929 return QString( QChar( idx < 2 ? 'I' : char(mdns[idx-2]) ) );
932 const QString KMFilterActionFakeDisposition::displayString() const
934 // FIXME after string freeze:
935 // return i18n("").arg( );
936 return label() + " \"" + Qt::escape( argsAsString() ) + "\"";
939 //=============================================================================
940 // KMFilterActionRemoveHeader - remove header
941 // Remove all instances of the given header field.
942 //=============================================================================
943 class KMFilterActionRemoveHeader: public KMFilterActionWithStringList
945 public:
946 KMFilterActionRemoveHeader();
947 virtual ReturnCode process(KMMessage* msg) const;
948 virtual QWidget* createParamWidget( QWidget* parent ) const;
949 virtual void setParamWidgetValue( QWidget* paramWidget ) const;
951 static KMFilterAction* newAction();
954 KMFilterAction* KMFilterActionRemoveHeader::newAction()
956 return (new KMFilterActionRemoveHeader);
959 KMFilterActionRemoveHeader::KMFilterActionRemoveHeader()
960 : KMFilterActionWithStringList( "remove header", i18n("Remove Header") )
962 mParameterList << ""
963 << "Reply-To"
964 << "Delivered-To"
965 << "X-KDE-PR-Message"
966 << "X-KDE-PR-Package"
967 << "X-KDE-PR-Keywords";
968 mParameter = mParameterList.at(0);
971 QWidget* KMFilterActionRemoveHeader::createParamWidget( QWidget* parent ) const
973 QComboBox *cb = new QComboBox( parent );
974 cb->setEditable( true );
975 cb->setInsertPolicy( QComboBox::AtBottom );
976 setParamWidgetValue( cb );
977 return cb;
980 KMFilterAction::ReturnCode KMFilterActionRemoveHeader::process(KMMessage* msg) const
982 if ( mParameter.isEmpty() ) return ErrorButGoOn;
984 while ( !msg->headerField( mParameter.toLatin1() ).isEmpty() )
985 msg->removeHeaderField( mParameter.toLatin1() );
986 return GoOn;
989 void KMFilterActionRemoveHeader::setParamWidgetValue( QWidget* paramWidget ) const
991 QComboBox * cb = dynamic_cast<QComboBox*>(paramWidget);
992 Q_ASSERT( cb );
994 int idx = mParameterList.indexOf( mParameter );
995 cb->clear();
996 cb->addItems( mParameterList );
997 if ( idx < 0 ) {
998 cb->addItem( mParameter );
999 cb->setCurrentIndex( cb->count() - 1 );
1000 } else {
1001 cb->setCurrentIndex( idx );
1006 //=============================================================================
1007 // KMFilterActionAddHeader - add header
1008 // Add a header with the given value.
1009 //=============================================================================
1010 class KMFilterActionAddHeader: public KMFilterActionWithStringList
1012 public:
1013 KMFilterActionAddHeader();
1014 virtual ReturnCode process(KMMessage* msg) const;
1015 virtual QWidget* createParamWidget( QWidget* parent ) const;
1016 virtual void setParamWidgetValue( QWidget* paramWidget ) const;
1017 virtual void applyParamWidgetValue( QWidget* paramWidget );
1018 virtual void clearParamWidget( QWidget* paramWidget ) const;
1020 virtual const QString argsAsString() const;
1021 virtual void argsFromString( const QString &argsStr );
1023 virtual const QString displayString() const;
1025 static KMFilterAction* newAction()
1027 return (new KMFilterActionAddHeader);
1029 private:
1030 QString mValue;
1033 KMFilterActionAddHeader::KMFilterActionAddHeader()
1034 : KMFilterActionWithStringList( "add header", i18n("Add Header") )
1036 mParameterList << ""
1037 << "Reply-To"
1038 << "Delivered-To"
1039 << "X-KDE-PR-Message"
1040 << "X-KDE-PR-Package"
1041 << "X-KDE-PR-Keywords";
1042 mParameter = mParameterList.at(0);
1045 KMFilterAction::ReturnCode KMFilterActionAddHeader::process(KMMessage* msg) const
1047 if ( mParameter.isEmpty() ) return ErrorButGoOn;
1049 msg->setHeaderField( mParameter.toLatin1(), mValue );
1050 return GoOn;
1053 QWidget* KMFilterActionAddHeader::createParamWidget( QWidget* parent ) const
1055 QWidget *w = new QWidget( parent );
1056 QHBoxLayout *hbl = new QHBoxLayout( w );
1057 hbl->setSpacing( 4 );
1058 hbl->setMargin( 0 );
1059 QComboBox *cb = new QComboBox( w );
1060 cb->setObjectName( "combo" );
1061 cb->setEditable( true );
1062 cb->setInsertPolicy( QComboBox::AtBottom );
1063 hbl->addWidget( cb, 0 /* stretch */ );
1064 QLabel *l = new QLabel( i18n("With value:"), w );
1065 l->setFixedWidth( l->sizeHint().width() );
1066 hbl->addWidget( l, 0 );
1067 QLineEdit *le = new KLineEdit( w );
1068 le->setObjectName( "ledit" );
1069 hbl->addWidget( le, 1 );
1070 setParamWidgetValue( w );
1071 return w;
1074 void KMFilterActionAddHeader::setParamWidgetValue( QWidget* paramWidget ) const
1076 int idx = mParameterList.indexOf( mParameter );
1077 QComboBox *cb = paramWidget->findChild<QComboBox*>("combo");
1078 Q_ASSERT( cb );
1079 cb->clear();
1080 cb->addItems( mParameterList );
1081 if ( idx < 0 ) {
1082 cb->addItem( mParameter );
1083 cb->setCurrentIndex( cb->count() - 1 );
1084 } else {
1085 cb->setCurrentIndex( idx );
1087 QLineEdit *le = paramWidget->findChild<QLineEdit*>("ledit");
1088 Q_ASSERT( le );
1089 le->setText( mValue );
1092 void KMFilterActionAddHeader::applyParamWidgetValue( QWidget* paramWidget )
1094 QComboBox *cb = paramWidget->findChild<QComboBox*>("combo");
1095 Q_ASSERT( cb );
1096 mParameter = cb->currentText();
1098 QLineEdit *le = paramWidget->findChild<QLineEdit*>("ledit");
1099 Q_ASSERT( le );
1100 mValue = le->text();
1103 void KMFilterActionAddHeader::clearParamWidget( QWidget* paramWidget ) const
1105 QComboBox *cb = paramWidget->findChild<QComboBox*>("combo");
1106 Q_ASSERT( cb );
1107 cb->setCurrentIndex(0);
1108 QLineEdit *le = paramWidget->findChild<QLineEdit*>("ledit");
1109 Q_ASSERT( le );
1110 le->clear();
1113 const QString KMFilterActionAddHeader::argsAsString() const
1115 QString result = mParameter;
1116 result += '\t';
1117 result += mValue;
1119 return result;
1122 const QString KMFilterActionAddHeader::displayString() const
1124 // FIXME after string freeze:
1125 // return i18n("").arg( );
1126 return label() + " \"" + Qt::escape( argsAsString() ) + "\"";
1129 void KMFilterActionAddHeader::argsFromString( const QString &argsStr )
1131 QStringList l = argsStr.split( '\t' );
1132 QString s;
1133 if ( l.count() < 2 ) {
1134 s = l[0];
1135 mValue = "";
1136 } else {
1137 s = l[0];
1138 mValue = l[1];
1141 int idx = mParameterList.indexOf( s );
1142 if ( idx < 0 ) {
1143 mParameterList.append( s );
1144 idx = mParameterList.count() - 1;
1146 mParameter = mParameterList.at( idx );
1150 //=============================================================================
1151 // KMFilterActionRewriteHeader - rewrite header
1152 // Rewrite a header using a regexp.
1153 //=============================================================================
1154 class KMFilterActionRewriteHeader: public KMFilterActionWithStringList
1156 public:
1157 KMFilterActionRewriteHeader();
1158 virtual ReturnCode process(KMMessage* msg) const;
1159 virtual QWidget* createParamWidget( QWidget* parent ) const;
1160 virtual void setParamWidgetValue( QWidget* paramWidget ) const;
1161 virtual void applyParamWidgetValue( QWidget* paramWidget );
1162 virtual void clearParamWidget( QWidget* paramWidget ) const;
1164 virtual const QString argsAsString() const;
1165 virtual void argsFromString( const QString &argsStr );
1167 virtual const QString displayString() const;
1169 static KMFilterAction* newAction()
1171 return (new KMFilterActionRewriteHeader);
1173 private:
1174 QRegExp mRegExp;
1175 QString mReplacementString;
1178 KMFilterActionRewriteHeader::KMFilterActionRewriteHeader()
1179 : KMFilterActionWithStringList( "rewrite header", i18n("Rewrite Header") )
1181 mParameterList << ""
1182 << "Subject"
1183 << "Reply-To"
1184 << "Delivered-To"
1185 << "X-KDE-PR-Message"
1186 << "X-KDE-PR-Package"
1187 << "X-KDE-PR-Keywords";
1188 mParameter = mParameterList.at(0);
1191 KMFilterAction::ReturnCode KMFilterActionRewriteHeader::process(KMMessage* msg) const
1193 if ( mParameter.isEmpty() || !mRegExp.isValid() )
1194 return ErrorButGoOn;
1195 // QString::replace is not const.
1196 QString value = msg->headerField( mParameter.toLatin1() );
1197 msg->setHeaderField( mParameter.toLatin1(), value.replace( mRegExp, mReplacementString ) );
1198 return GoOn;
1201 QWidget* KMFilterActionRewriteHeader::createParamWidget( QWidget* parent ) const
1203 QWidget *w = new QWidget( parent );
1204 QHBoxLayout *hbl = new QHBoxLayout( w );
1205 hbl->setSpacing( 4 );
1206 hbl->setMargin( 0 );
1208 QComboBox *cb = new QComboBox( w );
1209 cb->setEditable( true );
1210 cb->setObjectName( "combo" );
1211 cb->setInsertPolicy( QComboBox::AtBottom );
1212 hbl->addWidget( cb, 0 /* stretch */ );
1214 QLabel *l = new QLabel( i18n("Replace:"), w );
1215 l->setFixedWidth( l->sizeHint().width() );
1216 hbl->addWidget( l, 0 );
1218 RegExpLineEdit *rele = new RegExpLineEdit( w );
1219 rele->setObjectName( "search" );
1220 hbl->addWidget( rele, 1 );
1222 l = new QLabel( i18n("With:"), w );
1223 l->setFixedWidth( l->sizeHint().width() );
1224 hbl->addWidget( l, 0 );
1226 QLineEdit *le = new KLineEdit( w );
1227 le->setObjectName( "replace" );
1228 hbl->addWidget( le, 1 );
1230 setParamWidgetValue( w );
1231 return w;
1234 void KMFilterActionRewriteHeader::setParamWidgetValue( QWidget* paramWidget ) const
1236 int idx = mParameterList.indexOf( mParameter );
1237 QComboBox *cb = paramWidget->findChild<QComboBox*>("combo");
1238 Q_ASSERT( cb );
1240 cb->clear();
1241 cb->addItems( mParameterList );
1242 if ( idx < 0 ) {
1243 cb->addItem( mParameter );
1244 cb->setCurrentIndex( cb->count() - 1 );
1245 } else {
1246 cb->setCurrentIndex( idx );
1249 RegExpLineEdit *rele = paramWidget->findChild<RegExpLineEdit*>("search");
1250 Q_ASSERT( rele );
1251 rele->setText( mRegExp.pattern() );
1253 QLineEdit *le = paramWidget->findChild<QLineEdit*>("replace");
1254 Q_ASSERT( le );
1255 le->setText( mReplacementString );
1258 void KMFilterActionRewriteHeader::applyParamWidgetValue( QWidget* paramWidget )
1260 QComboBox *cb = paramWidget->findChild<QComboBox*>("combo");
1261 Q_ASSERT( cb );
1262 mParameter = cb->currentText();
1264 RegExpLineEdit *rele = paramWidget->findChild<RegExpLineEdit*>("search");
1265 Q_ASSERT( rele );
1266 mRegExp.setPattern( rele->text() );
1268 QLineEdit *le = paramWidget->findChild<QLineEdit*>("replace");
1269 Q_ASSERT( le );
1270 mReplacementString = le->text();
1273 void KMFilterActionRewriteHeader::clearParamWidget( QWidget* paramWidget ) const
1275 QComboBox *cb = paramWidget->findChild<QComboBox*>("combo");
1276 Q_ASSERT( cb );
1277 cb->setCurrentIndex(0);
1279 RegExpLineEdit *rele = paramWidget->findChild<RegExpLineEdit*>("search");
1280 Q_ASSERT( rele );
1281 rele->clear();
1283 QLineEdit *le = paramWidget->findChild<QLineEdit*>("replace");
1284 Q_ASSERT( le );
1285 le->clear();
1288 const QString KMFilterActionRewriteHeader::argsAsString() const
1290 QString result = mParameter;
1291 result += '\t';
1292 result += mRegExp.pattern();
1293 result += '\t';
1294 result += mReplacementString;
1296 return result;
1299 const QString KMFilterActionRewriteHeader::displayString() const
1301 // FIXME after string freeze:
1302 // return i18n("").arg( );
1303 return label() + " \"" + Qt::escape( argsAsString() ) + "\"";
1306 void KMFilterActionRewriteHeader::argsFromString( const QString &argsStr )
1308 QStringList l = argsStr.split( '\t' );
1309 QString s;
1311 s = l[0];
1312 mRegExp.setPattern( l[1] );
1313 mReplacementString = l[2];
1315 int idx = mParameterList.indexOf( s );
1316 if ( idx < 0 ) {
1317 mParameterList.append( s );
1318 idx = mParameterList.count() - 1;
1320 mParameter = mParameterList.at( idx );
1324 //=============================================================================
1325 // KMFilterActionMove - move into folder
1326 // File message into another mail folder
1327 //=============================================================================
1328 class KMFilterActionMove: public KMFilterActionWithFolder
1330 public:
1331 KMFilterActionMove();
1332 virtual ReturnCode process(KMMessage* msg) const;
1333 virtual bool requiresBody(KMMsgBase*) const;
1334 static KMFilterAction* newAction(void);
1337 KMFilterAction* KMFilterActionMove::newAction(void)
1339 return (new KMFilterActionMove);
1342 KMFilterActionMove::KMFilterActionMove()
1343 : KMFilterActionWithFolder( "transfer", i18n("Move Into Folder") )
1347 KMFilterAction::ReturnCode KMFilterActionMove::process(KMMessage* msg) const
1349 if ( !mFolder )
1350 return ErrorButGoOn;
1352 ActionScheduler *handler = MessageProperty::filterHandler( msg );
1353 if (handler) {
1354 MessageProperty::setFilterFolder( msg, mFolder );
1355 } else {
1356 // The old filtering system does not support online imap targets.
1357 // Skip online imap targets when using the old system.
1358 KMFolder *check;
1359 check = kmkernel->imapFolderMgr()->findIdString( argsAsString() );
1360 if (mFolder && (check != mFolder)) {
1361 MessageProperty::setFilterFolder( msg, mFolder );
1364 return GoOn;
1367 bool KMFilterActionMove::requiresBody(KMMsgBase*) const
1369 return false; //iff mFolder->folderMgr == msgBase->parent()->folderMgr;
1373 //=============================================================================
1374 // KMFilterActionCopy - copy into folder
1375 // Copy message into another mail folder
1376 //=============================================================================
1377 class KMFilterActionCopy: public KMFilterActionWithFolder
1379 public:
1380 KMFilterActionCopy();
1381 virtual ReturnCode process(KMMessage* msg) const;
1382 virtual void processAsync(KMMessage* msg) const;
1383 virtual bool requiresBody(KMMsgBase*) const;
1384 static KMFilterAction* newAction(void);
1387 KMFilterAction* KMFilterActionCopy::newAction( void )
1389 return ( new KMFilterActionCopy );
1392 KMFilterActionCopy::KMFilterActionCopy()
1393 : KMFilterActionWithFolder( "copy", i18n("Copy Into Folder") )
1397 KMFilterAction::ReturnCode KMFilterActionCopy::process( KMMessage *msg ) const
1399 // TODO opening and closing the folder is a trade off.
1400 // Perhaps Copy is a seldomly used action for now,
1401 // but I gonna look at improvements ASAP.
1402 if ( !mFolder || mFolder->open( "filtercopy" ) != 0 ) {
1403 return ErrorButGoOn;
1406 // copy the message 1:1
1407 KMMessage* msgCopy = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
1409 int index;
1410 int rc = mFolder->addMsg( msgCopy, &index );
1411 if ( rc == 0 && index != -1 ) {
1412 mFolder->unGetMsg( index );
1414 mFolder->close( "filtercopy" );
1416 return GoOn;
1419 void KMFilterActionCopy::processAsync( KMMessage *msg ) const
1421 ActionScheduler *handler = MessageProperty::filterHandler( msg );
1423 KMCommand *cmd = new KMCopyCommand( mFolder, msg );
1424 QObject::connect( cmd, SIGNAL( completed( KMCommand * ) ),
1425 handler, SLOT( copyMessageFinished( KMCommand * ) ) );
1426 cmd->start();
1429 bool KMFilterActionCopy::requiresBody( KMMsgBase *msg ) const
1431 Q_UNUSED( msg );
1432 return true;
1435 //=============================================================================
1436 // KMFilterActionForward - forward to
1437 // Forward message to another user
1438 //=============================================================================
1439 class KMFilterActionForward: public KMFilterActionWithAddress
1441 public:
1442 KMFilterActionForward();
1443 virtual ReturnCode process( KMMessage *msg ) const;
1444 static KMFilterAction* newAction( void );
1447 KMFilterAction *KMFilterActionForward::newAction( void )
1449 return ( new KMFilterActionForward );
1452 KMFilterActionForward::KMFilterActionForward()
1453 : KMFilterActionWithAddress( "forward", i18n("Forward To") )
1457 KMFilterAction::ReturnCode KMFilterActionForward::process( KMMessage *aMsg ) const
1459 if ( mParameter.isEmpty() )
1460 return ErrorButGoOn;
1462 // avoid endless loops when this action is used in a filter
1463 // which applies to sent messages
1464 if ( KMMessage::addressIsInAddressList( mParameter, QStringList( aMsg->to() ) ) )
1465 return ErrorButGoOn;
1467 // Create the forwarded message by hand to make forwarding of messages with
1468 // attachments work.
1469 // Note: This duplicates a lot of code from KMMessage::createForward() and
1470 // KMComposeWin::applyChanges().
1471 // ### FIXME: Remove the code duplication again.
1473 KMMessage* msg = new KMMessage;
1475 msg->initFromMessage( aMsg );
1477 // QString st = QString::fromUtf8( aMsg->createForwardBody() );
1478 TemplateParser parser( msg, TemplateParser::Forward,
1479 aMsg->body(), false, false, false);
1480 parser.process( aMsg );
1482 QByteArray
1483 encoding = KMMsgBase::autoDetectCharset( aMsg->charset(),
1484 KMMessage::preferredCharsets(),
1485 msg->body() );
1486 if( encoding.isEmpty() )
1487 encoding = "utf-8";
1488 QByteArray str = KMMsgBase::codecForName( encoding )->fromUnicode( msg->body() );
1490 msg->setCharset( encoding );
1491 msg->setTo( mParameter );
1492 msg->setSubject( "Fwd: " + aMsg->subject() );
1494 bool isQP = kmkernel->msgSender()->sendQuotedPrintable();
1496 if( aMsg->numBodyParts() == 0 )
1498 msg->setAutomaticFields( true );
1499 msg->setHeaderField( "Content-Type", "text/plain" );
1500 // msg->setCteStr( isQP ? "quoted-printable": "8bit" );
1501 QList<int> dummy;
1502 msg->setBodyAndGuessCte(str, dummy, !isQP);
1503 msg->setCharset( encoding );
1504 if( isQP )
1505 msg->setBodyEncoded( str );
1506 else
1507 msg->setBody( str );
1509 else
1511 KMMessagePart bodyPart, msgPart;
1513 msg->removeHeaderField( "Content-Type" );
1514 msg->removeHeaderField( "Content-Transfer-Encoding" );
1515 msg->setAutomaticFields( true );
1516 msg->setBody( "This message is in MIME format.\n\n" );
1518 bodyPart.setTypeStr( "text" );
1519 bodyPart.setSubtypeStr( "plain" );
1520 // bodyPart.setCteStr( isQP ? "quoted-printable": "8bit" );
1521 QList<int> dummy;
1522 bodyPart.setBodyAndGuessCte(str, dummy, !isQP);
1523 bodyPart.setCharset( encoding );
1524 bodyPart.setBodyEncoded( str );
1525 msg->addBodyPart( &bodyPart );
1527 for( int i = 0; i < aMsg->numBodyParts(); i++ )
1529 aMsg->bodyPart( i, &msgPart );
1530 if( i > 0 || qstricmp( msgPart.typeStr(), "text" ) != 0 )
1531 msg->addBodyPart( &msgPart );
1534 msg->cleanupHeader();
1535 msg->link( aMsg, MessageStatus::statusForwarded() );
1537 sendMDN( aMsg, KMime::MDN::Dispatched );
1539 if ( !kmkernel->msgSender()->send( msg, KMail::MessageSender::SendLater ) ) {
1540 kDebug(5006) <<"KMFilterAction: could not forward message (sending failed)";
1541 return ErrorButGoOn; // error: couldn't send
1543 return GoOn;
1547 //=============================================================================
1548 // KMFilterActionRedirect - redirect to
1549 // Redirect message to another user
1550 //=============================================================================
1551 class KMFilterActionRedirect: public KMFilterActionWithAddress
1553 public:
1554 KMFilterActionRedirect();
1555 virtual ReturnCode process(KMMessage* msg) const;
1556 static KMFilterAction* newAction(void);
1559 KMFilterAction* KMFilterActionRedirect::newAction(void)
1561 return (new KMFilterActionRedirect);
1564 KMFilterActionRedirect::KMFilterActionRedirect()
1565 : KMFilterActionWithAddress( "redirect", i18n("Redirect To") )
1569 KMFilterAction::ReturnCode KMFilterActionRedirect::process(KMMessage* aMsg) const
1571 KMMessage* msg;
1572 if ( mParameter.isEmpty() )
1573 return ErrorButGoOn;
1575 msg = aMsg->createRedirect( mParameter );
1577 sendMDN( aMsg, KMime::MDN::Dispatched );
1579 if ( !kmkernel->msgSender()->send( msg, KMail::MessageSender::SendLater ) ) {
1580 kDebug(5006) <<"KMFilterAction: could not redirect message (sending failed)";
1581 return ErrorButGoOn; // error: couldn't send
1583 return GoOn;
1587 //=============================================================================
1588 // KMFilterActionExec - execute command
1589 // Execute a shell command
1590 //=============================================================================
1591 class KMFilterActionExec : public KMFilterActionWithCommand
1593 public:
1594 KMFilterActionExec();
1595 virtual ReturnCode process(KMMessage* msg) const;
1596 static KMFilterAction* newAction(void);
1599 KMFilterAction* KMFilterActionExec::newAction(void)
1601 return (new KMFilterActionExec());
1604 KMFilterActionExec::KMFilterActionExec()
1605 : KMFilterActionWithCommand( "execute", i18n("Execute Command") )
1609 KMFilterAction::ReturnCode KMFilterActionExec::process(KMMessage *aMsg) const
1611 return KMFilterActionWithCommand::genericProcess( aMsg, false ); // ignore output
1614 //=============================================================================
1615 // KMFilterActionExtFilter - use external filter app
1616 // External message filter: executes a shell command with message
1617 // on stdin; altered message is expected on stdout.
1618 //=============================================================================
1620 #include <threadweaver/ThreadWeaver.h>
1621 #include <threadweaver/Job.h>
1622 #include <threadweaver/DebuggingAids.h>
1623 class PipeJob : public ThreadWeaver::Job
1625 public:
1626 PipeJob(QObject* parent = 0 , KMMessage* aMsg = 0, QString cmd = 0, QString tempFileName = 0 )
1627 : ThreadWeaver::Job ( parent ),
1628 mTempFileName( tempFileName ),
1629 mCmd( cmd ),
1630 mMsg( aMsg )
1634 ~PipeJob() {}
1636 virtual void done( ThreadWeaver::Job *job )
1638 ThreadWeaver::Job::done( job );
1639 deleteLater( );
1642 protected:
1643 void run()
1645 ThreadWeaver::debug (1, "PipeJob::run: doing it .\n");
1646 FILE *p;
1647 QByteArray ba;
1649 // backup the serial number in case the header gets lost
1650 QString origSerNum = mMsg->headerField( "X-KMail-Filtered" );
1652 p = popen(QFile::encodeName(mCmd), "r");
1653 int len =100;
1654 char buffer[100];
1655 // append data to ba:
1656 while (true) {
1657 if (! fgets( buffer, len, p ) ) break;
1658 int oldsize = ba.size();
1659 ba.resize( oldsize + strlen(buffer) );
1660 qmemmove( ba.begin() + oldsize, buffer, strlen(buffer) );
1662 pclose(p);
1663 if ( !ba.isEmpty() ) {
1664 ThreadWeaver::debug (1, "PipeJob::run: %s", ba.constData() );
1665 KMFolder *filterFolder = mMsg->parent();
1666 ActionScheduler *handler = MessageProperty::filterHandler( mMsg->getMsgSerNum() );
1668 mMsg->fromString( ba );
1669 if ( !origSerNum.isEmpty() )
1670 mMsg->setHeaderField( "X-KMail-Filtered", origSerNum );
1671 if ( filterFolder && handler ) {
1672 bool oldStatus = handler->ignoreChanges( true );
1673 filterFolder->take( filterFolder->find( mMsg ) );
1674 filterFolder->addMsg( mMsg );
1675 handler->ignoreChanges( oldStatus );
1676 } else {
1677 kDebug(5006) <<"Warning: Cannot refresh the message from the external filter.";
1681 ThreadWeaver::debug (1, "PipeJob::run: done.\n" );
1682 // unlink the tempFile
1683 QFile::remove(mTempFileName);
1686 QString mTempFileName;
1687 QString mCmd;
1688 KMMessage *mMsg;
1691 class KMFilterActionExtFilter: public KMFilterActionWithCommand
1693 public:
1694 KMFilterActionExtFilter();
1695 virtual ReturnCode process(KMMessage* msg) const;
1696 virtual void processAsync(KMMessage* msg) const;
1697 static KMFilterAction* newAction(void);
1700 KMFilterAction* KMFilterActionExtFilter::newAction(void)
1702 return (new KMFilterActionExtFilter);
1705 KMFilterActionExtFilter::KMFilterActionExtFilter()
1706 : KMFilterActionWithCommand( "filter app", i18n("Pipe Through") )
1709 KMFilterAction::ReturnCode KMFilterActionExtFilter::process(KMMessage* aMsg) const
1711 return KMFilterActionWithCommand::genericProcess( aMsg, true ); // use output
1714 void KMFilterActionExtFilter::processAsync(KMMessage* aMsg) const
1717 ActionScheduler *handler = MessageProperty::filterHandler( aMsg->getMsgSerNum() );
1718 KTemporaryFile *inFile = new KTemporaryFile;
1719 inFile->setAutoRemove(false);
1720 inFile->open();
1722 QList<KTemporaryFile*> atmList;
1723 atmList.append( inFile );
1725 QString commandLine = substituteCommandLineArgsFor( aMsg , atmList );
1726 qDeleteAll( atmList );
1727 atmList.clear();
1728 if ( commandLine.isEmpty() )
1729 handler->actionMessage( ErrorButGoOn );
1731 // The parentheses force the creation of a subshell
1732 // in which the user-specified command is executed.
1733 // This is to really catch all output of the command as well
1734 // as to avoid clashes of our redirection with the ones
1735 // the user may have specified. In the long run, we
1736 // shouldn't be using tempfiles at all for this class, due
1737 // to security aspects. (mmutz)
1738 commandLine = '(' + commandLine + ") <" + inFile->fileName();
1740 // write message to file
1741 QString tempFileName = inFile->fileName();
1742 KPIMUtils::kByteArrayToFile( aMsg->asString(), tempFileName, //###
1743 false, false, false );
1744 inFile->close();
1746 PipeJob *job = new PipeJob(0, aMsg, commandLine, tempFileName);
1747 QObject::connect ( job, SIGNAL( done() ), handler, SLOT( actionMessage() ) );
1748 kmkernel->weaver()->enqueue(job);
1751 //=============================================================================
1752 // KMFilterActionExecSound - execute command
1753 // Execute a sound
1754 //=============================================================================
1755 class KMFilterActionExecSound : public KMFilterActionWithTest
1757 public:
1758 KMFilterActionExecSound();
1759 ~KMFilterActionExecSound();
1760 virtual ReturnCode process(KMMessage* msg) const;
1761 virtual bool requiresBody(KMMsgBase*) const;
1762 static KMFilterAction* newAction(void);
1763 private:
1764 Phonon::MediaObject* mPlayer;
1767 KMFilterActionWithTest::KMFilterActionWithTest( const char* aName, const QString &aLabel )
1768 : KMFilterAction( aName, aLabel )
1772 KMFilterActionWithTest::~KMFilterActionWithTest()
1776 QWidget* KMFilterActionWithTest::createParamWidget( QWidget* parent ) const
1778 KMSoundTestWidget *le = new KMSoundTestWidget(parent);
1779 le->setUrl( mParameter );
1780 return le;
1784 void KMFilterActionWithTest::applyParamWidgetValue( QWidget* paramWidget )
1786 mParameter = ((KMSoundTestWidget*)paramWidget)->url();
1789 void KMFilterActionWithTest::setParamWidgetValue( QWidget* paramWidget ) const
1791 ((KMSoundTestWidget*)paramWidget)->setUrl( mParameter );
1794 void KMFilterActionWithTest::clearParamWidget( QWidget* paramWidget ) const
1796 ((KMSoundTestWidget*)paramWidget)->clear();
1799 void KMFilterActionWithTest::argsFromString( const QString &argsStr )
1801 mParameter = argsStr;
1804 const QString KMFilterActionWithTest::argsAsString() const
1806 return mParameter;
1809 const QString KMFilterActionWithTest::displayString() const
1811 // FIXME after string freeze:
1812 // return i18n("").arg( );
1813 return label() + " \"" + Qt::escape( argsAsString() ) + "\"";
1817 KMFilterActionExecSound::KMFilterActionExecSound()
1818 : KMFilterActionWithTest( "play sound", i18n("Play Sound") )
1820 mPlayer = Phonon::createPlayer(Phonon::NotificationCategory);
1823 KMFilterActionExecSound::~KMFilterActionExecSound()
1825 delete mPlayer;
1828 KMFilterAction* KMFilterActionExecSound::newAction(void)
1830 return (new KMFilterActionExecSound());
1833 KMFilterAction::ReturnCode KMFilterActionExecSound::process(KMMessage*) const
1835 if ( mParameter.isEmpty() )
1836 return ErrorButGoOn;
1837 mPlayer->setCurrentSource( mParameter );
1838 mPlayer->play();
1839 return GoOn;
1842 bool KMFilterActionExecSound::requiresBody(KMMsgBase*) const
1844 return false;
1847 KMFilterActionWithUrl::KMFilterActionWithUrl( const char* aName, const QString &aLabel )
1848 : KMFilterAction( aName, aLabel )
1852 KMFilterActionWithUrl::~KMFilterActionWithUrl()
1856 QWidget* KMFilterActionWithUrl::createParamWidget( QWidget* parent ) const
1858 KUrlRequester *le = new KUrlRequester(parent);
1859 le->setPath( mParameter );
1860 return le;
1864 void KMFilterActionWithUrl::applyParamWidgetValue( QWidget* paramWidget )
1866 mParameter = ((KUrlRequester*)paramWidget)->url().path();
1869 void KMFilterActionWithUrl::setParamWidgetValue( QWidget* paramWidget ) const
1871 ((KUrlRequester*)paramWidget)->setPath( mParameter );
1874 void KMFilterActionWithUrl::clearParamWidget( QWidget* paramWidget ) const
1876 ((KUrlRequester*)paramWidget)->clear();
1879 void KMFilterActionWithUrl::argsFromString( const QString &argsStr )
1881 mParameter = argsStr;
1884 const QString KMFilterActionWithUrl::argsAsString() const
1886 return mParameter;
1889 const QString KMFilterActionWithUrl::displayString() const
1891 // FIXME after string freeze:
1892 // return i18n("").arg( );
1893 return label() + " \"" + Qt::escape( argsAsString() ) + "\"";
1897 //=============================================================================
1899 // Filter Action Dictionary
1901 //=============================================================================
1902 KMFilterActionDict::~KMFilterActionDict()
1904 qDeleteAll( mList );
1907 void KMFilterActionDict::init(void)
1909 insert( KMFilterActionMove::newAction );
1910 insert( KMFilterActionCopy::newAction );
1911 insert( KMFilterActionIdentity::newAction );
1912 insert( KMFilterActionSetStatus::newAction );
1913 insert( KMFilterActionFakeDisposition::newAction );
1914 insert( KMFilterActionTransport::newAction );
1915 insert( KMFilterActionReplyTo::newAction );
1916 insert( KMFilterActionForward::newAction );
1917 insert( KMFilterActionRedirect::newAction );
1918 insert( KMFilterActionSendReceipt::newAction );
1919 insert( KMFilterActionExec::newAction );
1920 insert( KMFilterActionExtFilter::newAction );
1921 insert( KMFilterActionRemoveHeader::newAction );
1922 insert( KMFilterActionAddHeader::newAction );
1923 insert( KMFilterActionRewriteHeader::newAction );
1924 insert( KMFilterActionExecSound::newAction );
1925 // Register custom filter actions below this line.
1927 // The int in the QDict constructor (41) must be a prime
1928 // and should be greater than the double number of KMFilterAction types
1929 KMFilterActionDict::KMFilterActionDict()
1930 : QMultiHash<QString, KMFilterActionDesc*>()
1932 init();
1935 void KMFilterActionDict::insert( KMFilterActionNewFunc aNewFunc )
1937 KMFilterAction *action = aNewFunc();
1938 KMFilterActionDesc* desc = new KMFilterActionDesc;
1939 desc->name = action->name();
1940 desc->label = action->label();
1941 desc->create = aNewFunc;
1942 QMultiHash<QString, KMFilterActionDesc*>::insert( desc->name, desc );
1943 QMultiHash<QString, KMFilterActionDesc*>::insert( desc->label, desc );
1944 mList.append( desc );
1945 delete action;