• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

mailcommon

  • sources
  • kde-4.14
  • kdepim
  • mailcommon
  • filter
  • filteractions
filteractionwithcommand.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  */
19 
20 #include "filteractionwithcommand.h"
21 
22 #include <KDE/KPIMUtils/KFileIO>
23 #include <KDE/KProcess>
24 #include <KDE/KShell>
25 #include <KDE/KTemporaryFile>
26 #include <KDE/KUrl>
27 
28 using namespace MailCommon;
29 
30 FilterActionWithCommand::FilterActionWithCommand( const QString &name, const QString &label, QObject *parent )
31  : FilterActionWithUrl( name, label, parent )
32 {
33 }
34 
35 QWidget* FilterActionWithCommand::createParamWidget( QWidget *parent ) const
36 {
37  return FilterActionWithUrl::createParamWidget( parent );
38 }
39 
40 void FilterActionWithCommand::applyParamWidgetValue( QWidget *paramWidget )
41 {
42  FilterActionWithUrl::applyParamWidgetValue( paramWidget );
43 }
44 
45 void FilterActionWithCommand::setParamWidgetValue( QWidget *paramWidget ) const
46 {
47  FilterActionWithUrl::setParamWidgetValue( paramWidget );
48 }
49 
50 void FilterActionWithCommand::clearParamWidget( QWidget *paramWidget ) const
51 {
52  FilterActionWithUrl::clearParamWidget( paramWidget );
53 }
54 
55 static KMime::Content* findMimeNodeForIndex( KMime::Content* node, int &index )
56 {
57  if ( index <= 0 )
58  return node;
59 
60  foreach ( KMime::Content* child, node->contents() ) {
61  KMime::Content *result = findMimeNodeForIndex( child, --index );
62  if ( result )
63  return result;
64  }
65 
66  return 0;
67 }
68 
69 QString FilterActionWithCommand::substituteCommandLineArgsFor( const KMime::Message::Ptr &aMsg, QList<KTemporaryFile*> &aTempFileList ) const
70 {
71  QString result = mParameter;
72  QList<int> argList;
73  QRegExp r( QLatin1String("%[0-9-]+") );
74 
75  // search for '%n'
76  int start = -1;
77  while ( ( start = r.indexIn( result, start + 1 ) ) > 0 ) {
78  const int len = r.matchedLength();
79 
80  // and save the encountered 'n' in a list.
81  bool ok = false;
82  const int n = result.mid( start + 1, len - 1 ).toInt( &ok );
83  if ( ok )
84  argList.append( n );
85  }
86 
87  // sort the list of n's
88  qSort( argList );
89 
90  // and use QString::arg to substitute filenames for the %n's.
91  int lastSeen = -2;
92  QString tempFileName;
93  QList<int>::ConstIterator end( argList.constEnd() );
94  for ( QList<int>::ConstIterator it = argList.constBegin() ; it != end ; ++it ) {
95  // setup temp files with check for duplicate %n's
96  if ( (*it) != lastSeen ) {
97  KTemporaryFile *tempFile = new KTemporaryFile();
98  if ( !tempFile->open() ) {
99  delete tempFile;
100  kDebug() << "FilterActionWithCommand: Could not create temp file!";
101  return QString();
102  }
103 
104  aTempFileList.append( tempFile );
105  tempFileName = tempFile->fileName();
106 
107  if ( (*it) == -1 )
108  KPIMUtils::kByteArrayToFile( aMsg->encodedContent(), tempFileName, //###
109  false, false, false );
110  else if (aMsg->contents().size() == 0)
111  KPIMUtils::kByteArrayToFile( aMsg->decodedContent(), tempFileName,
112  false, false, false );
113  else {
114  int index = *it; // we pass by reference below, so this is not const
115  KMime::Content *content = findMimeNodeForIndex( aMsg.get(), index );
116  if ( content ) {
117  KPIMUtils::kByteArrayToFile( content->decodedContent(), tempFileName,
118  false, false, false );
119  }
120  }
121  tempFile->close();
122  }
123 
124  // QString( "%0 and %1 and %1" ).arg( 0 ).arg( 1 )
125  // returns "0 and 1 and %1", so we must call .arg as
126  // many times as there are %n's, regardless of their multiplicity.
127  if ( (*it) == -1 )
128  result.replace( QLatin1String("%-1"), tempFileName );
129  else
130  result = result.arg( tempFileName );
131  }
132 
133  return result;
134 }
135 
136 
137 namespace {
138 
144 void substituteMessageHeaders( const KMime::Message::Ptr &aMsg, QString &result )
145 {
146  // Replace the %{foo} with the content of the foo header field.
147  // If the header doesn't exist, remove the placeholder.
148  QRegExp header_rx( QLatin1String("%\\{([a-z0-9-]+)\\}"), Qt::CaseInsensitive );
149  int idx = 0;
150  while ( ( idx = header_rx.indexIn( result, idx ) ) != -1 ) {
151  const KMime::Headers::Base* header = aMsg->headerByType( header_rx.cap(1).toLatin1() );
152  QString replacement;
153  if ( header )
154  replacement = KShell::quoteArg( QString::fromLatin1(header->as7BitString()) );
155  result.replace( idx, header_rx.matchedLength(), replacement );
156  idx += replacement.length();
157  }
158 }
159 
165 void substituteCommandLineArgsForItem( const Akonadi::Item &item, QString &commandLine )
166 {
167  commandLine.replace( QLatin1String( "%{itemurl}" ), item.url( Akonadi::Item::UrlWithMimeType ).url() );
168  commandLine.replace( QLatin1String( "%{itemid}" ), QString::number( item.id() ) );
169 }
170 
171 }
172 
173 FilterAction::ReturnCode FilterActionWithCommand::genericProcess( ItemContext &context, bool withOutput ) const
174 {
175  const KMime::Message::Ptr aMsg = context.item().payload<KMime::Message::Ptr>();
176  Q_ASSERT( aMsg );
177 
178  if ( mParameter.isEmpty() )
179  return ErrorButGoOn;
180 
181  // KProcess doesn't support a QProcess::launch() equivalent, so
182  // we must use a temp file :-(
183  KTemporaryFile * inFile = new KTemporaryFile;
184  if ( !inFile->open() ) {
185  delete inFile;
186  return ErrorButGoOn;
187  }
188 
189  QList<KTemporaryFile*> atmList;
190  atmList.append( inFile );
191 
192  QString commandLine = substituteCommandLineArgsFor( aMsg, atmList );
193  substituteCommandLineArgsForItem( context.item(), commandLine );
194  substituteMessageHeaders( aMsg, commandLine );
195 
196  if ( commandLine.isEmpty() ) {
197  qDeleteAll( atmList );
198  atmList.clear();
199  return ErrorButGoOn;
200  }
201  // The parentheses force the creation of a subshell
202  // in which the user-specified command is executed.
203  // This is to really catch all output of the command as well
204  // as to avoid clashes of our redirection with the ones
205  // the user may have specified. In the long run, we
206  // shouldn't be using tempfiles at all for this class, due
207  // to security aspects. (mmutz)
208  commandLine = QLatin1Char( '(' ) + commandLine + QLatin1String( ") <" ) + inFile->fileName();
209 
210  // write message to file
211  QString tempFileName = inFile->fileName();
212  if ( !KPIMUtils::kByteArrayToFile( aMsg->encodedContent(), tempFileName, //###
213  false, false, false ) ) {
214  qDeleteAll( atmList );
215  atmList.clear();
216  return CriticalError;
217  }
218 
219  inFile->close();
220 
221  KProcess shProc;
222  shProc.setOutputChannelMode( KProcess::SeparateChannels );
223  shProc.setShellCommand( commandLine );
224  int result = shProc.execute();
225 
226  if ( result != 0 ) {
227  qDeleteAll( atmList );
228  atmList.clear();
229  return ErrorButGoOn;
230  }
231 
232  if ( withOutput ) {
233  // read altered message:
234  const QByteArray msgText = shProc.readAllStandardOutput();
235 
236  if ( !msgText.trimmed().isEmpty() ) {
237  /* If the pipe through alters the message, it could very well
238  happen that it no longer has a X-UID header afterwards. That is
239  unfortunate, as we need to removed the original from the folder
240  using that, and look it up in the message. When the (new) message
241  is uploaded, the header is stripped anyhow. */
242  const QString uid = aMsg->headerByType( "X-UID" ) ? aMsg->headerByType( "X-UID" )->asUnicodeString() : QString();
243  aMsg->setContent( KMime::CRLFtoLF( msgText ) );
244  aMsg->setFrozen(true);
245  aMsg->parse();
246 
247  const QString newUid = aMsg->headerByType( "X-UID" ) ? aMsg->headerByType( "X-UID" )->asUnicodeString() : QString();
248  if (uid != newUid) {
249  aMsg->setFrozen(false);
250  KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-UID", aMsg.get(), uid, "utf-8" );
251  aMsg->setHeader( header );
252  aMsg->assemble();
253  }
254 
255  context.setNeedsPayloadStore();
256  } else {
257  qDeleteAll( atmList );
258  atmList.clear();
259  return ErrorButGoOn;
260  }
261  }
262 
263  qDeleteAll( atmList );
264  atmList.clear();
265 
266  return GoOn;
267 }
268 
MailCommon::FilterActionWithUrl::setParamWidgetValue
virtual void setParamWidgetValue(QWidget *paramWidget) const
The filter action shall set it's widget's contents from it's parameter.
Definition: filteractionwithurl.cpp:98
QList::clear
void clear()
QWidget
MailCommon::FilterAction::GoOn
Go on with applying filter actions.
Definition: filteraction.h:62
MailCommon::FilterActionWithUrl::applyParamWidgetValue
virtual void applyParamWidgetValue(QWidget *paramWidget)
The filter action shall set it's parameter from the widget's contents.
Definition: filteractionwithurl.cpp:85
QByteArray::trimmed
QByteArray trimmed() const
QByteArray
MailCommon::FilterActionWithUrl::clearParamWidget
virtual void clearParamWidget(QWidget *paramWidget) const
The filter action shall clear it's parameter widget's contents.
Definition: filteractionwithurl.cpp:105
MailCommon::ItemContext::setNeedsPayloadStore
void setNeedsPayloadStore()
Marks that the item's payload has been changed and needs to be written back.
Definition: itemcontext.cpp:44
MailCommon::FilterActionWithUrl::mParameter
QString mParameter
Definition: filteractionwithurl.h:111
QByteArray::isEmpty
bool isEmpty() const
MailCommon::FilterActionWithCommand::createParamWidget
virtual QWidget * createParamWidget(QWidget *parent) const
Creates a widget for setting the filter action parameter.
Definition: filteractionwithcommand.cpp:35
QRegExp::matchedLength
int matchedLength() const
QRegExp::indexIn
int indexIn(const QString &str, int offset, CaretMode caretMode) const
QRegExp
QString::number
QString number(int n, int base)
filteractionwithcommand.h
QList::append
void append(const T &value)
MailCommon::FilterAction::ErrorButGoOn
A non-critical error occurred.
Definition: filteraction.h:63
MailCommon::FilterActionWithUrl
Definition: filteractionwithurl.h:56
QObject
MailCommon::FilterActionWithUrl::createParamWidget
virtual QWidget * createParamWidget(QWidget *parent) const
Creates a widget for setting the filter action parameter.
Definition: filteractionwithurl.cpp:57
QString::toInt
int toInt(bool *ok, int base) const
QString::isEmpty
bool isEmpty() const
MailCommon::FilterActionWithCommand::setParamWidgetValue
virtual void setParamWidgetValue(QWidget *paramWidget) const
The filter action shall set it's widget's contents from it's parameter.
Definition: filteractionwithcommand.cpp:45
MailCommon::FilterActionWithCommand::substituteCommandLineArgsFor
virtual QString substituteCommandLineArgsFor(const KMime::Message::Ptr &aMsg, QList< KTemporaryFile * > &aTempFileList) const
Substitutes various placeholders for data from the message resp.
Definition: filteractionwithcommand.cpp:69
QString
QList
QLatin1Char
QString::replace
QString & replace(int position, int n, QChar after)
MailCommon::FilterAction::ReturnCode
ReturnCode
Describes the possible return codes of filter processing:
Definition: filteraction.h:60
QString::mid
QString mid(int position, int n) const
QLatin1String
MailCommon::ItemContext::item
Akonadi::Item & item()
Returns the item of the context.
Definition: itemcontext.cpp:29
MailCommon::FilterActionWithCommand::FilterActionWithCommand
FilterActionWithCommand(const QString &name, const QString &label, QObject *parent=0)
Creates a new filter action.
Definition: filteractionwithcommand.cpp:30
MailCommon::FilterActionWithCommand::clearParamWidget
virtual void clearParamWidget(QWidget *paramWidget) const
The filter action shall clear it's parameter widget's contents.
Definition: filteractionwithcommand.cpp:50
context
const char * context
Definition: searchpatternedit.cpp:54
QString::length
int length() const
MailCommon::FilterActionWithCommand::applyParamWidgetValue
virtual void applyParamWidgetValue(QWidget *paramWidget)
The filter action shall set it's parameter from the widget's contents.
Definition: filteractionwithcommand.cpp:40
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QList::constEnd
const_iterator constEnd() const
QList::constBegin
const_iterator constBegin() const
MailCommon::ItemContext
A helper class for the filtering process.
Definition: itemcontext.h:39
MailCommon::FilterActionWithCommand::genericProcess
virtual ReturnCode genericProcess(ItemContext &context, bool filtering) const
Definition: filteractionwithcommand.cpp:173
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
MailCommon::FilterAction::CriticalError
(e.g.
Definition: filteraction.h:66
findMimeNodeForIndex
static KMime::Content * findMimeNodeForIndex(KMime::Content *node, int &index)
Definition: filteractionwithcommand.cpp:55
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:31:40 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

mailcommon

Skip menu "mailcommon"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal