"""
w2lapp.add.py: add an entry

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: add.py,v 1.31 2002/02/26 06:50:54 michael Exp $
"""

import sys,ldap, \
       msbase,ldaputil.base,ldap.modlist, \
       pyweblib.forms,w2lapp.cnf,w2lapp.core,w2lapp.gui, \
       w2lapp.addmodifyform,w2lapp.modify


def ModlistTable(form,ls,modlist):
  """
  Return a string containing a HTML table showing attr type/value pairs
  """
  s = []
  s.append('<table summary="Modify list">')
  for attr_type,attr_value in modlist:
    if attr_type.lower() in w2lapp.core.ldap_binaryattrkeys:
      tablestr = '%s bytes of binary data' % (
        ' + '.join(
          [ str(len(x)) for x in attr_value ]
        )
      )
    else:
      tablestr = '<br>'.join([
        pyweblib.forms.escapeHTML(repr(v))
        for v in attr_value
      ])
    s.append('<tr><td>%s</td><td>%s</td></tr>' % (
      w2lapp.gui.AttrNameStr(attr_type),
      tablestr
    )
  )
  s.append('</table>')
  return '\n'.join(s) # ModlistTable()


########################################################################
# Add new entry
########################################################################

def w2l_Add(sid,outf,command,form,ls,dn):

  # Look for configured naming rules for RDNs
  new_rdn_attrtype,default_objectclasses,dit_immutable = w2lapp.cnf.GetParam(
    ls,'dit',{}
  ).get(
    dn,('',[],0)
  )

  entry = w2lapp.modify.GetEntryfromInputForm(form,ls,dn,discard_empty_values=1)

  # Final check if object classes were defined in entry data
  if not entry.has_key('objectClass'):
    raise w2lapp.core.ErrorExitClass(ls,dn,'No object class(es) defined.')

  rdn = ''

  # Try to get the RDN from the user's input.
  # If add_rdn does not contain a complete RDN try to determine
  # the attribute type for forming the RDN.
  if not dit_immutable and \
     ('add_rdn' in form.inputFieldNames) and \
     form.field['add_rdn'].value[0]:
    rdn = form.field['add_rdn'].value[0].strip()
    if ldaputil.base.is_dn(rdn):
      new_rdn_attrtype = None
    else:
      # Check for attrtype= format
      try:
        new_rdn_attrtype,value = rdn.split('=',1)
      except ValueError:
        new_rdn_attrtype = None
      else:
        if value:
          new_rdn_attrtype = None
      if new_rdn_attrtype is None:
        w2lapp.addmodifyform.w2l_AddModifyForm(
          sid,outf,'addform',form,ls,dn,
          Msg='<p>Wrong format of RDN string.</p>',
          rdn_default=rdn,
          entry=entry,
        )
        return

  # Try to define complete RDN if 
  if new_rdn_attrtype:
    new_rdn_attrtype = new_rdn_attrtype.strip()
    if entry.has_key(new_rdn_attrtype) and entry[new_rdn_attrtype]:
      new_rdn_attrvalue = entry[new_rdn_attrtype][0]
      if type(new_rdn_attrvalue)==type(''):
        new_rdn_attrvalue = ldaputil.base.escape_dn_chars(
          unicode(new_rdn_attrvalue,ls.charset)
        )
      rdn = '%s=%s' % (new_rdn_attrtype,new_rdn_attrvalue)
    else:
      w2lapp.addmodifyform.w2l_AddModifyForm(
        sid,outf,'addform',form,ls,dn,
        Msg='<p>Attribute value for <strong>%s</strong> required for default RDN not in entry data.</p>' % (new_rdn_attrtype),
        rdn_default=new_rdn_attrtype+'=',
        entry=entry,
      )
      return

  if not rdn:
    w2lapp.addmodifyform.w2l_AddModifyForm(
      sid,outf,'addform',form,ls,dn,
      Msg='<p>Unable to determine new RDN.</p>',
      rdn_default='',
      entry=entry,
    )
    return

  # Modify-Liste zumsammenbauen
  modlist = ldap.modlist.addModlist(entry)

  if not modlist:
    raise w2lapp.core.ErrorExitClass(
      ls,dn,'Cannot add entry without attribute values.'
    )

  if dn:
    new_dn = ','.join([rdn,dn])
  else:
    # Makes it possible to add entries for a namingContext
    new_dn = rdn

  # Add new entry
  try:
    ls.addEntry(new_dn,modlist)
  except ldap.NO_SUCH_OBJECT,e:
    parent_dn = ldaputil.base.ParentDN(new_dn)
    missing_parentdns = []
    while parent_dn.lower():
      try:
        parent_entry = ls.getAttributeTypes(parent_dn)
      except ldap.NO_SUCH_OBJECT:
        missing_parentdns.append(parent_dn)
      parent_dn = ldaputil.base.ParentDN(parent_dn)
    if missing_parentdns:
      w2lapp.gui.TopSection(
        sid,outf,form,ls,dn,
        'Error adding new entry',
        w2lapp.gui.MainMenu(sid,form,ls,dn),
        context_menu_list=[]
      )
      outf.write("""<div id="ErrorMessageDiv">
        <h1>Error</h1>
        <p>No such object: The entry %s was not correctly added.</p>
        Missing parent entries:
        <table>""" % (
          w2lapp.gui.DisplayDN(sid,form,ls,new_dn)
        )
      )
      for parent_dn in missing_parentdns:
        rdn,dn = ldaputil.base.SplitRDN(parent_dn)
        outf.write('<tr><td>%s</td><td>%s</td></tr>' % (
	    parent_dn,
	    w2lapp.gui.W2L_Anchor(
	      form,'addform','Create entry',sid,
              [('dn',dn),('add_rdn',rdn)],
              target='_inputform'
            )
          )
        )
      outf.write('</table></div>')
      w2lapp.gui.PrintFooter(outf,form)
      return
    else:
      raise e
  except ( ldap.ALREADY_EXISTS,ldap.OBJECT_CLASS_VIOLATION,
           ldap.UNDEFINED_TYPE,ldap.INVALID_SYNTAX,ldap.NAMING_VIOLATION,
           ldap.TYPE_OR_VALUE_EXISTS,ldap.CONSTRAINT_VIOLATION ),e:
    w2lapp.addmodifyform.w2l_AddModifyForm(
      sid,outf,'addform',form,ls,dn,
      Msg=w2lapp.gui.LDAPError2ErrMsg(e),
      rdn_default=rdn,
      entry=entry
    )
  else:
    w2lapp.gui.SimpleMessage(
      sid,outf,form,ls,dn,
      'Added Entry',
      'Added entry %s with your input data:\n%s' % (
        w2lapp.gui.DisplayDN(sid,form,ls,new_dn,commandbutton=1),
        ModlistTable(form,ls,modlist)
      ),
      main_menu_list=w2lapp.gui.MainMenu(sid,form,ls,dn),
      context_menu_list=[]
    )
