"""
w2lapp.handler.py: base handler

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: handler.py,v 1.96 2002/03/01 12:07:07 michael Exp $
"""

import sys,os,types,socket,msgzip,\
       ldap,ldaputil.base,ldapdns,ldapsession, \
       pyweblib.forms,pyweblib.httphelper,pyweblib.sslenv,pyweblib.helper,pyweblib.session

# Import the application modules
import w2lapp.core,w2lapp.gui,w2lapp.cnf, \
       w2lapp.passwd,w2lapp.searchform,w2lapp.locate, \
       w2lapp.search,w2lapp.addmodifyform,w2lapp.add, \
       w2lapp.modify,w2lapp.delete, \
       w2lapp.read,w2lapp.conninfo,w2lapp.login,w2lapp.connect, \
       w2lapp.referral,w2lapp.monitor,w2lapp.groupadm,w2lapp.rename

from ldapurl import LDAPUrl,isLDAPUrl
from w2lapp.core import utf2display

def CheckRequiredSecLevel(ls,env):
  required_ssl_level = w2lapp.cnf.GetParam(ls,'ssl_minlevel',0)
  current_ssl_level = pyweblib.sslenv.SecLevel(
    env,
    w2lapp.cnf.misc.sec_sslacceptedciphers,
    w2lapp.cnf.GetParam(ls,'ssl_valid_dn',''),
    w2lapp.cnf.GetParam(ls,'ssl_valid_idn','')
  )
  if current_ssl_level < required_ssl_level:
    raise w2lapp.core.ErrorExitClass(
      ls,None,
      'Access denied. SSL security level %d not sufficient. Must be at least %d.' % (
        current_ssl_level,required_ssl_level
      )
    )


def InitializeForm(command,inf,env):
  """
  Return an instantiated pyweblib.forms.formClass object
  depending on command
  """
  form = pyweblib.forms.Form(inf,env)
  form.accept_charset = DetermineCharset(form)
  form.addField(pyweblib.forms.Input('who',u'Bind DN',255,1,u'.*',size=40))
  form.addField(pyweblib.forms.Input('cred',u'with Password',200,1,u'.*',size=15))
  form.addField(pyweblib.forms.Input('host',u'Host:Port',255,1,w2lapp.gui.host_pattern,size=30))
  form.addField(w2lapp.gui.DistinguishedNameInput('dn','Distinguished Name'))
  form.addField(w2lapp.gui.DistinguishedNameInput('login_search_root','Login search root'))
  if command=='searchform':
    form.addField(pyweblib.forms.Select('searchform_mode',u'Search form mode',1,options=[(u'base',u'Base'),(u'adv',u'Advanced'),(u'exp',u'Expert')],default=u'base'))
    form.addField(pyweblib.forms.Field('search_params',u'Anzahl Suchangaben',2,1,'[0-9]+'))
    form.addField(w2lapp.gui.DistinguishedNameInput('search_root','Search root'))
    form.addField(
      pyweblib.forms.Select(
        'scope','Scope',1,
        options=[
          (str(ldap.SCOPE_BASE),'Base'),
          (str(ldap.SCOPE_ONELEVEL),'One level'),
          (str(ldap.SCOPE_SUBTREE),'Sub tree')
        ],
        default=str(ldap.SCOPE_SUBTREE)
      )
    )
    form.addField(pyweblib.forms.Input('search_filterstr',u'Search filter string',120,1,'.*'))
    form.addField(
      pyweblib.forms.Select(
        'search_resnumber',
        u'Number of results to display',
        1,
        options=[(u'0',u'unlimited'),(u'10',u'10'),(u'20',u'20'),(u'50',u'50'),(u'100',u'100'),(u'200',u'200')],
        default='10'
      )
    )
  elif command=='search':
    form.addField(pyweblib.forms.Input('search_filterstr',u'Search filter string',120,1,u'.*'))
    form.addField(pyweblib.forms.Input('search_resminindex',u'Minimum index of search results',10,1,u'[0-9]+'))
    form.addField(pyweblib.forms.Input('search_resnumber',u'Number of results to display',3,1,u'[0-9]+'))
    form.addField(pyweblib.forms.Select('search_output',u'Search output format',1,options=[u'table',u'ldif',u'ldif1',u'dsml',u'print']))
    form.addField(pyweblib.forms.Select('search_mode',u'Search Mode',1,options=[ur'(&%s)',ur'(|%s)']))
    form.addField(pyweblib.forms.Select('scope','Scope',1,options=[('0','Base'),('1','One level'),('2','Sub tree')],default='2'))
    form.addField(pyweblib.forms.Input('search_attr',u'Search attribute',250,w2lapp.cnf.misc.max_searchparams,ur'[\w_;-]+'))
    form.addField(pyweblib.forms.Select('search_option',u'Search option',w2lapp.cnf.misc.max_searchparams,options=w2lapp.searchform.search_options))
    form.addField(pyweblib.forms.Input('search_string',u'Search string',60,w2lapp.cnf.misc.max_searchparams,u'.*'))
  elif command in ['addform','modifyform']:
    if command=='addform':
      form.addField(pyweblib.forms.Input('add_rdn','RDN of new entry',255,1,u'.*',size=50))
    form.addField(w2lapp.gui.ObjectClassSelect())
  elif command=='conninfo':
    form.addField(
      pyweblib.forms.Select(
        'ldap_managedsait',u'Manage DSA it mode',1,
        options=[('1','Enabled'),('0','Enabled')],
        default='0'
      )
    )
  elif command=='add':
    form.addField(pyweblib.forms.Input('add_rdn',u'RDN of new entry',255,1,u'.*',size=50))
    form.addField(w2lapp.gui.ObjectClassSelect())
    form.addField(pyweblib.forms.Input('in_attrtype',u'Attribute Type',255,w2lapp.cnf.misc.input_maxattrs,'[\w_;-]*'))
    form.addField(pyweblib.forms.Input('in_value',u'Attribute Value',w2lapp.cnf.misc.input_maxfieldlen,w2lapp.cnf.misc.input_maxattrs,'.*'))
    form.addField(w2lapp.gui.LDIFTextArea('in_ldif',u'LDIF data'))
  elif command=='modify':
    form.addField(w2lapp.gui.ObjectClassSelect())
    form.addField(pyweblib.forms.Input('in_attrtype',u'Attribute Type',255,w2lapp.cnf.misc.input_maxattrs,u'[\w_;-]+'))
    form.addField(pyweblib.forms.Input('in_value',u'Attribute Value',w2lapp.cnf.misc.input_maxfieldlen,w2lapp.cnf.misc.input_maxattrs,'.*'))
    form.addField(w2lapp.gui.LDIFTextArea('in_ldif',u'LDIF data'))
  elif command=='delete':
    form.addField(pyweblib.forms.Select('delete_confirm',u'Confirmation',1,options=['yes','no'],default='no'))
    form.addField(
      pyweblib.forms.Select(
        'scope',u'Mode of delete operation',1,
        options=[
          (str(ldap.SCOPE_BASE),'Only this entry'),
          (str(ldap.SCOPE_ONELEVEL),'All entries below this entry (recursive)'),
          (str(ldap.SCOPE_SUBTREE),'All entries including this entry (recursive)'),
        ],
        default='0'
      )
    )
    form.addField(pyweblib.forms.Input('delete_attr',u'Attribute to be deleted',255,100,u'[\w_;-]+'))
  elif command=='rename':
    form.addField(pyweblib.forms.Input('rename_newrdn',u'New RDN',255,1,ldaputil.base.rdn_pattern,size=50))
    form.addField(w2lapp.gui.DistinguishedNameInput('rename_newsuperior','New Superior DN'))
    form.addField(pyweblib.forms.Checkbox('rename_delold',u'Delete old',1,default="yes",checked=1))
  elif command=='passwd':
    form.addField(w2lapp.gui.DistinguishedNameInput('passwd_who',u'Password DN'))
    form.addField(pyweblib.forms.Field('passwd_newpasswd',u'New password',100,2,'.*'))
    form.addField(pyweblib.forms.Select('passwd_scheme',u'Hash',1,options=w2lapp.passwd.available_hashtypes,default=w2lapp.passwd.available_hashtypes[-1]))
  elif command=='read':
    form.addField(pyweblib.forms.Input('read_attr',u'Read attribute',255,100,u'[\w_;-]+'))
    form.addField(pyweblib.forms.Select('read_attrmode',u'Read attribute',1,options=[u'view',u'load']))
    form.addField(pyweblib.forms.Input('read_attrindex',u'Read attribute',255,1,u'[0-9]+'))
    form.addField(pyweblib.forms.Input('read_attrmimetype',u'MIME type',255,1,u'[\w.-]+/[\w.-]+'))
    form.addField(pyweblib.forms.Select('read_output',u'Read output format',1,options=['table','vcard','template'],default='template'))
  elif command=='groupadm':
    form.addField(w2lapp.gui.DistinguishedNameInput('groupadm_add','Add to group',300))
    form.addField(w2lapp.gui.DistinguishedNameInput('groupadm_remove','Remove from group',300))
  elif command=='login':
    form.addField(w2lapp.gui.DistinguishedNameInput('login_who',u'Bind DN'))
  elif command=='locate':
    form.addField(
      pyweblib.forms.Input(
        'locate_name',
        u'Location name',
        255,1,
        u'(%s|%s|%s)' % (
          w2lapp.gui.mail_pattern[1:-1],
          w2lapp.gui.host_pattern,
          ldaputil.base.dn_pattern
        ),
        size=25
      )
    )
  return form

def CommandDispatcher(sid,outf,command,form,ldapUrl,ls,env):
  """Execute function for command"""
  dn = ldapUrl.dn
  if command=='searchform':
    w2lapp.searchform.w2l_SearchForm(sid,outf,command,form,ls,dn)
  elif command=='search':
    w2lapp.search.w2l_Search(
      sid,outf,command,form,ls,dn,
      scope=ldapUrl.scope,
      search_filterstr=ldapUrl.filterstr,
    )
  elif command=='addform' or command=='modifyform':
    w2lapp.addmodifyform.w2l_AddModifyForm(sid,outf,command,form,ls,dn)
  elif command=='add':
    w2lapp.add.w2l_Add(sid,outf,command,form,ls,dn)
  elif command=='modify':
    w2lapp.modify.w2l_Modify(sid,outf,command,form,ls,dn)
  elif command=='delete':
    w2lapp.delete.w2l_Delete(sid,outf,command,form,ls,dn)
  elif command=='rename':
    w2lapp.rename.w2l_Rename(sid,outf,command,form,ls,dn)
  elif command=='passwd':
    w2lapp.passwd.w2l_Passwd(sid,outf,command,form,ls,dn)
  elif command=='read':
    w2lapp.read.w2l_Read(
      sid,outf,command,form,ls,dn,wanted_attrs=ldapUrl.attrs,
    )
  elif command=='conninfo':
    w2lapp.conninfo.w2l_ConnInfo(sid,outf,command,form,ls,dn,env)
  elif command=='login':
    w2lapp.login.w2l_Login(sid,outf,'searchform',form,ls,dn)
  elif command=='groupadm':
    w2lapp.groupadm.w2l_GroupAdm(sid,outf,command,form,ls,dn)
  else:
    raise w2lapp.core.ErrorExitClass(
      ls,dn,'Invalid web2ldap command <strong>%s</strong>!' % (command)
    )
  return # CommandDispatcher()


def OutFileObject(outfile,form):
  """
  Create file object for gziping on-the-fly if configuration
  and HTTP header allows it
  """
  if w2lapp.cnf.misc.gzip_level>0:
    if form.http_accept_encoding['gzip']>0:
      if msgzip.GzipFile:
        # Create new gzip-stream file object
        return msgzip.GzipFile(
          filename='web2ldap output',
          mode='wb',
          compresslevel=w2lapp.cnf.misc.gzip_level,
          fileobj=outfile
        )
      else:
        return outfile
    else:
      return outfile
  else:
    return outfile


def DetermineCharset(form):
  if w2lapp.cnf.misc.print_rawutf8==2:
    c = 'utf-8'
  elif w2lapp.cnf.misc.print_rawutf8==1:
    if form.http_accept_charset['utf-8']:
      c = 'utf-8'
    else:
      c = form.http_accept_charset.preferred()
  else:
    c = 'iso-8859-1'
  return c

def ExtractPathInfo(env):
  # Extract the command from PATH_INFO env var
  path_info = env.get('PATH_INFO','')[1:]
  if not path_info:
    return '',''
  else:
    try:
      c,s = path_info.split('/',1)
    except ValueError:
      c,s = path_info,''
    if c=='ldapurl': c=''
    return c,s


def HandleHTTPRequest(
  inf=sys.stdin,
  outfile=sys.stdout,
  errfile=sys.stderr,
  env=os.environ
):

  ####################################################
  # Main try-except block for catching and logging
  # all unhandled exceptions
  ####################################################

  ls = ldapsession.LDAPSession()

  try:

    command,sid = ExtractPathInfo(env)

    if command=='urlredirect':
      # URL redirecting has absolutely nothing to do with rest
      pyweblib.httphelper.URLRedirect(outfile,env.get('QUERY_STRING',''))
      return

    form = InitializeForm(command,inf,env)

    outf = OutFileObject(outfile,form)

    if command=='monitor':
      # Output simple monitor page. Does not require session handling.
      w2lapp.monitor.w2l_Monitor(outf,command,form)
      return

    if command=='':
      # New connect => create new session, remove old if necessary
      w2lapp.core.session.deleteSession(sid)
      sid = ''

      ####################################################
      # Restore old or initialize new web session object
      ####################################################

    ####################################################
    # try-except block for gracefully handling of
    # certain exceptions (mainly ldap.LDAPError)
    ####################################################

    try:

      if sid:
        # Try to retrieve old session
        try:
          ls = w2lapp.core.session.retrieveSession(sid,env)
        except pyweblib.session.SessionExpired,e:
          # Handle expired sessions
          form.getInputFields(ignoreEmptyFields=0)
          if hasattr(e.session_data,'host'):
            # Allow to relogin
            sid = w2lapp.core.session.newSession(env)
            ls = e.session_data ; ls.cred = ''
            w2lapp.login.w2l_Login(
              sid,outf,command,form,ls,
              dn=form.getInputValue('dn',[ls._dn])[0],
              login_msg=str(e),
              who=ls.__dict__.get('who',''),
              relogin=1,nomenu=1
            )
          else:
            pyweblib.httphelper.URLRedirect(outf,form.script_name,2,'Session invalid and expired.')
          return
        except pyweblib.session.KeyError:
          pyweblib.httphelper.URLRedirect(outf,form.script_name,2,'Session ID not found.')
          return
        except pyweblib.session.SessionHijacked,e:
          pyweblib.httphelper.URLRedirect(
            outf,form.script_name,2,'Session hijacking detected. Access denied!'
          )
          return
      else:
        # Create new session
        sid = w2lapp.core.session.newSession(env)
        ls = ldapsession.LDAPSession(
          on_behalf=env.get('REMOTE_HOST',env.get('REMOTE_ADDR',None)),
          traceLevel=w2lapp.cnf.misc.ldap_trace_level,traceFile=errfile
        )

      if isLDAPUrl(form.query_string):
        # Extract the connection parameters from a LDAP URL
        try:
          ldapUrl = LDAPUrl(form.query_string)
        except ValueError,e:
          raise w2lapp.core.ErrorExitClass(ls,None,'Error parsing LDAP URL: %s.' % (str(e)))

      else:
        # Extract the connection parameters from form fields
        form.getInputFields(ignoreEmptyFields=0)
        if command=='':
          # Just output a connect form
          w2lapp.connect.w2l_Connect(outf,command,form,ls)
          return
        if command=='locate':
          w2lapp.locate.w2l_Locate(outf,command,form)
          return

        if 'ldapurl' in form.inputFieldNames:
          # One form parameter with LDAP URL
          try:
            ldapUrl = LDAPUrl(form.field['ldapurl'][0])
          except ValueError,e:
            raise w2lapp.core.ErrorExitClass(ls,dn,'Error parsing LDAP URL: %s.' % (str(e)))
        else:
          # Separate parameters for host, dn, who, cred and scope
          host=form.getInputValue('host',[None])[0]
          dn=form.getInputValue('dn',[None])[0]
          who=form.getInputValue('who',[None])[0]
          cred=form.getInputValue('cred',[None])[0]
          scope_str=form.getInputValue('scope',[str(ldap.SCOPE_BASE)])[0]
          if scope_str: scope=int(scope_str)
          else: scope=ldap.SCOPE_BASE
          del scope_str
          ldapUrl = None

      if ldapUrl!=None:
        command = {0:'search',1:'read'}[ldapUrl.scope==ldap.SCOPE_BASE]
        host = ldapUrl.hostport
        dn = ldapUrl.dn
        who = ldapUrl.who
        cred = ldapUrl.cred
        scope = ldapUrl.scope

      dn = ldaputil.base.normalize_dn(dn)

      ####################################################
      # Connect to LDAP host
      ####################################################

      if not host and not hasattr(ls,'host'):
        # Force a SRV RR lookup for dc-style DNs
        host = ldapdns.dcDNSLookup(dn)
      if not host and not hasattr(ls,'host'):
        pyweblib.httphelper.URLRedirect(
          outf,form.script_name,2,'No host specified.'
        )
        return
      if host and (not hasattr(ls,'host') or host!=ls.host):
        # Connect to new specified host
        del ls
        ls = ldapsession.LDAPSession(
          on_behalf=env.get('REMOTE_HOST',env.get('REMOTE_ADDR',None)),
          traceLevel=w2lapp.cnf.misc.ldap_trace_level,traceFile=errfile
        )
        ls.open(host,startTLS=0)
        ls._startTLS(startTLS=w2lapp.cnf.GetParam(ls,'starttls',ldapsession.START_TLS_NO))
        ls.l.set_option(ldap.OPT_DEREF,0);
        ls.l.set_option(ldap.OPT_REFERRALS,0)
        ls.timeout = w2lapp.cnf.GetParam(ls,'timeout',-1)
        ls.getRootDSE()
        ls.setDN(dn)
        # Search and set backend specific timeout
        ls.timeout = w2lapp.cnf.GetParam(ls,'timeout',-1)
        # Search and set backend specific cache options
        ls.setCache(
          w2lapp.cnf.GetParam(ls,'cache_timeout',0),
          w2lapp.cnf.GetParam(ls,'cache_maxmem',0),
        )

      ####################################################
      # Bind to LDAP host
      ####################################################

      if who!=None:
        if cred!=None:
          if cred=='': who=''
          loginSearchRoot = form.getInputValue('login_search_root',[None])[0]
          try:
            try:
              ls.bind(
                who,cred,
                filtertemplate=w2lapp.cnf.GetParam(ls,'binddnsearch','(uid=%s)'),
                loginSearchRoot = loginSearchRoot
              )
            finally:
              del cred
          except ldap.NO_SUCH_OBJECT,e:
            w2lapp.login.w2l_Login(
              sid,outf,command,form,ls,dn,
              login_msg=w2lapp.gui.LDAPError2ErrMsg(e),
              who=who,relogin=1
            )
            return
        else:
          w2lapp.login.w2l_Login(
            sid,outf,command,form,ls,dn,
            login_msg='',
            who=who,relogin=1,nomenu=1
          )
          return

      ls.setDN(dn);

      if not hasattr(ls,'l'):
        pyweblib.httphelper.URLRedirect(
          outf,form.script_name,2,'No valid LDAP connection instance.'
        )
        return

      # Store session data the first time
      w2lapp.core.session.storeSession(sid,ls)

      # Check backend specific required SSL level
      CheckRequiredSecLevel(ls,env)

      if ldapUrl is None:
        ldapUrl = LDAPUrl(
          hostport=ls.host,dn=dn,who=ls.__dict__.get('who',None),scope=scope
        )

      # Execute the command module
      try:
        CommandDispatcher(sid,outf,command,form,ldapUrl,ls,env)
      finally:
        # Once again clean up to avoid circular references
        del ldapUrl

    except pyweblib.forms.FormException,e:
      dn=form.getInputValue('dn',[ls.__dict__.get('dn',None)])[0]
      w2lapp.gui.ExceptionMsg(sid,outf,form,ls,dn,'Error parsing form','Error parsing form: %s.' % (e.html()))

    except ldap.NO_SUCH_OBJECT,e:

      #########################################
      # Generic handler for "No such object"
      #########################################

      host_list = ldapdns.dcDNSLookup(dn)
      if (not host_list) or (ls.host in host_list):
        # Did not find LDAP server for this naming context
        try:
          if type(e.args[0])==types.DictType:
            new_dn = e.args[0].get('matched',ls._dn)
        except IndexError:
          new_dn = dn
        w2lapp.gui.ExceptionMsg(
          sid,outf,form,ls,new_dn,'No such object',
          '<br>'.join([
            w2lapp.gui.LDAPError2ErrMsg(e),
            w2lapp.gui.DisplayDN(sid,form,ls,dn),
          ])
        )
      else:
        # Found LDAP server for this naming context via DNS SRV RR
        w2lapp.gui.TopSection(
          sid,outf,form,ls,dn,
          'LDAP server located via DNS',
          w2lapp.gui.MainMenu(sid,form,ls,dn),
          context_menu_list=[]
        )
        host_select_field = pyweblib.forms.Select(
          'host','Host selection',1,options=host_list,default=host_list[0],ignoreCase=1
        )
        outf.write("""
          <div id="InputDiv">
            <h1>Entry located via DNS</h1>
            <form
              id=CommandForm
              action="%s/%s/%s"
              method="POST"
              enctype="application/x-www-form-urlencoded"
              accept-charset="%s"
            >
              <input type="hidden" name="dn" value="%s">
              %s might be located on different host:
              <p>%s</p>
              %s
              <input type="submit" value="Redirect">
            </form>
          </div>
          """  % (
            form.script_name,
            command,
            sid,
            form.accept_charset,
            utf2display(form.accept_charset,dn),
            utf2display(form.accept_charset,dn),
            host_select_field.inputHTML(),
            w2lapp.gui.BindInput % (
              '','','',''
              '',
              'Change host',
            ),
          )
        )
        form.hiddenInputFields(outf,['host','dn','who','cred'])
        outf.write('</form></div>\n')
        w2lapp.gui.PrintFooter(outf,form)

    except (ldap.PARTIAL_RESULTS,ldap.REFERRAL),e:
      w2lapp.referral.w2l_ChaseReferral(sid,outf,command,form,ls,dn,e)

    except ldap.INSUFFICIENT_ACCESS,e:
      w2lapp.login.w2l_Login(
        sid,outf,command,form,ls,dn,who='',
        login_msg=w2lapp.gui.LDAPError2ErrMsg(e),relogin=1
      )

    except ldap.INAPPROPRIATE_AUTH,e:
      w2lapp.login.w2l_Login(
        sid,outf,command,form,ls,dn,who='',
        login_msg=w2lapp.gui.LDAPError2ErrMsg(e),relogin=1
      )
    except ldap.INVALID_CREDENTIALS,e:
      if who is None:
        who=ls.__dict__.get('who','')
      w2lapp.login.w2l_Login(
        sid,outf,command,form,ls,dn,
        login_msg=w2lapp.gui.LDAPError2ErrMsg(e),
        who=who,relogin=1
      )
    except ldap.SERVER_DOWN,e:
      if hasattr(ls,'who'):
        # Try to re-establish an old connection
        host=ls.host
        who=ls.__dict__.get('who','')
        ls.unbind(); del ls
        ls = ldapsession.LDAPSession(
          on_behalf=env.get('REMOTE_HOST',env.get('REMOTE_ADDR',None)),
          traceLevel=w2lapp.cnf.misc.ldap_trace_level,traceFile=errfile
        )
        try:
          # Try to reconnect
          ls.host = host
          ls.open(
            host,
            startTLS=ls.__dict__.get(
              'startedTLS',
              w2lapp.cnf.GetParam(ls,'starttls',ldapsession.START_TLS_NO)
            )
          )
        except ldap.LDAPError,e:
          # Reconnecting impossible => new login
          pyweblib.httphelper.URLRedirect(
            outf,form.script_name,2,
            'Reconnecting to host %s impossible.' % (host)
          )
        else:
          # Reconnecting was possible => new connect
          ls.l.set_option(ldap.OPT_DEREF,0);
          ls.l.set_option(ldap.OPT_REFERRALS,0)
          ls.setDN(dn)
          w2lapp.login.w2l_Login(
            sid,outf,command,form,ls,dn,
            login_msg='Connection to LDAP host %s invalid. Retry with new login.' % (ls.host.encode('ascii')),
            who=who,relogin=1,nomenu=1
          )
      else:
        # Reconnecting impossible => new login
        pyweblib.httphelper.URLRedirect(
          outf,form.script_name,2,
          'Connecting to host %s impossible.' % (host)
        )
    except ldaputil.base.USERNAME_NOT_FOUND,e:
      w2lapp.login.w2l_Login(sid,outf,command,form,ls,dn,login_msg=w2lapp.gui.LDAPError2ErrMsg(e),who=who,relogin=1)
    except ldaputil.base.USERNAME_NOT_UNIQUE,e:
      w2lapp.login.w2l_Login(sid,outf,command,form,ls,dn,login_msg=w2lapp.gui.LDAPError2ErrMsg(e),who=who,relogin=1)

    except ldap.LDAPError,e:
      if __debug__:
        w2lapp.core.log_exception(errfile,sid,command,form,ls,env)
      if not vars().has_key('ls'):
        ls = ldapsession.LDAPSession(
          on_behalf=env.get('REMOTE_HOST',env.get('REMOTE_ADDR',None)),
          traceLevel=w2lapp.cnf.misc.ldap_trace_level,traceFile=errfile
        )
      ErrMsg = w2lapp.gui.LDAPError2ErrMsg(e)
      w2lapp.gui.ExceptionMsg(sid,outf,form,ls,dn,'LDAP exception',ErrMsg)

    except socket.error,e:
      w2lapp.gui.ExceptionMsg(sid,outf,form,None,None,'Socket Error',str(e))

#    except IOError,e:
#      w2lapp.gui.ExceptionMsg(sid,outf,form,ls,dn,'I/O Error',str(e))

    except w2lapp.core.ErrorExitClass,e:
      w2lapp.gui.ExceptionMsg(sid,outf,form,e.ls,e.dn,'Error',e.Msg)

    w2lapp.core.session.storeSession(sid,ls)

  except:
    # Log unhandled exceptions
    w2lapp.core.log_exception(errfile,sid,command,form,ls,env)

  return # HandleHTTPRequest()
