########################################################################
# web2ldap
# (c) by Michael Stroeder <michael@stroeder.com>
# Distributed under GNU Public License (GPL)
# web-based LDAP Client, see http://www.web2ldap.de for details
########################################################################

import sys, string,ldap, \
       msbase,cgiforms,ldapbase,w2lcnf,w2lcore,web2ldapcnf,w2lgui
from msbase import listremove

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

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

  def AddListTable(form,modlist):
    stringlist = []
    stringlist.append('<TABLE BORDER RULES=rows CELLSPACING=0 CELLPADDING=2%%>')
    for i in modlist:
      if i[0] in w2lcore.ldap_binaryattrkeys:
        tablestr = '%s Bytes of binary data' % string.join(map(str,map(len,i[1])),'Bytes, ')
      else:
        tablestr = string.join(w2lcore.utf2display(form.accept_charset,i[1]),'<BR>')
      stringlist.append('<TR><TD>%s</TD><TD>%s</TD></TR>' % (
        w2lgui.AttrNameStr(i[0]),
	tablestr
      )
    )
    stringlist.append('</TABLE>')
    return string.join(stringlist,'\n')


  if 'ldap_oc' in form.inputkeys:
    objectclasses = form.field['ldap_oc'][0].content
  else:
    raise w2lcore.ErrorExitClass(ls,'No object class(es) defined.')

  new_rdn_attr,default_objectclasses,dit_immutable = w2lcnf.GetParam(ls,'dit',{}).get(ls.dn,('',[],0))


  entry = msbase.CaseinsensitiveStringKeyDict()

  # Input from LDIF text area?
  if 'input_ldif' in form.inputkeys:
    from StringIO import StringIO
    import ldif
    f = StringIO(form.field['input_ldif'][0].content)
    try:
      ldif_data = ldif.ParseLDIF(f,maxentries=1)
    except ValueError:
      raise w2lcore.ErrorExitClass(ls,'Error parsing LDIF data.')
    else:
      if ldif_data:
        entry.update(ldif_data[0][1])

  if entry.has_key('objectClass'):
    entry['objectClass'].extend(objectclasses)
  else:
    entry['objectClass'] = objectclasses

  if 'input_attr' in form.inputkeys:
    for i in range(len(form.field['input_attr'][0].content)):
      attr = form.field['input_attr'][0].content[i]
      if attr:
	data = form.field['input_data'][0].content[i]
	if data:
	  if entry.has_key(attr):
	    entry[attr].append(data)
	  else:
	    entry[attr] = [data]

  if not dit_immutable and 'ldap_rdn' in form.inputkeys:
    ldap_rdn = form.field['ldap_rdn'][0].content
  else:
    if entry.has_key(new_rdn_attr):
      ldap_rdn='%s=%s' % (new_rdn_attr,entry[new_rdn_attr][0])
    else:
      raise w2lcore.ErrorExitClass(ls,'Required attribute <strong>%s</strong> not in entry data.' % (new_rdn_attr))

  if not ldap_rdn:
    raise w2lcore.ErrorExitClass(ls,'Unable to determine RDN for new entry.')

  if ls.dn:
    ls.dn = string.join([ldap_rdn,ls.dn],',')
  else:
    ls.dn = ldap_rdn

  # Modify-Liste zumsammenbauen
  modlist = ldapbase.add_modifylist(entry)

  if not modlist:
    raise w2lcore.ErrorExitClass(ls,'Cannot add entry without attributes.')

  # Add new entry
  try:
    ls.l.add_s(ls.dn.encode('utf-8'),modlist)
  except ldap.NO_SUCH_OBJECT:
    parent_dn = ldapbase.ParentDN(ls.dn)
    missing_parentdns = []
    while string.lower(parent_dn):
      try:
        parent_entry = ls.l.search_s(
          parent_dn.encode('utf-8'),
          ldap.SCOPE_BASE,
          "(objectclass=*)",
          ['objectclass'],
          w2lcnf.GetParam(ls,'search_attrsonly',1)
        )[0][1].keys()
      except ldap.NO_SUCH_OBJECT:
        missing_parentdns.append(parent_dn)
      parent_dn = ldapbase.ParentDN(parent_dn)
    if missing_parentdns:
      w2lgui.PrintHeader(outf,'Error',form.accept_charset)
      w2lgui.MainMenuTable(outf,form,ls)
      outf.write("""<div id=MessageDiv>
<h1>Error</h1>
<p>No such object: The entry %s was not correctly added.</p>
Missing parent entries:
<table>""" % (w2lgui.DisplayDN(form.accept_charset,ls.dn)))
      for parent_dn in missing_parentdns:
        rdn,dn = ldapbase.SplitRDN(parent_dn)
        outf.write('<tr><td>%s</td><td>%s</td></tr>' % (
	  parent_dn,
	  w2lgui.CommandButton(
	    form,'addform','Create entry',
	    ls.who,
	    ls.cred,
	    ls.host,
	    dn,
	    extrastr='<input type="hidden" name="ldap_rdn" value="%s">' % (w2lcore.utf2display(form.accept_charset,rdn)),target='_inputform'),
	))
      outf.write('</table></div>')
      w2lgui.PrintFooter(outf)
      return
    else:
      raise
  except ldap.ALREADY_EXISTS:
    raise w2lcore.ErrorExitClass(
      ls,'Entry %s already exists. You probably did not define a new (relative) DN.' % (
        w2lgui.DataStr(form,ls,ls.dn,commandbutton=1)
      )
    )
  except ldap.OBJECT_CLASS_VIOLATION:
    raise w2lcore.ErrorExitClass(
      ls,'Object class violation: Maybe a required attribute is missing or some of the given attributes are not allowed.'
    )

  w2lgui.PrintHeader(outf,'',form.accept_charset)
  w2lgui.MainMenuTable(outf,form,ls)
  w2lgui.ContextMenuSingleEntry(outf,form,ls)
  outf.write(
    '<div id=MessageDiv>\n<p>Added entry %s with your input data:</p>\n%s\n</div>\n' % (
      w2lgui.DataStr(form,ls,ls.dn),
      AddListTable(form,modlist)
    )
  )

  w2lgui.PrintFooter(outf)


