Logo Search packages:      
Sourcecode: mailfilter version File versions  Download package

Checker.cc

// Checker.cc - source file for the mailfilter program
// Copyright (c) 2000 - 2004  Andreas Bauer <baueran@in.tum.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.

#include <string>
#include <vector>
#include <algorithm>
extern "C" {
#include <unistd.h>
#include <regex.h>
}
#include "Header.hh"
#include "Feedback.hh"
#include "Checker.hh"

using namespace std;
using namespace msg;

namespace check {


  Checker::Checker(pref::Preferences* pr) {
    prefs = pr;
  }


  Checker::~Checker() {
  }

  
  //! Returns the header sub-string that was matched to a spam filter rule (see matchingFilter)
  vector<string>* Checker::getMatchingStrings(void) {
    return &matchingStrings;
  }


  //! Returns the filters that matched a header sub-string (see matchingString)
  vector<string>* Checker::getMatchingFilters(void) {
    return &matchingFilters;
  }


  //! Sets/adds matching filter
  void Checker::setMatchingFilter(const string nf) {
    matchingFilters.push_back(nf);
  }


  //! Sets/adds matching string
  void Checker::setMatchingString(const string ns) {
    matchingStrings.push_back(ns);
  }


  //! Delete matching strings
  void Checker::cleanMatchingStrings(void) {
    matchingStrings.clear();
  }


  //! Delete matching filters/scores
  void Checker::cleanMatchingFilters(void) {
    matchingFilters.clear();
  }


  //! Returns 0 if MAXSIZE_ALLOW was exceeded, 1 if message is a friend to pass filters, 2 if message could not be categorised
  // (i. e. needs further processing)
  int Checker::friends(Header* curMessage) {
    vector<Line>::const_iterator curLine = curMessage->lines().begin();
    vector<pref::friendInfo>::iterator curFriend = prefs->getFriends()->begin();
            
    while ( curLine != curMessage->lines().end() ) {
      curFriend = prefs->getFriends()->begin();
      string currentLine = ((Line)(*curLine)).descr();
      currentLine.append(": ");
      currentLine.append(((Line)(*curLine)).content());
      
      while ( curFriend != prefs->getFriends()->end() ) {
      // Check whether we're checking mail from a friend
      if (regExp.exec(&curFriend->cFilter, currentLine) == 0) {
        // Check if MAXSIZE_ALLOW applies and eventually delete message
        if ( (prefs->getMaxsizeFriends() > 0) && (curMessage->size() > prefs->getMaxsizeFriends()) )
          return 0;      // Message size exceeded
        else {
          setMatchingFilter(curFriend->filter);
          setMatchingString(currentLine);
          return 1;      // This message is a friend, don't delete
        }
      }

      curFriend++;
      }
      
      curLine++;
    }
    
    return 2;              // Message could not be recognised as a 'friend'
  }


  //! Returns the SPAM-score this message achieved
  int Checker::scores(Header* curMessage) {
    vector<Line>::const_iterator curLine = curMessage->lines().begin();
    vector<pref::scoreInfo>::iterator curScore = prefs->getScores()->begin();
    int totScore = 0;

    while (curLine != curMessage->lines().end()) {
      curScore = prefs->getScores()->begin();
      string currentLine = ((Line)(*curLine)).descr();
      currentLine.append(": ");
      currentLine.append(((Line)(*curLine)).content());
      
      while ( curScore != prefs->getScores()->end() ) {
      // Check the filters and message header strings
      if ( (regExp.exec(&curScore->cFilter, currentLine) == 0) && !curScore->negative ) {
        setMatchingFilter(curScore->filter);
        setMatchingString(currentLine);
        totScore += curScore->score;
      }
      // Check if the current filter matches the 'normalised' subject line
      // if the currently checked line is indeed the subject; this is not
      // necessary with the ordinary filters, cause they delete instantly.
      // Scores need to match the normalised subject really only once, not
      // multiple times, or they accumulate wrong scores.
      else if ( prefs->isNormal() &&
              currentLine.find("Subject") == 0 &&
              (regExp.exec(&curScore->cFilter, curMessage->normalSubject()) == 0) &&
              !curScore->negative )
        {
          setMatchingFilter(curScore->filter);
          setMatchingString(curMessage->normalSubject());
          totScore += curScore->score;
        }
      
      curScore++;
      }
      
      curLine++;
    }

    return totScore;
  }


  //! Returns 0 if message was spam, 1 if message was spam after normalisation, 2 otherwise
  int Checker::filters(Header* curMessage) {
    vector<Line>::const_iterator curLine = curMessage->lines().begin();
    vector<pref::filterInfo>::iterator curFilter = prefs->getFilters()->begin();

    while (curLine != curMessage->lines().end()) {
      curFilter = prefs->getFilters()->begin();
      string currentLine = ((Line)(*curLine)).descr();
      currentLine.append(": ");
      currentLine.append(((Line)(*curLine)).content());
      
      while ( curFilter != prefs->getFilters()->end() ) {
      // Check the filters and message header strings
      if ( (regExp.exec(&curFilter->cFilter, currentLine) == 0) && !curFilter->negative ) {
        setMatchingFilter(curFilter->filter);
        setMatchingString(currentLine);
        return 0;
      }
      // Check if the current filter matches the 'normalised' subject line (if NORMAL was set to 'yes')
      else if ( prefs->isNormal() && (regExp.exec(&curFilter->cFilter, curMessage->normalSubject()) == 0) && !curFilter->negative ) {
        setMatchingFilter(curFilter->filter);
        setMatchingString(curMessage->normalSubject());
        return 1;
      }

      curFilter++;
      }
      
      curLine++;
    }

    return 2;          // Message not recognized as spam - message remains untouched
  }
  

  //! Returns  0 if line length exceeded, 1 otherwise
  int Checker::lineLength(Header* curMessage) {
    vector<Line>::const_iterator curLine = curMessage->lines().begin();
    int maxLineLength = prefs->getMaxLineLength();

    if (maxLineLength == 0)
      return 1;         // Message should not be checked for line length
    else {
      while (curLine != curMessage->lines().end()) {
      if ((int)(((Line)(*curLine)).content().length()) >= maxLineLength) {
        setMatchingString(((Line)(*curLine)).descr());
        return 0;
      }
      curLine++;
      }
    }
    
    return 1;          // Message considered RFC822 compliant (or suits the user defined limit) - message remains untouched
  }
  
  
  //! Returns 0 if message was spam, 1 otherwise
  int Checker::negFilters(Header* curMessage) {
    string currentLine;
    vector<Line>::const_iterator curLine;
    vector<pref::filterInfo>::iterator curFilter = prefs->getFilters()->begin();

    while (curFilter != prefs->getFilters()->end()) {
      if (!curFilter->negative) {
      curFilter++;
      continue;
      }

      // Start with the first line of the header
      curLine = curMessage->lines().begin();

      while (curLine != curMessage->lines().end()) {
      currentLine = ((Line)(*curLine)).descr();
      currentLine.append(": ");
      currentLine.append(((Line)(*curLine)).content());

      if ( curFilter->negative && (regExp.exec(&curFilter->cFilter, currentLine) == 0) ) {
        break;         // Filter matched. Check next filter now.
      }
      else {
        curLine++;

        if (curLine == curMessage->lines().end()) {
          setMatchingFilter(curFilter->filter);
          setMatchingString(currentLine);
          return 0;
        }
      }
      }
      
      curFilter++;
    }

    return 1;          // Message not recognized as spam - message remains untouched
  }


  //! Returns the SPAM-score this message achieved with the negative filters
  int Checker::negScores(Header* curMessage) {
    string currentLine;
    vector<Line>::const_iterator curLine;
    vector<pref::scoreInfo>::iterator curScore = prefs->getScores()->begin();
    int totScore = 0;

    while (curScore != prefs->getScores()->end()) {
      if (!curScore->negative) {
      curScore++;
      continue;
      }

      // Start with the first line of the header
      curLine = curMessage->lines().begin();

      while (curLine != curMessage->lines().end()) {
      currentLine = ((Line)(*curLine)).descr();
      currentLine.append(": ");
      currentLine.append(((Line)(*curLine)).content());

      if ( curScore->negative && (regExp.exec(&curScore->cFilter, currentLine) == 0) ) {
        break;         // Filter matched. Check next filter now.
      }
      else {
        curLine++;

        if (curLine == curMessage->lines().end()) {
          setMatchingFilter(curScore->filter);
          setMatchingString(currentLine);
          totScore += curScore->score;
        }
      }
      }
      
      curScore++;
    }

    return totScore;
  }


  //! Returns the SPAM-score this message achieved with MAXSIZE_SCORE
  int Checker::maxSizeScore(Header* curMessage) {
    int totScore = 0;

    if (prefs->getMaxSizeScore().score != 0
      && prefs->getMaxSizeScore().size > 0
      && curMessage->size() > prefs->getMaxSizeScore().size)
      totScore = prefs->getMaxSizeScore().score;

    return totScore;
  }


  //! Returns 0 if message was too large, 1 otherwise
  int Checker::size(Header* curMessage) {
    if ( (prefs->getMaxsize() > 0) && (curMessage->size() > prefs->getMaxsize()) )
      return 0;            // Message size exceeded
    else
      return 1;            // This message does not exceed the limit
  }


  //! Returns  0 if message was a duplicate, 1 otherwise
  int Checker::duplicates(Header* curMessage, vector<string>* msgIDs) {
    bool isDuplicate = false;

    // Check whether the current message contains a valid Message-ID
    // field at all.
    if (curMessage->messageID().length() <= 0)
      return 1;

    // Check whether current message is a duplicate, if not then store
    // the header.
    if ( find(msgIDs->begin(), msgIDs->end(), curMessage->messageID()) != msgIDs->end() )
      isDuplicate = true;
    else {
      // Store the current message's ID for future validations
      msgIDs->push_back(curMessage->messageID());
      isDuplicate = false;
    }
    
    if ( prefs->getDelDubs() && isDuplicate ) {
      return 0;   // Message was duplicate, delete
    }
    else
      return 1;   // This message was no duplicate
  }


}

Generated by  Doxygen 1.6.0   Back to index