# -*- coding: utf-8 -*-
"""
w2lapp.form.py: class for web2ldap input form handling

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)
"""

import urllib,codecs,re,ldif,ldapurl,ldap.schema,msgzip,ldaputil.base, \
       pyweblib.forms,ldapsession

import w2lapp.cnf,w2lapp.core,w2lapp.gui,w2lapp.passwd,w2lapp.searchform,w2lapp.ldapparams,w2lapp.session

# OID description dictionary from configuration directory
from ldapoidreg import oid as oid_desc_reg

try:
  from cStringIO import StringIO
except ImportError:
  from StringIO import StringIO


from types import UnicodeType
from pyweblib.forms import escapeHTML


CONNTYPE2URLSCHEME = {
  0:'ldap',
  1:'ldap',
  2:'ldaps',
  3:'ldapi',
}


class Web2LDAPForm(pyweblib.forms.Form):

  def __init__(self,inf,env,script_name=None):
    pyweblib.forms.Form.__init__(self,inf,env)
    self.script_name = script_name or self.script_name
    if env.has_key('HTTP_USER_AGENT'):
      self.browser_type,self.browser_version = pyweblib.helper.BrowserType(env['HTTP_USER_AGENT'])
    else:
      self.browser_type,self.browser_version = None,None
    self.determineCharset()
    self.initializeForm()

  def utf2display(self,value,tab_identiation='',sp_entity='&nbsp;&nbsp;',lf_entity='\n'):
    value = value or u''
    assert type(value)==UnicodeType, TypeError("Type of argument 'value' must be UnicodeType: %s" % repr(value))
    return escapeHTML(self.uc_encode(value,'replace')[0]).replace('\n',lf_entity).replace('\t',tab_identiation).replace('  ',sp_entity)

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

  def determineCharset(self):
    self.accept_charset = 'utf-8'
    form_codec = codecs.lookup(self.accept_charset)
    self.uc_encode,self.uc_decode = form_codec[0],form_codec[1]
    return # determineCharset()

  def initializeForm(self):
    """
    Add the required fields
    """
    self.addGeneralFields()
    self.addCommandFields()

  def addGeneralFields(self):
    self.addField(pyweblib.forms.Input(
      'delsid',
      u'Old SID to be deleted',
      w2lapp.session.session.session_id_len,
      1,
      w2lapp.session.session.session_id_re.pattern
    ))
    self.addField(pyweblib.forms.Input('who',u'Bind DN/AuthcID',1000,1,u'.*',size=40))
    self.addField(pyweblib.forms.Input('cred',u'with Password',200,1,u'.*',size=15))
    self.addField(pyweblib.forms.Select('login_authzid_prefix',u'SASL AuthzID',1,options=[('','- no prefix -'),('u:','user-ID'),('dn:','DN')],default=''))
    self.addField(pyweblib.forms.Input('login_authzid',u'SASL AuthzID',1000,1,u'.*',size=20))
    self.addField(pyweblib.forms.Input('login_realm',u'SASL Realm',1000,1,u'.*',size=20))
    self.addField(AuthMechSelect('login_mech',u'Authentication mechanism'))
    self.addField(pyweblib.forms.Input('ldapurl',u'LDAP Url',1024,1,'[ ]*ldap(|i|s)://.*',size=30))
    self.addField(pyweblib.forms.Input('host',u'Host:Port',255,1,'(%s|[a-zA-Z0-9/._-]+)' % w2lapp.gui.host_pattern,size=30))
    self.addField(DistinguishedNameInput('dn','Distinguished Name'))
    self.addField(pyweblib.forms.Select(
      'scope','Scope',1,
      options=w2lapp.searchform.SEARCH_SCOPE_OPTIONS,
      default=w2lapp.searchform.SEARCH_SCOPE_STR_SUBTREE),
    )
    self.addField(DistinguishedNameInput('login_search_root','Login search root'))
    self.addField(pyweblib.forms.Input('login_filterstr',u'Login search filter string',300,1,'.*'))
    self.addField(pyweblib.forms.Select(
      'conntype','Connection type',1,
      options=[
        ('0','LDAP clear-text connection'),
        ('1','LDAP with StartTLS ext.op.'),
        ('2','LDAP over separate SSL port (LDAPS)'),
        ('3','LDAP over Unix domain socket (LDAPI)')
      ],
      default='0',
    ))

  def addCommandFields(self):
    pass

  def actionUrlHTML(self,command,sid):
    return '%s/%s%s' % (
      self.script_name,
      command,
      {0:'/%s' % sid,1:''}[sid is None],
    )

  def beginFormHTML(self,command,sid,method,target=None,enctype=None):
    target = {0:'target="%s"' % (target),1:''}[target is None]
    return """
      <form
        action="%s"
        method="%s"
        %s
        enctype="%s"
        accept-charset="%s"
      >
      """  % (
        self.actionUrlHTML(command,sid),
        method,target,
        enctype or 'application/x-www-form-urlencoded',
        self.accept_charset
      )

  def hiddenFieldHTML(self,name,value,desc):
    return w2lapp.gui.HIDDEN_FIELD % (
      name,
      self.utf2display(value,sp_entity='  '),
      self.utf2display(desc,sp_entity='&nbsp;&nbsp;'),
    )

  def formHTML(
    self,command,submitstr,sid,method,form_parameters,
    extrastr='',
    target=None
  ):
    """
    Build the HTML text of a submit form
    """
    HIDDEN_FIELD = w2lapp.gui.HIDDEN_FIELD
    form_str = [self.beginFormHTML(command,sid,method,target)]
    for param_name,param_value in form_parameters:
      form_str.append(self.hiddenFieldHTML(param_name,param_value,u''))
    form_str.append("""
      <p>
      <input type="submit" value="%s">
      %s
      </p>
      </form>""" % (submitstr,extrastr)
    )
    return '\n'.join(form_str)

  def applAnchor(
    self,command,anchor_text,sid,
    form_parameters,
    target=None,
    title=None
  ):
    """
    Build the HTML text of a anchor with form parameters
    """
    target = {0:' target="%s"' % (target),1:''}[target is None]
    title = {0:' title="%s"' % (self.utf2display(title)),1:''}[title is None]
    return '<a class="CommandLink"%s%s href="%s?%s">%s</a>' % (
      target,title,
      self.actionUrlHTML(command,sid),
      '&amp;'.join([
        '%s=%s' % (
          param_name,
          urllib.quote(self.uc_encode(param_value)[0])
        )
        for param_name,param_value in form_parameters
      ]),
      anchor_text
    )


class Web2LDAPNullForm(Web2LDAPForm):
  pass


class Web2LDAPForm_searchform(Web2LDAPForm):

  def addCommandFields(self):
    self.addField(pyweblib.forms.Select('search_submit',u'',1,options=[u'Search',u'More',u'Fewer',u'All Attrs'],default=None))
    self.addField(pyweblib.forms.Input('search_submit',u'Search form submit button',6,1,'(Search|[+-][0-9]+)'))
    self.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'))
    self.addField(DistinguishedNameInput('search_root','Search root'))
    self.addField(pyweblib.forms.Input('filterstr',u'Search filter string',1200,1,'.*'))
    self.addField(pyweblib.forms.Input('searchform_template',u'Search form template name',60,w2lapp.cnf.misc.max_searchparams,u'[a-zA-Z0-9. ()-]+'))
    self.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=u'10'
      )
    )
    self.addField(
      pyweblib.forms.Select(
        'search_lastmod',u'Interval of last creation/modification',1,
        options=[
          (u'-1',u'-'),
          (u'10',u'10 sec.'),
          (u'60',u'1 min.'),
          (u'600',u'10 min.'),
          (u'3600',u'1 hour'),
          (u'14400',u'4 hours'),
          (u'43200',u'12 hours'),
          (u'86400',u'24 hours'),
          (u'172800',u'2 days'),
          (u'604800',u'1 week'),
          (u'2419200',u'4 weeks'),
          (u'6048000',u'10 weeks'),
          (u'31536000',u'1 year'),
        ],
        default=u'-1'
      )
    )
    self.addField(InclOpAttrsCheckbox('search_opattrs',u'Request operational attributes',default="yes",checked=0))
    self.addField(pyweblib.forms.Select('search_mode',u'Search Mode',1,options=[ur'(&%s)',ur'(|%s)']))
    self.addField(pyweblib.forms.Input('search_attr',u'Attribute(s) to be searched',1000,w2lapp.cnf.misc.max_searchparams,ur'[\w,_;-]+'))
    self.addField(pyweblib.forms.Input('search_mr',u'Matching Rule',1000,w2lapp.cnf.misc.max_searchparams,ur'[\w,_;-]+'))
    self.addField(pyweblib.forms.Select('search_option',u'Search option',w2lapp.cnf.misc.max_searchparams,options=w2lapp.searchform.search_options))
    self.addField(pyweblib.forms.Input('search_string',u'Search string',100,w2lapp.cnf.misc.max_searchparams,u'.*',size=60))
    self.addField(pyweblib.forms.Input('search_attrs',u'Attributes to be read',1000,1,ur'[@*+0-9.\w,_;-]+'))

class Web2LDAPForm_search(Web2LDAPForm_searchform):
  def addCommandFields(self):
    Web2LDAPForm_searchform.addCommandFields(self)
    self.addField(pyweblib.forms.Input('filterstr',u'Search filter string',1200,20,'.*'))
    self.addField(DistinguishedNameInput('search_root','Search root'))
    self.addField(pyweblib.forms.Input('search_resminindex',u'Minimum index of search results',10,1,u'[0-9]+'))
    self.addField(pyweblib.forms.Input('search_resnumber',u'Number of results to display',3,1,u'[0-9]+'))
    self.addField(ExportFormatSelect('search_output'))


class Web2LDAPForm_modifyform(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(pyweblib.forms.Select('input_formtype',u'Type of input form',1,options=['Template','Table','LDIF'],default='Template'))
    self.addField(pyweblib.forms.Input('ldap_oc',u'Object classes',60,40,u'[a-zA-Z0-9.-]+'))

class Web2LDAPForm_addform(Web2LDAPForm_modifyform):
  def addCommandFields(self):
    Web2LDAPForm_modifyform.addCommandFields(self)
    self.addField(pyweblib.forms.Input('add_rdn','RDN of new entry',255,1,u'.*',size=50))
    self.addField(pyweblib.forms.Input('add_template',u'LDIF template name',60,w2lapp.cnf.misc.max_searchparams,u'.+'))

class Web2LDAPForm_conninfo(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(pyweblib.forms.Select('conninfo_flushcaches',u'Flush caches',1,options=['0','1'],default=0))

class Web2LDAPForm_ldapparams(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(pyweblib.forms.Select('ldapparams_submit',u'Submit type',1,options=(u'Apply',u''),default=u''))
    self.addField(
      pyweblib.forms.Input(
        'ldap_bool_control_oid',
        u'LDAPv3 Boolean Control',
        50,
        len(w2lapp.ldapparams.AVAILABLE_BOOLEAN_CONTROLS),
        u'([0-9]+.)*[0-9]+',
      )
    )
    self.addField(
      pyweblib.forms.Select(
        'ldap_deref',u'Dereference aliases',maxValues=1,default=str(ldap.DEREF_NEVER),
        options=[
          (str(ldap.DEREF_NEVER),u'never'),
          (str(ldap.DEREF_SEARCHING),u'searching'),
          (str(ldap.DEREF_FINDING),u'finding'),
          (str(ldap.DEREF_ALWAYS),u'always'),
        ]
      )
    )

class Web2LDAPForm_input(Web2LDAPForm):
  """Base class for entry data input not directly used"""
  def addCommandFields(self):
    self.addField(pyweblib.forms.Select('input_formtype',u'Type of input form',1,options=[u'Template',u'Table',u'LDIF',u'+'],default=u'Template'))
    self.addField(pyweblib.forms.Select('input_currentformtype',u'Type of input form',1,options=[u'Template',u'Table',u'LDIF'],default=u'Template'))
    self.addField(AttributeType('in_attrtype',u'Attribute type',w2lapp.cnf.misc.input_maxattrs))
    self.addField(AttributeType('in_binattrtype',u'Binary attribute type',w2lapp.cnf.misc.input_maxbinattrs))
    self.addField(AttributeType('input_addattrtype',u'Attribute type to be extended',1))
    self.addField(
      pyweblib.forms.Input(
        'in_value',u'Attribute Value',
        w2lapp.cnf.misc.input_maxfieldlen,
        w2lapp.cnf.misc.input_maxattrs,
        ('.*',re.U|re.M|re.S)
      )
    )
    self.addField(
      pyweblib.forms.File(
        'in_binvalue',u'Binary attribute value',
        w2lapp.cnf.misc.input_maxfilelen,
        w2lapp.cnf.misc.input_maxattrs,
        None
      )
    )
    self.addField(LDIFTextArea('in_ldif',u'LDIF data'))

class Web2LDAPForm_add(Web2LDAPForm_input):
  def addCommandFields(self):
    Web2LDAPForm_input.addCommandFields(self)
    self.addField(pyweblib.forms.Input('add_rdn',u'RDN of new entry',255,1,u'.*',size=50))
    self.addField(pyweblib.forms.Input('add_basedn',u'Base DN of new entry',1024,1,u'.*',size=50))

class Web2LDAPForm_modify(Web2LDAPForm_input):
  def addCommandFields(self):
    Web2LDAPForm_input.addCommandFields(self)
    self.addField(AttributeType('in_oldattrtypes',u'Old attribute types',w2lapp.cnf.misc.input_maxattrs))
    self.addField(AttributeType('in_wrtattroids',u'Writeable attribute types',w2lapp.cnf.misc.input_maxattrs))
    self.addField(pyweblib.forms.Input('in_assertion',u'Assertion filter string',2000,1,'.*',required=1))

class Web2LDAPForm_dds(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(pyweblib.forms.Input('dds_renewttlnum',u'Request TTL number',12,1,'[0-9]+',default=''))
    self.addField(pyweblib.forms.Select(
      'dds_renewttlfac',
      u'Request TTL factor',1,
      options=(
        (u'1',u'seconds'),
        (u'60',u'minutes'),
        (u'3600',u'hours'),
        (u'86400',u'days'),
      ),
      default='1'
    ))

class Web2LDAPForm_delete(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(pyweblib.forms.Select('delete_confirm',u'Confirmation',1,options=['yes','no'],default='no'))
    delete_ctrl_options=[
      (ctrl_oid,oid_desc_reg.get(ctrl_oid,(ctrl_oid,))[0])
      for ctrl_oid,ctrl_methods in w2lapp.ldapparams.AVAILABLE_BOOLEAN_CONTROLS.items()
      if '**write**' in ctrl_methods or 'delete_ext' in ctrl_methods or 'modify_ext' in ctrl_methods
    ]
    delete_ctrl_options.append((ldapsession.CONTROL_TREEDELETE,u'Tree Deletion'))
    self.addField(
      pyweblib.forms.Select(
        'delete_ctrl',
        u'Extended controls',
        len(delete_ctrl_options),
        options=delete_ctrl_options,
        default=[],
        size=3,
        multiSelect=1,
      )
    )
    self.addField(pyweblib.forms.Input('delete_attr',u'Attribute to be deleted',255,100,u'[\w_;-]+'))

class Web2LDAPForm_rename(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(pyweblib.forms.Input('rename_newrdn',u'New RDN',255,1,ldaputil.base.rdn_pattern,size=50))
    self.addField(DistinguishedNameInput('rename_newsuperior','New superior DN'))
    self.addField(pyweblib.forms.Checkbox('rename_delold',u'Delete old',1,default="yes",checked=1))
    self.addField(
      pyweblib.forms.Input(
        'rename_newsupfilter',
        u'Filter string for searching new superior entry',300,1,'.*',
        default=u'(|(objectClass=organization)(objectClass=organizationalUnit))',
        size=50,
      )
    )
    self.addField(DistinguishedNameInput('rename_searchroot','Search root under which to look for new superior entry.'))
    self.addField(pyweblib.forms.Input('rename_supsearchurl',u'LDAP URL for searching new superior entry',100,1,'.*',size=30))

class Web2LDAPForm_passwd(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(
      pyweblib.forms.Select(
        'passwd_action',
        u'Password action',
        1,
        options=[ (action,short_desc) for action,short_desc,long_desc in w2lapp.passwd.PASSWD_ACTIONS ],
        default='setuserpassword'
    ))
    self.addField(DistinguishedNameInput('passwd_who',u'Password DN'))
    self.addField(pyweblib.forms.Field('passwd_oldpasswd',u'Old password',100,1,'.*'))
    self.addField(pyweblib.forms.Field('passwd_newpasswd',u'New password',100,2,'.*'))
    self.addField(pyweblib.forms.Select('passwd_scheme',u'Password hash scheme',1,options=w2lapp.passwd.available_hashtypes,default=w2lapp.passwd.available_hashtypes[-1]))
    self.addField(pyweblib.forms.Checkbox('passwd_ntpasswordsync',u'Sync ntPassword for Samba',1,default="yes",checked=1))
    self.addField(pyweblib.forms.Checkbox('passwd_settimesync',u'Sync password setting times',1,default="yes",checked=1))
    self.addField(pyweblib.forms.Checkbox('passwd_forcechange',u'Force password change',1,default="yes",checked=0))
    self.addField(pyweblib.forms.Checkbox('passwd_inform',u'Password change inform action',1,default="display_url",checked=0))

class Web2LDAPForm_read(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(pyweblib.forms.Input('filterstr',u'Search filter string when reading single entry',1200,1,'.*'))
    self.addField(pyweblib.forms.Select('read_nocache',u'Force fresh read',1,options=['0','1'],default=0))
    self.addField(pyweblib.forms.Input('read_attr',u'Read attribute',255,100,u'[\w_;-]+'))
    self.addField(pyweblib.forms.Select('read_attrmode',u'Read attribute',1,options=[u'view',u'load']))
    self.addField(pyweblib.forms.Input('read_attrindex',u'Read attribute',255,1,u'[0-9]+'))
    self.addField(pyweblib.forms.Input('read_attrmimetype',u'MIME type',255,1,u'[\w.-]+/[\w.-]+'))
    self.addField(pyweblib.forms.Select('read_output',u'Read output format',1,options=['table','vcard','template'],default='template'))
    self.addField(pyweblib.forms.Input('search_attrs',u'Attributes to be read',1000,1,ur'[@*+0-9.\w,_;-]+'))
    self.addField(pyweblib.forms.Input('read_expandattr',u'Attributes to be read',1000,1,ur'[*+\w,_;-]+'))

class Web2LDAPForm_groupadm(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(DistinguishedNameInput('groupadm_searchroot','Group search root'))
    self.addField(pyweblib.forms.Input('groupadm_name',u'Group name',100,1,u'.*',size=30))
    self.addField(DistinguishedNameInput('groupadm_add','Add to group',300))
    self.addField(DistinguishedNameInput('groupadm_remove','Remove from group',300))
    self.addField(pyweblib.forms.Select('groupadm_view',u'Group list view',1,options=[('0','none of the'),('1','only member'),('2','all')],default='1'))

class Web2LDAPForm_login(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(DistinguishedNameInput('login_who',u'Bind DN'))

class Web2LDAPForm_locate(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(
      pyweblib.forms.Input('locate_name',u'Location name',500,1,u'.*',size=25)
    )

class Web2LDAPForm_oid(Web2LDAPForm):
  def addCommandFields(self):
    self.addField(OIDInput('oid',u'OID'))
    self.addField(pyweblib.forms.Select('oid_class','Schema element class',1,options=ldap.schema.SCHEMA_ATTRS,default=''))



FORM_CLASS = {
  '':Web2LDAPForm,
  'monitor':Web2LDAPNullForm,
  'urlredirect':Web2LDAPNullForm,
  'disconnect':Web2LDAPNullForm,
}

_FORM_CLASS_NAME_PREFIX = 'Web2LDAPForm_'
_COMMAND_STR_OFFSET = len(_FORM_CLASS_NAME_PREFIX)

for _name in dir():
  if _name.startswith(_FORM_CLASS_NAME_PREFIX):
    c = eval(_name)
    try:
      command = _name[_COMMAND_STR_OFFSET:]
    except IndexError:
      pass
    else:
      FORM_CLASS[command] = c
      del command



class DistinguishedNameInput(pyweblib.forms.Input):
  """Input field class for LDAP DNs."""

  def __init__(self,name='dn',text='DN',maxValues=1,required=0,default=''):
    pyweblib.forms.Input.__init__(
      self,name,text,1024,maxValues,'',
      size=70,required=required,default=default
    )

  def _validateFormat(self,value):
    if value and not ldaputil.base.is_dn(value):
      raise pyweblib.forms.InvalidValueFormat(
        self.name,
        self.text.encode(self.charset),
        value.encode(self.charset)
      )


class LDIFTextArea(pyweblib.forms.Textarea):
  """A single multi-line input field for LDIF data"""

  def __init__(
    self,name='in_ldif',text='LDIF data',required=0,max_entries=1
  ):
    pyweblib.forms.Textarea.__init__(
      self,
      name,text,w2lapp.cnf.misc.ldif_maxbytes,1,ldif.ldif_pattern,
      required=required,
    )
    self._max_entries = max_entries
    self.allRecords = []

  def getLDIFRecords(self):
    if self.value:
      f = StringIO('\n'.join(self.value).encode(self.charset))
      ldif_parser = ldif.LDIFRecordList(
        f,
        ignored_attr_types=[],
        max_entries=self._max_entries,
        process_url_schemes=w2lapp.cnf.misc.ldif_url_schemes
      )
      # It's not clear why ldif_parser stays persistent.
      # But let's reset class attribute now.
      # FIX ME!!! Likely not thread-safe!
      ldif_parser.all_records = []
      ldif_parser.parse()
      return ldif_parser.all_records[:]
    else:
      return []


class OIDInput(pyweblib.forms.Input):

  def __init__(self,name,text,default=None):
    pyweblib.forms.Input.__init__(
      self,name,text,
      512,1,u'[a-zA-Z0-9_.;*-]+',
      default=default,
      required=0,size=30
    )


class ObjectClassSelect(pyweblib.forms.Select):
  """Select field class for choosing the object class(es)"""
  def __init__(
    self,
    name='ldap_oc',
    text='Object classes',
    options=None,
    default=None,
    required=0,
    accesskey='',
    size=12,            # Size of displayed select field
  ):
    select_default = default or []
    select_default.sort(key=str.lower)
    additional_options = [ i for i in options or [] if not i in select_default ]
    additional_options.sort(key=str.lower)
    select_options = select_default[:]
    select_options.extend(additional_options)
    pyweblib.forms.Select.__init__(
      self,
      name,text,maxValues=200,
      required=required,
      options=select_options,
      default=select_default,
      accessKey=accesskey,
      size=size,
      ignoreCase=1,
      multiSelect=1
    )
    self.setRegex('[\w]+')
    self.maxLen = 200


class ExportFormatSelect(pyweblib.forms.Select):
  """Select field class for choosing export format"""

  def __init__(
    self,
    name='search_output',
    text=u'Export format',
    options=None,
    default='ldif1',
    required=0,
  ):
    default_options = [
      (u'table',u'Table/template'),
      (u'raw',u'Raw DN list'),
      (u'print',u'Printable'),
      (u'ldif',u'LDIF (Umich)'),
      (u'ldif1',u'LDIFv1 (RFC2849)'),
      (u'dsml1',u'DSMLv1'),
      (u'csv',u'CSV'),
    ]
    if w2lapp.search.ExcelWriter:
      default_options.append((u'excel',u'Excel'))
    pyweblib.forms.Select.__init__(
      self,
      name,text,1,
      options=options or default_options,
      default=default,
      required=required,
      size=1,
    )


class AttributeType(pyweblib.forms.Input):

  def __init__(self,name,text,maxValues):
    pyweblib.forms.Input.__init__(
      self,name,text,500,maxValues,
      ldaputil.base.attr_type_pattern,required=0,size=30
    )


class InclOpAttrsCheckbox(pyweblib.forms.Checkbox):

  def __init__(self,name,text,default='yes',checked=0):
    pyweblib.forms.Checkbox.__init__(self,name,text,1,default=default,checked=checked)


class AuthMechSelect(pyweblib.forms.Select):
  """Select field class for choosing the bind mech"""

  supported_bind_mechs = {
    '':'Simple Bind',
    'DIGEST-MD5':'SASL Bind: DIGEST-MD5',
    'CRAM-MD5':'SASL Bind: CRAM-MD5',
    'PLAIN':'SASL Bind: PLAIN',
    'LOGIN':'SASL Bind: LOGIN',
    'GSSAPI':'SASL Bind: GSSAPI',
    'EXTERNAL':'SASL Bind: EXTERNAL',
    'OTP':'SASL Bind: OTP',
    'NTLM':'SASL Bind: NTLM',
    'SCRAM-SHA-1':'SASL Bind: SCRAM-SHA-1',
  }

  def __init__(
    self,
    name='login_mech',
    text=u'Authentication mechanism',
    default=None,
    required=0,
    accesskey='',
    size=1,            # Size of displayed select field
  ):
    pyweblib.forms.Select.__init__(
      self,
      name,text,maxValues=1,
      required=required,
      options=None,
      default=default or [],
      accessKey=accesskey,
      size=size,
      ignoreCase=0,
      multiSelect=0
    )

  def setOptions(self,options):
    options_dict = {}
    options_dict[''] = self.supported_bind_mechs['']
    for o in options or self.supported_bind_mechs.keys():
      o_upper = o.upper()
      if self.supported_bind_mechs.has_key(o_upper):
        options_dict[o_upper] = self.supported_bind_mechs[o_upper]
    pyweblib.forms.Select.setOptions(self,options_dict.items())
