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

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


def GetEntryfromInputForm(form,ls,dn,default_oc=[],discard_empty_values=1):

  e = msbase.CaseinsensitiveStringKeyDict({})

  try:
    in_ldif = form.field['in_ldif'].getLDIFRecords()
  except ValueError,e:
    raise w2lapp.core.ErrorExitClass(ls,dn,'LDIF parsing error: '+str(e))
  else:
    if in_ldif:
      e.update(in_ldif[0][1])

  ldap_oc = [
    oc.encode('ascii')
    for oc in form.getInputValue('ldap_oc',default_oc)
  ]
  # Determine object classes of new entry
  if e.has_key('objectClass'):
    e['objectClass'] = msbase.union(e['objectClass'],ldap_oc,ignorecase=1)
  else:
    e['objectClass'] = ldap_oc

  in_attrtype_list = [
    a.encode('ascii')
    for a in form.getInputValue('in_attrtype',[])
  ]
  in_value_list = [
    a.encode(ls.charset)
    for a in form.getInputValue('in_value',[])
  ]
  if len(in_attrtype_list)!=len(in_value_list):
    raise w2lapp.core.ErrorExitClass(
      ls,dn,'Different count of attribute types and values.'
    )
  for i in range(len(in_attrtype_list)):
    attr_type = in_attrtype_list[i]
    attr_value = in_value_list[i]
    if attr_type:
      if e.has_key(attr_type):
	e[attr_type].append(attr_value)
      else:
  	e[attr_type] = [attr_value]

  e = msbase.CaseinsensitiveStringKeyDict(ldaputil.base.sanitize_entry(e))

  if discard_empty_values:
    for attr_type in e.keys():
      e[attr_type]=filter(None,e[attr_type])
    if not e[attr_type]:
      del e[attr_type]

  return e # GetEntryfromInputForm()


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


##############################################################################
# Modify existing entry
##############################################################################

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

  # Retrieve all attribute types
  existing_attrs = ls.getAttributeTypes(dn)
  # Remove the hidden and binary attribute types
  existing_attrs = msbase.listremove(
    existing_attrs,
    w2lapp.cnf.GetParam(ls,'hiddenattrs',[])+w2lapp.core.ldap_binaryattrkeys,
    ignorecase=1
  )
  # Read modifiable attributes of entry
  result_dnlist = ls.readEntry(dn,existing_attrs,no_cache=1)
  if not result_dnlist:
    raise w2lapp.core.ErrorExitClass(ls,dn,"""
      No search result when reading entry <strong>%s</strong>.""" % (
        w2lapp.gui.DisplayDN(sid,form,ls,dn)
      )
    )

  old_entry = result_dnlist[0][1]
  old_objectclasses = old_entry.get('objectClass',old_entry.get('objectclass',[]))

  new_entry = GetEntryfromInputForm(
    form,ls,dn,old_objectclasses,discard_empty_values=0
  )

  modlist = ldap.modlist.modifyModlist(
    old_entry,new_entry,
    ignore_oldexistent=1,
  )

  if modlist:
    # Send modify-list to host
    try:
      ls.modifyEntry(dn,modlist)
    except ( ldap.OBJECT_CLASS_VIOLATION,
             ldap.TYPE_OR_VALUE_EXISTS,
             ldap.UNDEFINED_TYPE,
             ldap.INVALID_SYNTAX,
             ldap.CONSTRAINT_VIOLATION ),e:
      w2lapp.addmodifyform.w2l_AddModifyForm(
        sid,outf,command+'form',form,ls,dn,
        Msg=w2lapp.gui.LDAPError2ErrMsg(e),
        entry=new_entry,
      )
      return
    else:
      # delete all cache entries referencing to old DN
      UserMsg = 'Modified entry %s with your input data:</p>\n%s' % (
        w2lapp.gui.DisplayDN(sid,form,ls,dn),
        ModlistTable(form,ls,modlist).encode(form.accept_charset)
      )
  else:
    UserMsg = 'No attributes modified of entry %s.' % (w2lapp.gui.DisplayDN(sid,form,ls,dn))

  # Output comes here
  w2lapp.gui.SimpleMessage(
    sid,outf,form,ls,dn,
    'Modify result',
    UserMsg,
    main_menu_list=w2lapp.gui.MainMenu(sid,form,ls,dn),
    context_menu_list=w2lapp.gui.ContextMenuSingleEntry(sid,form,ls,dn)
  )

