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

mailcommon

  • sources
  • kde-4.12
  • kdepim
  • mailcommon
  • filter
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.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->parse();
245 
246  KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-UID", aMsg.get(), uid, "utf-8" );
247  aMsg->setHeader( header );
248 
249  context.setNeedsPayloadStore();
250  } else {
251  qDeleteAll( atmList );
252  atmList.clear();
253  return ErrorButGoOn;
254  }
255  }
256 
257  qDeleteAll( atmList );
258  atmList.clear();
259 
260  return GoOn;
261 }
262 
263 #include "filteractionwithcommand.moc"
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:60
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:53
MailCommon::FilterActionWithUrl::clearParamWidget
virtual void clearParamWidget(QWidget *paramWidget) const
The filter action shall clear it's parameter widget's contents.
Definition: filteractionwithurl.cpp:65
QWidget
MailCommon::ItemContext::setNeedsPayloadStore
void setNeedsPayloadStore()
Marks that the item's payload has been changed and needs to be written back.
Definition: itemcontext.cpp:45
MailCommon::FilterActionWithUrl::mParameter
QString mParameter
Definition: filteractionwithurl.h:102
MailCommon::FilterActionWithCommand::createParamWidget
virtual QWidget * createParamWidget(QWidget *parent) const
Creates a widget for setting the filter action parameter.
Definition: filteractionwithcommand.cpp:35
QObject
filteractionwithcommand.h
MailCommon::FilterAction::ErrorButGoOn
A non-critical error occurred.
Definition: filteraction.h:63
MailCommon::FilterActionWithUrl
Abstract base class for filter actions with a command line as parameter.
Definition: filteractionwithurl.h:47
MailCommon::FilterActionWithUrl::createParamWidget
virtual QWidget * createParamWidget(QWidget *parent) const
Creates a widget for setting the filter action parameter.
Definition: filteractionwithurl.cpp:42
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
MailCommon::FilterAction::ReturnCode
ReturnCode
Describes the possible return codes of filter processing:
Definition: filteraction.h:60
MailCommon::ItemContext::item
Akonadi::Item & item()
Returns the item of the context.
Definition: itemcontext.cpp:30
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
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
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
MailCommon::FilterAction::CriticalError
(e.g.
Definition: filteraction.h:66
findMimeNodeForIndex
static KMime::Content * findMimeNodeForIndex(KMime::Content *node, int &index)
Definition: filteractionwithcommand.cpp:55
QList
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:55:14 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

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