"use strict";
/* jshint node: true */
/* globals DENY */

var util = require('util');

exports.register = function() {
    var plugin = this;

    try {
        plugin.ldap = require('ldapjs');
    }
    catch(e) {
        plugin.logerror("failed to load ldapjs, try installing it (npm install ldapjs)");
        return;
    }

    // only load this stuff if ldapjs loaded
    plugin.load_host_list();
    plugin.load_ldap_ini();
    plugin.register_hook('rcpt', 'validate_rcpt');
};

exports.load_ldap_ini = function() {
    var plugin = this;
    plugin.loginfo("loading rcpt_to.ldap.ini");
    plugin.cfg = plugin.config.get('rcpt_to.ldap.ini', 'ini', plugin.load_ldap_ini);
};

exports.load_host_list = function () {
    var plugin = this;

    plugin.loginfo(plugin, "loading host_list");
    var lowered_list = {};  // assemble
    var raw_list = plugin.config.get('host_list', 'list', plugin.load_host_list);
    for (var i in raw_list) {
        lowered_list[raw_list[i].toLowerCase()] = true;
    }
    plugin.host_list = lowered_list;
};

exports.validate_rcpt = function(next, connection, params) {
    var plugin = this;

    var domain = params[0].host.toLowerCase();

    if (!plugin.in_host_list(domain) && !plugin.in_ldap_ini(domain)) {
        connection.logdebug(plugin, "domain '" + domain + "' is not local; skipping ldap.");
        return next();
    }

    var ar = connection.transaction.results.get('access');
    if (ar && ar.pass.length > 0 && ar.pass.indexOf("rcpt_to.access.whitelist") !== -1) {
        connection.loginfo(plugin, "Accepting whitelisted recipient.");
        return next();
    }

    var cfg = plugin.in_host_list(domain) ? plugin.cfg.main : plugin.cfg[domain];
    var client = plugin.ldap.createClient({ url: cfg.server });

    client.bind(cfg.binddn, cfg.bindpw, function(err) {
        connection.logerror(plugin, 'error: ' + err);
    });

    var rcpt = params[0];
    var plain_rcpt = JSON.stringify(rcpt.original).replace('<', '').replace('>', '').replace('"', '').replace('"', '');

    var opts = {
        filter: '(&(objectClass=' + cfg.objectclass + ')(|(mail=' + plain_rcpt  + ')(mailAlternateAddress=' + plain_rcpt + ')))',
        scope: 'sub',
        attributes: ['dn', 'mail', 'mailAlternateAddress']
    };

    connection.logdebug(plugin, "Search filter is: " + util.inspect(opts));

    client.search(cfg.basedn, opts, function(err, res) {
        var items = [];
        res.on('searchEntry', function(entry) {
            connection.logdebug(plugin, 'entry: ' + JSON.stringify(entry.object));
            items.push(entry.object);
        });

        res.on('error', function(err) {
            connection.logerror(plugin, 'LDAP search error: ' + err);
        });

        res.on('end', function(result) {
            connection.logdebug(plugin, 'LDAP search results: ' + items.length + ' -- ' + util.inspect(items));

            if (!items.length) {
                return next(DENY, "Sorry - no mailbox here by that name.");
            } else {
                next();
            }
        });
    });
};

exports.in_host_list = function (domain) {
    var plugin = this;
    plugin.logdebug("checking " + domain + " in config/host_list");
    if (plugin.host_list[domain]) return true;
    return false;
};

exports.in_ldap_ini = function (domain) {
    var plugin = this;
    if (!plugin.cfg[domain]) return false;
    if (!plugin.cfg[domain].server) return false;
    return true;
};

@@ -1135,22 +1135,20 @@
     var 
-domain
+rcpt
  = param
@@ -1151,16 +1151,161 @@
 arams%5B0%5D
+;%0A    if (!rcpt.host) %7B%0A        connection.transaction.results.add(plugin, %7Bfail: '!domain'%7D);%0A        return next();%0A    %7D%0A    var domain = rcpt
 .host.to
@@ -1472,18 +1472,13 @@
 skip
-ping
  ldap
-.
 %22);%0A
@@ -1696,17 +1696,12 @@
 n, %22
-Accepting
+skip
  whi
@@ -1718,17 +1718,16 @@
 ecipient
-.
 %22);%0A    
@@ -2030,46 +2030,57 @@
 var 
+plain_
 rcpt = 
-params%5B0%5D;%0A    var plain_rcpt =
+rcpt.address().toLowerCase();%0A    //
  JSO
@@ -2118,11 +2118,11 @@
 ace(
-'%3C'
+/%3C/
 , ''
@@ -2135,28 +2135,11 @@
 ace(
-'%3E', '').replace('%22'
+/%3E/
 , ''
@@ -2152,11 +2152,12 @@
 ace(
-'%22'
+/%22/g
 , ''
@@ -2481,60 +2481,147 @@
     
-client.search(cfg.basedn, opts, function(err, res) %7B
+var search_result = function(err, res) %7B%0A        if (err) %7B%0A            connection.logerror(plugin, 'LDAP search error: ' + err);%0A        %7D
 %0A   
@@ -3116,17 +3116,16 @@
     if (
-!
 items.le
@@ -3130,23 +3130,32 @@
 length) 
-%7B%0A     
+return next();%0A%0A
         
@@ -3153,30 +3153,24 @@
 %0A           
-return
  next(DENY, 
@@ -3223,76 +3223,68 @@
     
-   
- %7D else %7B%0A                next();%0A        
+%7D);%0A
     %7D
+;
 %0A    
-    %7D);%0A    %7D
+client.search(cfg.basedn, opts, search_result
 );%0A%7D

make sure domain exists before using it