"""
w2lapp.locate.py: Try to locate a LDAP host with various methods.

web2ldap - a web-based LDAP Client,
see http://www.web2ldap.de for details

(c) by Michael Stroeder <michael@stroeder.com>

This module is distributed under the terms of the
GPL (GNU GENERAL PUBLIC LICENSE) Version 2
(see http://www.gnu.org/copyleft/gpl.html)

$Id: locate.py,v 1.16 2002/01/10 02:27:07 michael Exp $
"""

import re,socket,ldap

from ldapurl import LDAPUrl

# Modules shipped with web2ldap
import ldaputil.base,ldapdns,w2lapp.core,w2lapp.gui


ldap_hostname_aliases = [
#  'ldap','dsa','x500','ldapdb','nds','openldap'
  'ldap',
]

##############################################################################
# LDAP Service Locator
##############################################################################

LOCATE_NAME_RFC822 = 0
LOCATE_NAME_DCDN   = 1
LOCATE_NAME_DOMAIN = 2

def w2l_Locate(outf,command,form):
  """
  Try to locate a LDAP server in DNS by several heuristics
  """
  # Check if DNS module is present
  if not ldapdns.dns_module_avail:
    raise w2lapp.core.ErrorExitClass(None,None,'Could not import DNS module.')

  # Parse resolv config every time
  w2lapp.gui.PrintHeader(outf,'Locate',form.accept_charset)
  
  locate_name = form.getInputValue('locate_name',[''])[0].strip()
  
  if locate_name:

    # Try to determine the format of the input parameter
    rm = re.match('^%s$' % w2lapp.gui.host_pattern,locate_name,re.I)
    if rm!=None:
      # Use DNS domain directly
      locate_domain = locate_name
      locate_name_type = LOCATE_NAME_DOMAIN
    else:
      rm = re.match(w2lapp.gui.mail_pattern,locate_name,re.I)
      if rm!=None:
        # Use domain part of RFC822 mail address
        locate_domain = locate_name.split('@')[-1]
        locate_name_type = LOCATE_NAME_RFC822
      else:
        rm = ldaputil.base.dn_regex.match(locate_name)
        if rm!=None:
          # Use dc-style LDAP DN
          locate_domain = ldapdns.dcdn2dnsdomain(locate_name)
          locate_name_type = LOCATE_NAME_DCDN
        else:
          locate_domain = locate_name_type = None
          # Parameter not recognized
          outf.write('<div id="ErrorMessageDiv">Could not recognize format of parameter &quot;%s&quot;.</div>\n' % (locate_name))

    if locate_domain:
      dns_list = locate_domain.encode().split('.')

      outf.write('<div id="MessageDiv">\n')

      for dns_index in range(len(dns_list),1,-1):

        dns_name = '.'.join(dns_list[-dns_index:])
        outf.write('<h1>Domain %s</h1>\n' % (dns_name))

        outf.write('<h2>Search for a SRV RR</h2>\n')
        # Search for a SRV RR of dns_name
        srv_result = ldapdns.ldapSRV(dns_name)

        # Display SRV search results
        for priority, weight, port, hostname in srv_result:
          outf.write('<p>Found SRV record: %s:%d (priority %d, weight %d)</p>' % (
              hostname,port,priority,weight,
            )
          )
          try:
            host_address = socket.gethostbyname(dns_name)
          except socket.error:
            outf.write('<p>Did not find IP address for host %s.</p>' % (hostname))
            pass
          else:
            ldap_url = LDAPUrl(
              hostport='%s:%d' % (hostname,port),
              dn=ldapdns.dnsdomain2dcdn(dns_name),
            )
            outf.write("""
              <p>IP address found for host name %s: %s</p>
              <table>
                <tr>
                  <td>%s</td>
                  <td><a href="%s" target="_ldapurl">%s</a></td>
                </tr>
            """ % (
                hostname,
                host_address,
                w2lapp.gui.LDAPURLButton(None,form,None,str(ldap_url)),
                ldap_url.unparse(urlEncode=1),
                ldap_url.unparse(charset=form.accept_charset),
              )
            )

            if locate_name_type==LOCATE_NAME_RFC822:
              ldap_url = LDAPUrl(
                hostport='%s:%d' % (hostname,port),
                dn=ldapdns.dnsdomain2dcdn(dns_name),
                scope=ldap.SCOPE_SUBTREE,
                filterstr='(mail=%s)' % (locate_name),
              )
              outf.write("""    <tr>
            <td>%s</td>
            <td><a href="%s" target="_ldapurl">Search %s</a></td>
          </tr>
      """ % (
                  w2lapp.gui.LDAPURLButton(None,form,None,ldap_url),
                  ldap_url.unparse('utf-8',urlEncode=1),
                  ldap_url.unparse(charset=form.accept_charset),
                )
              )
            outf.write('</table>\n')

        outf.write('<h2>Search for well known aliases</h2>\n')
        # Search for well known aliases of LDAP servers under dns_name
        for alias in ldap_hostname_aliases:
          alias_name = '.'.join([alias,dns_name])
          try:
            host_address = socket.gethostbyname(alias_name)
          except socket.error:
            pass
          else:
            ldap_url = LDAPUrl(
              hostport=alias_name,
              dn=ldapdns.dnsdomain2dcdn(dns_name)
            )
            outf.write("""
      <p>IP address found for host name %s: %s</p>
      <table>
        <tr>
          <td>%s</td>
          <td><a href="%s" target="_ldapurl">%s</a></td>
        </tr>
      </table>
    """ % (
                alias_name,
                host_address,
                w2lapp.gui.LDAPURLButton(None,form,None,ldap_url),
                ldap_url.unparse('utf-8',urlEncode=1),
                ldap_url.unparse(charset=form.accept_charset),
              )
            )
      outf.write('</div>\n')

  outf.write("""
<div id="InputDiv">

  <form 
    action="%s/locate"
    method="GET" 
    enctype="application/x-www-form-urlencoded"
    accept-charset="%s"
  >
    <h2>Locate LDAP host via DNS</h2>
    <p>
      Search for well-known DNS aliases
      of LDAP servers and DNS SRV records in
      a given DNS domain (experimental).
    </p>
    <fieldset title="Locate LDAP host by DNS name or DN.">
      <input type="submit" value="Locate"><br>
      <table>
        <tr>
          <td>
            E-mail address, DNS domain or dc-style DN:
          </td>
          <td>
            <input name="locate_name" size="60">
          </td>
        </tr>
      </table>
    </fieldset>
  </form>

</div>
""" % (
    form.script_name,
    form.accept_charset,
  )
)
    
  w2lapp.gui.PrintFooter(outf,form)
