#!/usr/bin/mawk -We
# *********************************************************************
# slapdtonbl: experimental slapd(8) SEARCH to NBL syntax converter.
#
# Copyright (c) 2006 Carlo Strozzi
#
# 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; version 2 dated June, 1991.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# *********************************************************************
#
# Notes (to be moved to slapdtonbl.txt):
#
# The name printed by slapd(8) in response to a query will not
# necessarily be those specified in the query itself, but may possibly
# be aliases of the former, depending on the relevant NoSQL schema.
#
# The input table MUST NOT contain any column named 'dn', but it MUST
# always contain a (possibly aliased) non-null 'cn' column.
#
# The data in the input table should strictly conform to the LDAP
# datatypes of schema being used, or LDAP may crash on queries.
#
# Directives of the slapd(8) SEARCH protocol not implemented/used
# by this program (see slapd-shell(5) for more information):
#
#    "msgid:" "timelimit:" "filterstr:" "attrsonly:"
#
# Directives of the slapd(8) SEARCH protocol only partly supported
# by this program (see slapd-shell(5) and slapd-meta(5) for more):
#
#    "suffix:" "scope:" "deref:"


BEGIN {
  NULL = ""

  # Get local settings.
  nosql_install = ENVIRON["NOSQL_INSTALL"]
  stdout = ENVIRON["NOSQL_STDOUT"]
  stderr = ENVIRON["NOSQL_STDERR"]

  # Set default values if necessary.
  if (nosql_install == NULL) nosql_install = "/usr/local/nosql"
  if (stdout == NULL) stdout = "/dev/stdout"
  if (stderr == NULL) stderr = "/dev/stderr"

  # Process command-line options and arguments.

  while (ARGV[++i] != NULL) {
    if (ARGV[i] == "-i" || ARGV[i] == "--input") i_file = ARGV[++i]
    else if (ARGV[i] == "-o" || ARGV[i] == "--output") o_file = ARGV[++i]
    else if (ARGV[i] == "-h") {
       system("grep -v '^#' " nosql_install "/help/slapdtonbl.txt")
       exit(rc=1)
    }
    else if (ARGV[i] == "--show-copying") {
       system("cat " nosql_install "/doc/COPYING")
       exit(rc=1)
    }
    else if (ARGV[i] == "--show-warranty") {
       system("cat " nosql_install "/doc/WARRANTY")
       exit(rc=1)
    }
    else if (ARGV[i] !~ /^-/) table = ARGV[i]
  }

  ARGC = 1					# Fix argv[]

  if (o_file == NULL) o_file = stdout
  if (i_file != NULL) { ARGV[1] = i_file; ARGC = 2 }

  if (table == "") {
     print "usage: slapdtonbl [options] table" > stderr
     exit(rc=1)
  }
}

# Main loop.

NR == 1 {
   if ($0 != "SEARCH") {
      print "slapdtonbl: unsupported input message format" > "/dev/stderr"
      exit(rc=1)
   }
}

$1 == "suffix:"		{ slapd[$1] = substr($0,9);  slapd[0]++ }

$1 == "base:"		{ slapd[$1] = substr($0,7);  slapd[0]++ }

$1 == "scope:"		{ slapd[$1] = substr($0,8);  slapd[0]++ }

$1 == "deref:"		{ slapd[$1] = substr($0,8);  slapd[0]++ }

$1 == "sizelimit:"	{ slapd[$1] = substr($0,12); slapd[0]++ }

$1 == "filter:"		{ slapd[$1] = substr($0,9);  slapd[0]++ }

$1 == "attrs:"		{ slapd[$1] = substr($0,8);  slapd[0]++ }

END {
  if (rc) exit(rc)

  if (slapd["filter:"] == "" || slapd["base:"] == "") {
     print "slapdtonbl: unsupported input message format" > "/dev/stderr"
     exit(rc=1)
  }

  # Only allow queries against the LDAP domain we are authoritative for.

  if (slapd["suffix:"] == "") {
     print "slapdtonbl: unauthorized LDAP domain specified" > "/dev/stderr"
     exit(rc=1)
  }

  # Only allow queries with "scope sub" (see slapd-meta(5) for more).

  if (slapd["scope:"] != "2") {
     print "slapdtonbl: unsupported LDAP query scope" > "/dev/stderr"
     exit(rc=1)
  }

  # Only allow queries having "deref: 0".

  if (slapd["deref:"] != "0") {
     print "slapdtonbl: unsupported LDAP query deref value" > "/dev/stderr"
     exit(rc=1)
  }

  if (slapd["sizelimit:"] == "") slapd["sizelimit:"] = "unlimited"

  if (slapd["sizelimit:"] != "-1" && slapd["sizelimit:"] != "unlimited")
		  print "sizelimit " (slapd["sizelimit:"] /= 1) > o_file
  print "read " table > o_file

  print "ldap",slapd["suffix:"],slapd["filter:"] > o_file

  # Make sure the 'dn' and 'cn' columns are always output in said order,
  # and that they are output first. If only the 'dn' column is always
  # output, slapd(8) may crash on queries returning records having only
  # the 'dn' data. Fortunately, slapd(8) suppresses the 'cn' column on
  # output, unless it is explicitly listed in the query output attribute
  # list.

  if (slapd["attrs:"] != "" && slapd["attrs:"] != "all") {

     slapd["attrs:"] = tolower(slapd["attrs:"])

     # Remove any misplaced references to 'dn'.
     gsub(/[ \t]+[Dd][Nn][ \t]+/," ",slapd["attrs:"])
     sub(/^[Dd][Nn][ \t]+/,"",slapd["attrs:"])
     sub(/[ \t][Dd][Nn]$/,"",slapd["attrs:"])

     # Remove any misplaced references to 'cn'.
     gsub(/[ \t]+[Cc][Nn][ \t]+/," ",slapd["attrs:"])
     sub(/^[Cc][Nn][ \t]+/,"",slapd["attrs:"])
     sub(/[ \t][Cc][Nn]$/,"",slapd["attrs:"])

     # Output 'dn' and 'cn' first, in due order.
     print "columns dn cn " slapd["attrs:"] > o_file
  }
}

# EOF
