# -*- ruby -*-
# $Id: schema.rb,v 1.2 2002/11/18 01:59:56 ttate Exp $

module LDAP
  class Schema < Hash
    def initialize(entry)
      if( entry )
	entry.each{|key,vals|
	  self[key] = vals
	}
      end
    end

    def names(key)
      self[key].collect{|val| val =~ /NAME\s+'([\w\d]+)'/; $1}
    end

    def attr(oc,at)
      self['objectClasses'].each{|s|
	if( s =~ /NAME\s+'#{oc}'/ )
	  case s
	  when /#{at}\s+\(([\w\d\s\$]+)\)/i
	    return $1.split("$").collect{|attr| attr.strip}
	  when /#{at}\s+([\w\d]+)/i
	    return $1.split("$").collect{|attr| attr.strip}
	  end
	end
      }
      return nil
    end

    def must(oc)
      attr(oc, "MUST")
    end

    def may(oc)
      attr(oc, "MAY")
    end

    def sup(oc)
      attr(oc, "SUP")
    end
  end

  class Conn
    def schema(base = nil, attrs = nil, sec = 0, usec = 0)
      attrs ||= [
	'objectClasses',
	'attributeTypes',
	'matchingRules',
	'matchingRuleUse',
	'dITStructureRules',
	'dITContentRules',
	'nameForms',
	'ldapSyntaxes',
      ]
      base ||= root_dse(['subschemaSubentry'], sec, usec)[0]['subschemaSubentry'][0]
      base ||= 'cn=schema'
      ent = search2(base, LDAP_SCOPE_BASE, '(objectClass=subschema)',
		    attrs, false, sec, usec)
      return Schema.new(ent[0])
    end

    def root_dse(attrs = nil, sec = 0, usec = 0)
      attrs ||= [
	'subschemaSubentry',
	'namingContexts',
	'altServer',
	'supportedExtension',
	'supportedControl',
	'supportedSASLMechanisms',
	'supportedLDAPVersion',
      ]

      entries = search2('', LDAP_SCOPE_BASE, '(objectClass=*)',
			attrs, false, sec, usec)
      return entries
    end
  end
end
