Messagelib

spamheaderanalyzer.cpp
1 /*
2  spamheaderanalyzer.cpp
3 
4  This file is part of KMail, the KDE mail client.
5  SPDX-FileCopyrightText: 2004 Patrick Audley <[email protected]>
6  SPDX-FileCopyrightText: 2004 Ingo Kloecker <[email protected]>
7 
8  SPDX-License-Identifier: GPL-2.0-or-later
9 */
10 
11 #include "spamheaderanalyzer.h"
12 #include "antispamconfig.h"
13 #include "messageviewer_debug.h"
14 
15 #include <KMime/Headers>
16 #include <KMime/KMimeMessage>
17 
18 using namespace MessageViewer;
19 
20 // static
22 {
23  SpamScores scores;
24  const SpamAgents agents = AntiSpamConfig::instance()->uniqueAgents();
26  for (SpamAgents::const_iterator it = agents.constBegin(); it != end; ++it) {
27  float score = -2.0;
28 
29  SpamError spamError = noError;
30 
31  // Skip bogus agents
32  if ((*it).scoreType() == SpamAgentNone) {
33  continue;
34  }
35 
36  // Do we have the needed score field for this agent?
37  KMime::Headers::Base *header = message->headerByType((*it).header().constData());
38  if (!header) {
39  continue;
40  }
41 
42  const QString mField = header->asUnicodeString();
43 
44  if (mField.isEmpty()) {
45  continue;
46  }
47 
48  QString scoreString;
49  bool scoreValid = false;
50 
51  if ((*it).scoreType() != SpamAgentBool) {
52  // Can we extract the score?
53  QRegExp scorePattern = (*it).scorePattern();
54  if (scorePattern.indexIn(mField) != -1) {
55  scoreString = scorePattern.cap(1);
56  scoreValid = true;
57  }
58  } else {
59  scoreValid = true;
60  }
61 
62  if (!scoreValid) {
63  spamError = couldNotFindTheScoreField;
64  qCDebug(MESSAGEVIEWER_LOG) << "Score could not be extracted from header '" << mField << "'";
65  } else {
66  bool floatValid = false;
67  switch ((*it).scoreType()) {
68  case SpamAgentNone:
69  spamError = errorExtractingAgentString;
70  break;
71 
72  case SpamAgentBool:
73  if ((*it).scorePattern().indexIn(mField) == -1) {
74  score = 0.0;
75  } else {
76  score = 100.0;
77  }
78  break;
79 
80  case SpamAgentFloat:
81  score = scoreString.toFloat(&floatValid);
82  if (!floatValid) {
83  spamError = couldNotConverScoreToFloat;
84  qCDebug(MESSAGEVIEWER_LOG) << "Score (" << scoreString << ") is no number";
85  } else {
86  score *= 100.0;
87  }
88  break;
89 
90  case SpamAgentFloatLarge:
91  score = scoreString.toFloat(&floatValid);
92  if (!floatValid) {
93  spamError = couldNotConverScoreToFloat;
94  qCDebug(MESSAGEVIEWER_LOG) << "Score (" << scoreString << ") is no number";
95  }
96  break;
97 
98  case SpamAgentAdjustedFloat:
99  score = scoreString.toFloat(&floatValid);
100  if (!floatValid) {
101  spamError = couldNotConverScoreToFloat;
102  qCDebug(MESSAGEVIEWER_LOG) << "Score (" << scoreString << ") is no number";
103  break;
104  }
105 
106  // Find the threshold value.
107  QString thresholdString;
108  const QRegExp thresholdPattern = (*it).thresholdPattern();
109  if (thresholdPattern.indexIn(mField) != -1) {
110  thresholdString = thresholdPattern.cap(1);
111  } else {
112  spamError = couldNotFindTheThresholdField;
113  qCDebug(MESSAGEVIEWER_LOG) << "Threshold could not be extracted from header '" << mField << "'";
114  break;
115  }
116  const float threshold = thresholdString.toFloat(&floatValid);
117  if (!floatValid || (threshold <= 0.0)) {
118  spamError = couldNotConvertThresholdToFloatOrThresholdIsNegative;
119  qCDebug(MESSAGEVIEWER_LOG) << "Threshold (" << thresholdString << ") is no"
120  << "number or is negative";
121  break;
122  }
123 
124  // Normalize the score. Anything below 0 means 0%, anything above
125  // threshold mean 100%. Values between 0 and threshold are mapped
126  // linearly to 0% - 100%.
127  if (score < 0.0) {
128  score = 0.0;
129  } else if (score > threshold) {
130  score = 100.0;
131  } else {
132  score = score / threshold * 100.0;
133  }
134  break;
135  }
136  }
137  // Find the confidence
138  float confidence = -2.0;
139  QString confidenceString = QStringLiteral("-2.0");
140  bool confidenceValid = false;
141  // Do we have the needed confidence field for this agent?
142  const QByteArray confidenceHeaderName = (*it).confidenceHeader();
143  QString mCField;
144  if (!confidenceHeaderName.isEmpty()) {
145  KMime::Headers::Base *cHeader = message->headerByType(confidenceHeaderName.constData());
146  if (cHeader) {
147  mCField = cHeader->asUnicodeString();
148  if (!mCField.isEmpty()) {
149  // Can we extract the confidence?
150  QRegExp cScorePattern = (*it).confidencePattern();
151  if (cScorePattern.indexIn(mCField) != -1) {
152  confidenceString = cScorePattern.cap(1);
153  }
154  confidence = confidenceString.toFloat(&confidenceValid);
155  if (!confidenceValid) {
156  spamError = couldNotConvertConfidenceToFloat;
157  qCDebug(MESSAGEVIEWER_LOG) << "Unable to convert confidence to float:" << confidenceString;
158  }
159  }
160  }
161  }
162  scores.append(SpamScore((*it).name(), spamError, score, confidence * 100, mField, mCField));
163  }
164 
165  return scores;
166 }
QString cap(int nth) const const
void append(const T &value)
QVector::const_iterator constEnd() const const
bool isEmpty() const const
static SpamScores getSpamScores(KMime::Message *message)
Extract scores from known anti-spam headers.
virtual QString asUnicodeString() const =0
A simple tuple of error, agent, score, confidence and header.
int indexIn(const QString &str, int offset, QRegExp::CaretMode caretMode) const const
bool isEmpty() const const
const char * constData() const const
Headers::Base * headerByType(const char *type) const
QVector::const_iterator constBegin() const const
float toFloat(bool *ok) const const
typedef const_iterator
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Dec 4 2021 23:12:54 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.