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

messageviewer

  • sources
  • kde-4.12
  • kdepim
  • messageviewer
  • header
headerstyle_util.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2013 Montel Laurent <montel@kde.org>
3 
4  This program is free software; you can redistribute it and/or modify it
5  under the terms of the GNU General Public License, version 2, as
6  published by the Free Software Foundation.
7 
8  This program is distributed in the hope that it will be useful, but
9  WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License along
14  with this program; if not, write to the Free Software Foundation, Inc.,
15  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include "headerstyle_util.h"
19 #include "viewer/nodehelper.h"
20 #include "header/headerstyle.h"
21 
22 #include <messagecore/utils/stringutil.h>
23 
24 #include "messagecore/settings/globalsettings.h"
25 #include "settings/globalsettings.h"
26 
27 
28 
29 #include <KLocale>
30 #include <KGlobal>
31 
32 #include <QBuffer>
33 #include "contactdisplaymessagememento.h"
34 #include "kxface.h"
35 
36 #include <kpimutils/email.h>
37 
38 using namespace MessageCore;
39 
40 namespace MessageViewer {
41 namespace HeaderStyleUtil {
42 //
43 // Convenience functions:
44 //
45 QString directionOf( const QString &str ) {
46  return str.isRightToLeft() ? QLatin1String("rtl") : QLatin1String("ltr");
47 }
48 
49 QString strToHtml( const QString &str, int flags ) {
50  return LinkLocator::convertToHtml( str, flags );
51 }
52 
53 // Prepare the date string (when printing always use the localized date)
54 QString dateString( KMime::Message *message, bool printing, bool shortDate ) {
55  const KDateTime dateTime = message->date()->dateTime();
56  if ( !dateTime.isValid() )
57  return i18nc( "Unknown date", "Unknown" );
58  if( printing ) {
59  KLocale * locale = KGlobal::locale();
60  return locale->formatDateTime( dateTime );
61  } else {
62  if ( shortDate )
63  return dateShortStr( dateTime );
64  else
65  return dateStr( dateTime );
66  }
67 }
68 
69 QString subjectString( KMime::Message *message, int flags )
70 {
71  QString subject;
72  if ( message->subject(false) ) {
73  subject = message->subject()->asUnicodeString();
74  if ( subject.isEmpty() )
75  subject = i18n("No Subject");
76  else
77  subject = strToHtml( subject, flags );
78  } else {
79  subject = i18n("No Subject");
80  }
81  return subject;
82 }
83 
84 QString subjectDirectionString( KMime::Message *message )
85 {
86  QString subjectDir;
87  if ( message->subject(false) )
88  subjectDir = directionOf( NodeHelper::cleanSubject( message ) );
89  else
90  subjectDir = directionOf( i18n("No Subject") );
91  return subjectDir;
92 }
93 
94 QString spamStatus(KMime::Message *message)
95 {
96  QString spamHTML;
97  if ( GlobalSettings::self()->showSpamStatus() ) {
98  const SpamScores scores = SpamHeaderAnalyzer::getSpamScores( message );
99 
100  for ( SpamScores::const_iterator it = scores.constBegin(), end = scores.constEnd() ; it != end ; ++it )
101  spamHTML += (*it).agent() + QLatin1Char(' ') +
102  MessageViewer::HeaderStyleUtil::drawSpamMeter( (*it).error(), (*it).score(), (*it).confidence(), (*it).spamHeader(), (*it).confidenceHeader() );
103  }
104  return spamHTML;
105 }
106 
107 
108 QString drawSpamMeter( SpamError spamError, double percent, double confidence,
109  const QString &filterHeader, const QString &confidenceHeader )
110 {
111  static const int meterWidth = 20;
112  static const int meterHeight = 5;
113  QImage meterBar( meterWidth, 1, QImage::Format_Indexed8/*QImage::Format_RGB32*/ );
114  meterBar.setNumColors( 24 );
115 
116  meterBar.setColor( meterWidth + 1, qRgb( 255, 255, 255 ) );
117  meterBar.setColor( meterWidth + 2, qRgb( 170, 170, 170 ) );
118  if ( spamError != noError ) // grey is for errors
119  meterBar.fill( meterWidth + 2 );
120  else {
121  static const unsigned short gradient[meterWidth][3] = {
122  { 0, 255, 0 },
123  { 27, 254, 0 },
124  { 54, 252, 0 },
125  { 80, 250, 0 },
126  { 107, 249, 0 },
127  { 135, 247, 0 },
128  { 161, 246, 0 },
129  { 187, 244, 0 },
130  { 214, 242, 0 },
131  { 241, 241, 0 },
132  { 255, 228, 0 },
133  { 255, 202, 0 },
134  { 255, 177, 0 },
135  { 255, 151, 0 },
136  { 255, 126, 0 },
137  { 255, 101, 0 },
138  { 255, 76, 0 },
139  { 255, 51, 0 },
140  { 255, 25, 0 },
141  { 255, 0, 0 }
142  };
143 
144  meterBar.fill( meterWidth + 1 );
145  const int max = qMin( meterWidth, static_cast<int>( percent ) / 5 );
146  for ( int i = 0; i < max; ++i ) {
147  meterBar.setColor( i+1, qRgb( gradient[i][0], gradient[i][1],
148  gradient[i][2] ) );
149  meterBar.setPixel( i, 0, i+1 );
150  }
151  }
152 
153  QString titleText;
154  QString confidenceString;
155  if ( spamError == noError ) {
156  if ( confidence >= 0 ) {
157  confidenceString = QString::number( confidence ) + QLatin1String("% &nbsp;");
158  titleText = i18n("%1% probability of being spam with confidence %3%.\n\n"
159  "Full report:\nProbability=%2\nConfidence=%4",
160  QString::number(percent,'f',2), filterHeader, confidence, confidenceHeader );
161  } else { // do not show negative confidence
162  confidenceString = QString() + QLatin1String("&nbsp;");
163  titleText = i18n("%1% probability of being spam.\n\n"
164  "Full report:\nProbability=%2",
165  QString::number(percent,'f',2), filterHeader);
166  }
167  } else {
168  QString errorMsg;
169  switch ( spamError )
170  {
171  case errorExtractingAgentString:
172  errorMsg = i18n( "No Spam agent" );
173  break;
174  case couldNotConverScoreToFloat:
175  errorMsg = i18n( "Spam filter score not a number" );
176  break;
177  case couldNotConvertThresholdToFloatOrThresholdIsNegative:
178  errorMsg = i18n( "Threshold not a valid number" );
179  break;
180  case couldNotFindTheScoreField:
181  errorMsg = i18n( "Spam filter score could not be extracted from header" );
182  break;
183  case couldNotFindTheThresholdField:
184  errorMsg = i18n( "Threshold could not be extracted from header" );
185  break;
186  default:
187  errorMsg = i18n( "Error evaluating spam score" );
188  break;
189  }
190  // report the error in the spam filter
191  titleText = i18n("%1.\n\n"
192  "Full report:\n%2",
193  errorMsg, filterHeader );
194  }
195  return QString::fromLatin1("<img src=\"%1\" width=\"%2\" height=\"%3\" style=\"border: 1px solid black;\" title=\"%4\"> &nbsp;")
196  .arg( imgToDataUrl( meterBar ), QString::number( meterWidth ),
197  QString::number( meterHeight ), titleText ) + confidenceString;
198 }
199 
200 QString imgToDataUrl( const QImage &image )
201 {
202  QByteArray ba;
203  QBuffer buffer( &ba );
204  buffer.open( QIODevice::WriteOnly );
205  image.save( &buffer, "PNG" );
206  return QString::fromLatin1("data:image/%1;base64,%2").arg( QString::fromLatin1( "PNG" ), QString::fromLatin1( ba.toBase64() ) );
207 }
208 
209 QString dateStr(const KDateTime &dateTime)
210 {
211  const time_t unixTime = dateTime.toTime_t();
212  return KMime::DateFormatter::formatDate(
213  static_cast<KMime::DateFormatter::FormatType>(
214  MessageCore::GlobalSettings::self()->dateFormat() ),
215  unixTime, MessageCore::GlobalSettings::self()->customDateFormat() );
216 }
217 
218 QString dateShortStr(const KDateTime &dateTime)
219 {
220  return KGlobal::locale()->formatDateTime( dateTime, KLocale::FancyShortDate );
221 }
222 
223 
224 QList<KMime::Types::Mailbox> resentFromList(KMime::Message *message)
225 {
226  // Get the resent-from header into a Mailbox
227  QList<KMime::Types::Mailbox> resentFrom;
228  if ( message->headerByType( "Resent-From" ) ) {
229  const QByteArray data = message->headerByType( "Resent-From" )->as7BitString( false );
230  const char * start = data.data();
231  const char * end = start + data.length();
232  KMime::Types::AddressList addressList;
233  KMime::HeaderParsing::parseAddressList( start, end, addressList );
234  foreach ( const KMime::Types::Address &addr, addressList ) {
235  foreach ( const KMime::Types::Mailbox &mbox, addr.mailboxList ) {
236  resentFrom.append( mbox );
237  }
238  }
239  }
240  return resentFrom;
241 }
242 
243 QList<KMime::Types::Mailbox> resentToList(KMime::Message *message)
244 {
245  // Get the resent-from header into a Mailbox
246  QList<KMime::Types::Mailbox> resentTo;
247  if ( message->headerByType( "Resent-To" ) ) {
248  const QByteArray data = message->headerByType( "Resent-To" )->as7BitString( false );
249  const char * start = data.data();
250  const char * end = start + data.length();
251  KMime::Types::AddressList addressList;
252  KMime::HeaderParsing::parseAddressList( start, end, addressList );
253  foreach ( const KMime::Types::Address &addr, addressList ) {
254  foreach ( const KMime::Types::Mailbox &mbox, addr.mailboxList ) {
255  resentTo.append( mbox );
256  }
257  }
258  }
259  return resentTo;
260 }
261 
262 xfaceSettings xface(const MessageViewer::HeaderStyle *style, KMime::Message *message)
263 {
264 
265  xfaceSettings settings;
266  bool useOtherPhotoSources = false;
267 
268  if ( style->allowAsync() ) {
269 
270  Q_ASSERT( style->nodeHelper() );
271  Q_ASSERT( style->sourceObject() );
272 
273  ContactDisplayMessageMemento *photoMemento =
274  dynamic_cast<ContactDisplayMessageMemento*>( style->nodeHelper()->bodyPartMemento( message, "contactphoto" ) );
275  if ( !photoMemento ) {
276  const QString email = QString::fromLatin1(KPIMUtils::firstEmailAddress( message->from()->as7BitString(false) ));
277  photoMemento = new ContactDisplayMessageMemento( email );
278  style->nodeHelper()->setBodyPartMemento( message, "contactphoto", photoMemento );
279  QObject::connect( photoMemento, SIGNAL(update(MessageViewer::Viewer::UpdateMode)),
280  style->sourceObject(), SLOT(update(MessageViewer::Viewer::UpdateMode)) );
281 
282  QObject::connect( photoMemento, SIGNAL(changeDisplayMail(Viewer::ForceDisplayTo,bool)),
283  style->sourceObject(), SIGNAL(changeDisplayMail(Viewer::ForceDisplayTo,bool)) );
284  }
285 
286  if ( photoMemento->finished() ) {
287 
288  useOtherPhotoSources = true;
289  if ( photoMemento->photo().isIntern() ) {
290  // get photo data and convert to data: url
291  QImage photo = photoMemento->photo().data();
292  if ( !photo.isNull() ) {
293  settings.photoWidth = photo.width();
294  settings.photoHeight = photo.height();
295  // scale below 60, otherwise it can get way too large
296  if ( settings.photoHeight > 60 ) {
297  double ratio = ( double )settings.photoHeight / ( double )settings.photoWidth;
298  settings.photoHeight = 60;
299  settings.photoWidth = (int)( 60 / ratio );
300  photo = photo.scaled( settings.photoWidth, settings.photoHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
301  }
302  settings.photoURL = MessageViewer::HeaderStyleUtil::imgToDataUrl( photo );
303  }
304  } else {
305  settings.photoURL = photoMemento->photo().url();
306  if ( settings.photoURL.startsWith(QLatin1Char('/')) )
307  settings.photoURL.prepend( QLatin1String("file:") );
308  }
309  } else {
310  // if the memento is not finished yet, use other photo sources instead
311  useOtherPhotoSources = true;
312  }
313  } else {
314  useOtherPhotoSources = true;
315  }
316 
317  if( settings.photoURL.isEmpty() && message->headerByType( "Face" ) && useOtherPhotoSources ) {
318  // no photo, look for a Face header
319  const QString faceheader = message->headerByType( "Face" )->asUnicodeString();
320  if ( !faceheader.isEmpty() ) {
321 
322  kDebug() << "Found Face: header";
323 
324  const QByteArray facestring = faceheader.toUtf8();
325  // Spec says header should be less than 998 bytes
326  // Face: is 5 characters
327  if ( facestring.length() < 993 ) {
328  const QByteArray facearray = QByteArray::fromBase64( facestring );
329 
330  QImage faceimage;
331  if ( faceimage.loadFromData( facearray, "png" ) ) {
332  // Spec says image must be 48x48 pixels
333  if ( ( 48 == faceimage.width() ) && ( 48 == faceimage.height() ) ) {
334  settings.photoURL = MessageViewer::HeaderStyleUtil::imgToDataUrl( faceimage );
335  settings.photoWidth = 48;
336  settings.photoHeight = 48;
337  } else {
338  kDebug() << "Face: header image is" << faceimage.width() << "by"
339  << faceimage.height() << "not 48x48 Pixels";
340  }
341  } else {
342  kDebug() << "Failed to load decoded png from Face: header";
343  }
344  } else {
345  kDebug() << "Face: header too long at" << facestring.length();
346  }
347  }
348  }
349 
350  if( settings.photoURL.isEmpty() && message->headerByType( "X-Face" ) && useOtherPhotoSources ) {
351  // no photo, look for a X-Face header
352  const QString xfhead = message->headerByType( "X-Face" )->asUnicodeString();
353  if ( !xfhead.isEmpty() ) {
354  MessageViewer::KXFace xf;
355  settings.photoURL = MessageViewer::HeaderStyleUtil::imgToDataUrl( xf.toImage( xfhead ) );
356  settings.photoWidth = 48;
357  settings.photoHeight = 48;
358  }
359  }
360 
361  return settings;
362 }
363 
364 }
365 }
MessageViewer::HeaderStyleUtil::directionOf
QString directionOf(const QString &str)
Definition: headerstyle_util.cpp:45
MessageViewer::HeaderStyle::allowAsync
bool allowAsync() const
Definition: headerstyle.h:124
globalsettings.h
MessageViewer::HeaderStyleUtil::drawSpamMeter
QString drawSpamMeter(SpamError spamError, double percent, double confidence, const QString &filterHeader, const QString &confidenceHeader)
Definition: headerstyle_util.cpp:108
MessageViewer::HeaderStyle
This class encapsulates the visual appearance of message headers.
Definition: headerstyle.h:60
MessageViewer::HeaderStyleUtil::dateString
QString dateString(KMime::Message *message, bool printing, bool shortDate)
Definition: headerstyle_util.cpp:54
MessageViewer::HeaderStyleUtil::resentToList
QList< KMime::Types::Mailbox > resentToList(KMime::Message *message)
Definition: headerstyle_util.cpp:243
MessageViewer::noError
Definition: spamheaderanalyzer.h:45
MessageViewer::HeaderStyleUtil::xface
xfaceSettings xface(const MessageViewer::HeaderStyle *style, KMime::Message *message)
Definition: headerstyle_util.cpp:262
MessageViewer::HeaderStyleUtil::xfaceSettings::photoHeight
int photoHeight
Definition: headerstyle_util.h:70
MessageViewer::HeaderStyleUtil::xfaceSettings::photoWidth
int photoWidth
Definition: headerstyle_util.h:69
MessageViewer::Viewer::UpdateMode
UpdateMode
The display update mode: Force updates the display immediately, Delayed updates after some time (150m...
Definition: viewer.h:132
kxface.h
nodehelper.h
MessageViewer::HeaderStyleUtil::xfaceSettings
Definition: headerstyle_util.h:61
MessageViewer::couldNotConverScoreToFloat
Definition: spamheaderanalyzer.h:48
MessageViewer::SpamScores
QVector< SpamScore > SpamScores
Definition: spamheaderanalyzer.h:102
headerstyle.h
MessageViewer::SpamError
SpamError
Definition: spamheaderanalyzer.h:44
MessageViewer::HeaderStyleUtil::dateShortStr
QString dateShortStr(const KDateTime &dateTime)
Definition: headerstyle_util.cpp:218
MessageViewer::Viewer::ForceDisplayTo
ForceDisplayTo
Definition: viewer.h:108
MessageViewer::HeaderStyleUtil::dateStr
QString dateStr(const KDateTime &dateTime)
Definition: headerstyle_util.cpp:209
MessageViewer::HeaderStyle::nodeHelper
NodeHelper * nodeHelper() const
Definition: headerstyle.h:121
MessageViewer::ContactDisplayMessageMemento
Definition: contactdisplaymessagememento.h:35
MessageViewer::KXFace::toImage
QImage toImage(const QString &xface)
creates a pixmap from xface
Definition: kxface.cpp:154
MessageViewer::couldNotFindTheScoreField
Definition: spamheaderanalyzer.h:50
contactdisplaymessagememento.h
MessageViewer::KXFace
Definition: kxface.h:521
MessageViewer::HeaderStyleUtil::subjectDirectionString
QString subjectDirectionString(KMime::Message *message)
Definition: headerstyle_util.cpp:84
MessageViewer::NodeHelper::setBodyPartMemento
void setBodyPartMemento(KMime::Content *node, const QByteArray &which, Interface::BodyPartMemento *memento)
Definition: nodehelper.cpp:610
MessageViewer::HeaderStyleUtil::subjectString
QString subjectString(KMime::Message *message, int flags)
Definition: headerstyle_util.cpp:69
MessageViewer::HeaderStyleUtil::imgToDataUrl
QString imgToDataUrl(const QImage &image)
Definition: headerstyle_util.cpp:200
MessageViewer::NodeHelper::bodyPartMemento
Interface::BodyPartMemento * bodyPartMemento(KMime::Content *node, const QByteArray &which) const
Definition: nodehelper.cpp:597
MessageViewer::HeaderStyleUtil::spamStatus
QString spamStatus(KMime::Message *message)
Definition: headerstyle_util.cpp:94
headerstyle_util.h
MessageViewer::couldNotFindTheThresholdField
Definition: spamheaderanalyzer.h:51
MessageViewer::errorExtractingAgentString
Definition: spamheaderanalyzer.h:47
MessageViewer::HeaderStyle::sourceObject
QObject * sourceObject() const
Definition: headerstyle.h:127
MessageViewer::HeaderStyleUtil::resentFromList
QList< KMime::Types::Mailbox > resentFromList(KMime::Message *message)
Definition: headerstyle_util.cpp:224
MessageViewer::HeaderStyleUtil::xfaceSettings::photoURL
QString photoURL
Definition: headerstyle_util.h:68
MessageViewer::HeaderStyleUtil::strToHtml
QString strToHtml(const QString &str, int flags)
Definition: headerstyle_util.cpp:49
MessageViewer::couldNotConvertThresholdToFloatOrThresholdIsNegative
Definition: spamheaderanalyzer.h:49
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:55:57 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

messageviewer

Skip menu "messageviewer"
  • 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