<commit_before>var net = require('net');
var util = require('util');
var events = require('events');
var PathModule = require('path');
var glob = require('./glob');
require('./date-format');

/*
TODO:
- Implement Full RFC 959
- Implement RFC 2428
- Implement RFC 2228
- Implement RFC 3659
- Implement TLS - http://en.wikipedia.org/wiki/FTPS


- passive command is for server to determine which port it listens on and report that to the client
- doesn't necessarily mean it needs to be listening (i guess), but i assume it actually SHOULD be listening
- it keeps listening for subsequent connections

- what sort of security should i enforce? should i require the same IP for data and control connections?
    - maybe just for milesplit's use?
*/

function FtpConnection(properties) {
    if (false === (this instanceof FtpConnection)) {
        return new FtpConnection();
    }
    events.EventEmitter.call(this);

    for (k in properties) { this[k] = properties[k]; }
}
util.inherits(FtpConnection, process.EventEmitter);

// host
//     an IP address.
//
// options.getFsModule
//     a function which, given a username, returns an object implemeting the API of
//     require('fs'). The following need to be implemented:
//         unlink
//         readdir
//         statSync
//         mkdir
//         open
//         read
//         close
//         rmdir
//         rename
//         stat
//         write
//
// options.getPathModule
//     a function which, given a username, returns an object implemeting the API of
//     require('path'). The following need to be implemented:
//         exists
//
// options.getInitialCwd
//     a function which, given a username, returns an initial CWD.
//
// options.getRoot
//     a function which, given a username, returns a root directory (user cannot get
//     outside of this dir).
// 
function FtpServer(host, options) {
    var self = this;

    if (false === (this instanceof FtpServer)) {
        return new FtpServer(host, options);
    }
    events.EventEmitter.call(this);

    // make sure host is an IP address, otherwise DATA connections will likely break
    this.server = net.createServer();
    this.getFsModule = options.getFsModule || (function () { var fs = require('fs'); return function () { return fs } })();
    this.getPathModule = options.getPathModule || function () { return PathModule; }
    this.getInitialCwd = options.getInitialCwd || function () { return "/"; };
    this.getRoot = options.getRoot || function () { return "/"; };
    this.debugging = 0;

    var logIf = function(level, message, socket) {
        if (self.debugging >= level) {
            if (socket)
                console.log(socket.remoteAddress + ": " + message);
            else
                console.log(message);
        }
    };

    this.server.on("listening", function() {
        logIf(0, "nodeFTPd server up and ready for connections");
    });
    this.server.on("connection", function(socket) {
        var conn = new FtpConnection({
            passive: false,
            dataHost: null,
            dataPort: 20, // default
            dataListener: null, // for incoming passive connections
            dataSocket: null, // the actual data socket
            mode: "ascii",
            filefrom: "",
            authFailures: 0, // 3 tries then we disconnect you
            temp: null,
            username: null,
            totsize: 0,
            filename: ""
        });

        self.emit("client:connected", conn); // pass socket so they can listen for client-specific events

        socket.setTimeout(0);
        socket.setEncoding("ascii"); // force data String not Buffer
        socket.setNoDelay();

//        logIf(0, "Base FTP directory: "+conn.fs.cwd());

        var authenticated = function() {
            // send a message if not authenticated?
            return (conn.username ? true : false);
        };

        var authFailures = function() {
            if (conn.authFailures >= 2) {
                socket.end();
                return true;
            }
            return false;
        };<commit_msg>Prefigure options of FtpConnection set when user logs in.<commit_after>var net = require('net');
var util = require('util');
var events = require('events');
var PathModule = require('path');
var glob = require('./glob');
require('./date-format');

/*
TODO:
- Implement Full RFC 959
- Implement RFC 2428
- Implement RFC 2228
- Implement RFC 3659
- Implement TLS - http://en.wikipedia.org/wiki/FTPS


- passive command is for server to determine which port it listens on and report that to the client
- doesn't necessarily mean it needs to be listening (i guess), but i assume it actually SHOULD be listening
- it keeps listening for subsequent connections

- what sort of security should i enforce? should i require the same IP for data and control connections?
    - maybe just for milesplit's use?
*/

function FtpConnection(properties) {
    if (false === (this instanceof FtpConnection)) {
        return new FtpConnection();
    }
    events.EventEmitter.call(this);

    for (k in properties) { this[k] = properties[k]; }
}
util.inherits(FtpConnection, process.EventEmitter);

// host
//     an IP address.
//
// options.getFsModule
//     a function which, given a username, returns an object implemeting the API of
//     require('fs'). The following need to be implemented:
//         unlink
//         readdir
//         statSync
//         mkdir
//         open
//         read
//         close
//         rmdir
//         rename
//         stat
//         write
//
// options.getPathModule
//     a function which, given a username, returns an object implemeting the API of
//     require('path'). The following need to be implemented:
//         exists
//
// options.getInitialCwd
//     a function which, given a username, returns an initial CWD.
//
// options.getRoot
//     a function which, given a username, returns a root directory (user cannot get
//     outside of this dir).
// 
function FtpServer(host, options) {
    var self = this;

    if (false === (this instanceof FtpServer)) {
        return new FtpServer(host, options);
    }
    events.EventEmitter.call(this);

    // make sure host is an IP address, otherwise DATA connections will likely break
    this.server = net.createServer();
    this.getFsModule = options.getFsModule || (function () { var fs = require('fs'); return function () { return fs } })();
    this.getPathModule = options.getPathModule || function () { return PathModule; }
    this.getInitialCwd = options.getInitialCwd || function () { return "/"; };
    this.getRoot = options.getRoot || function () { return "/"; };
    this.debugging = 0;

    var logIf = function(level, message, socket) {
        if (self.debugging >= level) {
            if (socket)
                console.log(socket.remoteAddress + ": " + message);
            else
                console.log(message);
        }
    };

    this.server.on("listening", function() {
        logIf(0, "nodeFTPd server up and ready for connections");
    });
    this.server.on("connection", function(socket) {
        var conn = new FtpConnection({
            passive: false,
            dataHost: null,
            dataPort: 20, // default
            dataListener: null, // for incoming passive connections
            dataSocket: null, // the actual data socket
            mode: "ascii",
            filefrom: "",
            authFailures: 0, // 3 tries then we disconnect you
            temp: null,
            username: null,
            totsize: 0,
            filename: "",
            fs: null,
            path: null,
            cwd: null,
            root: null
        });

        self.emit("client:connected", conn); // pass socket so they can listen for client-specific events

        socket.setTimeout(0);
        socket.setEncoding("ascii"); // force data String not Buffer
        socket.setNoDelay();

//        logIf(0, "Base FTP directory: "+conn.fs.cwd());

        var authenticated = function() {
            // send a message if not authenticated?
            return (conn.username ? true : false);
        };

        var authFailures = function() {
            if (conn.authFailures >= 2) {
                socket.end();
                return true;
            }
            return false;
        };
{'fraction_non_alphanumeric': 0.11456961570693164, 'fraction_numerical': 0.005985873338920148, 'mean_word_length': 2.142964635063958, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 7, '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': '4770135', 'n_tokens_mistral': 2290, 'n_tokens_neox': 2202, 'n_words': 768}