<commit_before>"use strict";
// An SMTP Transaction

var config = require('./config');
var Header = require('./mailheader').Header;
var body   = require('./mailbody');
var utils  = require('./utils');
var MessageStream = require('./messagestream');

var trans = exports;

function Transaction() {
    this.uuid = null;
    this.mail_from = null;
    this.rcpt_to = [];
    this.header_lines = [];
    this.data_lines = [];
    this.banner = null;
    this.data_bytes = 0;
    this.header_pos = 0;
    this.body = null;
    this.parse_body = false;
    this.notes = {};
    this.header = new Header();
    this.message_stream = null;
    this.discard_data = false;
    this.rcpt_count = {
        accept:   0,
        tempfail: 0,
        reject:   0,
    };
}

exports.Transaction = Transaction;

exports.createTransaction = function(uuid) {
    var t = new Transaction();
    t.uuid = uuid || utils.uuid();
    // Initialize MessageStream here to pass in the UUID
    t.message_stream = new MessageStream(config.get('smtp.ini'), t.uuid, t.header.header_list);
    return t;
};

Transaction.prototype.add_data = function(line) {
    if (!this.discard_data) this.message_stream.add_line(line);
    if (typeof line !== 'string') {
        line = line.toString('binary');
    }
    line = line.replace(/^\./, '').replace(/\r\n$/, '\n');
    // check if this is the end of headers line  
    if (this.header_pos === 0 && line[0] === '\n') {
        this.header.parse(this.header_lines);
        this.header_pos = this.header_lines.length;
        if (this.parse_body) {
            this.body = this.body || new body.Body(this.header, {"banner": this.banner});
        }
    }
    else if (this.header_pos === 0) {
        // Build up headers
        this.header_lines.push(line);
    }
    else if (this.header_pos && this.parse_body) {
        this.body.parse_more(line);
    }
};

Transaction.prototype.end_data = function() {
    if (this.header_pos && this.parse_body) {<commit_msg>Fix parsing of busted emails<commit_after>"use strict";
// An SMTP Transaction

var config = require('./config');
var Header = require('./mailheader').Header;
var body   = require('./mailbody');
var utils  = require('./utils');
var MessageStream = require('./messagestream');

var trans = exports;

var MAX_HEADER_LINES = config.get('max_header_lines') || 1000;

function Transaction() {
    this.uuid = null;
    this.mail_from = null;
    this.rcpt_to = [];
    this.header_lines = [];
    this.data_lines = [];
    this.banner = null;
    this.data_bytes = 0;
    this.header_pos = 0;
    this.body = null;
    this.parse_body = false;
    this.notes = {};
    this.header = new Header();
    this.message_stream = null;
    this.discard_data = false;
    this.rcpt_count = {
        accept:   0,
        tempfail: 0,
        reject:   0,
    };
}

exports.Transaction = Transaction;

exports.createTransaction = function(uuid) {
    var t = new Transaction();
    t.uuid = uuid || utils.uuid();
    // Initialize MessageStream here to pass in the UUID
    t.message_stream = new MessageStream(config.get('smtp.ini'), t.uuid, t.header.header_list);
    return t;
};

Transaction.prototype.add_data = function(line) {
    if (!this.discard_data) this.message_stream.add_line(line);
    if (typeof line !== 'string') {
        line = line.toString('binary');
    }
    line = line.replace(/^\./, '').replace(/\r\n$/, '\n');
    // check if this is the end of headers line  
    if (this.header_pos === 0 && line[0] === '\n') {
        this.header.parse(this.header_lines);
        this.header_pos = this.header_lines.length;
        if (this.parse_body) {
            this.body = this.body || new body.Body(this.header, {"banner": this.banner});
        }
    }
    else if (this.header_pos === 0) {
        // Build up headers
        if (this.header_lines.length < MAX_HEADER_LINES) {
            this.header_lines.push(line);
        }
    }
    else if (this.header_pos && this.parse_body) {
        this.body.parse_more(line);
    }
};

Transaction.prototype.end_data = function() {
    if (this.header_lines.length && this.header.header_list.length === 0) {
        // Headers not parsed yet - must be a busted email
        // Strategy: Find first blank line, parse up to that as headers. Rest as body.
        var header_pos = 0;
        for (var i = 0; i < this.header_lines.length; i++) {
            header_pos = i;
            if (/^\s*$/.test(this.header_lines[i])) {
                this.header_lines[i] = '\n';
                break;
            }
        }
        var body_lines = this.header_lines.splice(header_pos + 1);
        this.header_lines = this.header_lines.splice(0, header_pos);
        this.header.parse(this.header_lines);
        this.header_pos = header_pos;
        if (this.parse_body) {
            this.body = this.body || new body.Body(this.header, {"banner": this.banner});
            for (var i = 0; i < body_lines.length; i++) {
                this.body.parse_more(body_lines[i]);
            }
        }
    }
    if (this.header_pos && this.parse_body) {
{'fraction_non_alphanumeric': 0.15069840645288216, 'fraction_numerical': 0.005115089514066497, 'mean_word_length': 2.4351351351351354, 'pattern_counts': {'":': 3, '<': 6, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3775123', 'n_tokens_mistral': 1650, 'n_tokens_neox': 1626, 'n_words': 363}