<?xml-stylesheet type="text/xsl" href="html.xsl"?>
<manual title="ldapvi User Manual" style="manual.css">
  <intro>
    <p>
      <tt>ldapvi</tt> is an interactive LDAP client for Unix terminals.
      Using it, you can update LDAP entries with a text editor.
    </p>
    <p>
      Think of it as <tt>vipw</tt>(1) for LDAP.
    </p>
    <p>
      ldapvi was written by David Lichteblau and is available
      at <link>http://www.lichteblau.com/ldapvi/</link>.
    </p>
  </intro>

  <chapter name="installing" title="Installing ldapvi">
    <p>
      ldapvi uses autoconf and should be rather easy to install.
    </p>
    <p>
      It used to work on Linux, Solaris, FreeBSD, IRIX, and Cygwin for
      me and seems to work on MacOS X and NetBSD for others.  Current
      versions are only really tested on Linux though, so please
      send a bug report if a port is broken.
    </p>
    <code>$ ./configure &amp;&amp; make
# make install</code>
    <p title="Prerequisites">
      <ul>
	<li>
	  Recent OpenLDAP client library (>= 2.2 preferred, 2.1 tolerated)
	</li>
	<li>glib-2.0</li>
	<li>popt</li>
	<li>curses</li>
	<li>GNU make</li>
	<li>
	  OpenSSL or GnuTLS, choose using
	  <tt>./configure --with-libcrypto</tt>
	</li>
	<li>GNU readline</li>
	<li>
	  Build dependency: Cyrus SASL.  SASL support is disabled in
	  ldapvi if Cyrus SASL headers cannot be found at compilation
	  time.  (Whether libldap was compiled with SASL support is only
	  relevant at run time.)
	</li>
      </ul>
    </p>
    <p>
      Note that binaries compiled for libldap 2.1 will crash when ran
      with libldap 2.2.
    </p>
    <p>
      The choice of GnuTLS over OpenSSL affects only the use of hashing
      routines for the <tt>userPassword</tt> convenience encodings md5,
      smd5, sha, and ssha.  GnuTLS support is offered because, according
      to Debian, OpenSSL is not GPL compatible.
    </p>
  </chapter>

  <chapter name="gettingstarted" title="Getting started">
    <p>
      The quickest way to try ldapvi is using this:
    </p>
    <code>$ ldapvi -d --host HOSTNAME</code>

    <p title="Explanation">
      This will bind anonymously to <tt>hostname</tt>, read all entries
      the server has and open them in the editor.
    </p>
    <p>
      <tt>--host</tt> is the one option you really need to give.  It can
      be one of:
    </p>
    <ul>
      <li>A domain name.</li>
      <li><tt>ldap://hostname[:port]</tt></li>
      <li><tt>ldaps://hostname[:port]</tt></li>
    </ul>
    <p>
      <tt>-d</tt> is short for <tt>--discover</tt> and lets ldapvi
      search all of the server's naming contexts.  Without <tt>-d</tt>,
      you would have had to specify the base DN yourself
      using <tt>--base</tt>, and you know how inconvenient those LDAP
      DNs are to type.
    </p>

    <p title="Using a configuration file">
      As easy as that was, you might want to put the hostname and other
      search options like the precise base DN to use into a
      configuration file.
    </p>
    <p>
      To do that, you might like 
    </p>
    <code>$ ldapvi --config --discover --host HOSTNAME</code>
    <p>
      This will ask the server for its naming contexts and print
      sample contents for <tt>~/.ldaprc</tt>
      (or <tt>/etc/ldap.conf</tt>).
    </p>
    <p>
      (Note that ldapvi also has its own <a href="config">configuration
      file format</a> which supports multiple configuration profiles and
      all of its options.)
    </p>
    <code><i># ldap.conf(5)
# edit this as needed and paste into ~/.ldaprc

# server name
# (for parameterless operation, make sure to include at least this line)</i>
<b>HOST localhost</b>

<i># default search base
### multiple namingcontexts found (uncomment one of these lines):</i>
<b>#BASE dc=lichteblau,dc=com
#BASE dc=acme,dc=com</b>

<i># user to bind as</i>
<b>#BINDDN &lt;dn&gt;</b>

<i># search parameters (uncomment as needed)</i>
<b>#DEREF never
#SIZELIMIT 0
#TIMELIMIT 0</b></code>
    <p>
      Adjust to taste.
    </p>
  </chapter>

  <chapter name="interactive" title="Interactive usage">
    <p>
      After quitting from the editor, one of three things can happen:
    </p>
    <ul>
      <li>
	If ldapvi detects that nothing in the file has changed, it will
	quit.
	<tty>No changes.</tty>
      </li>
      <li>
	Syntax error: Oops.  In this case you only have two options:<br/>
	You can either re-edit the file and fix the error
	(type <tt>e</tt>) or give up and quit (type <tt>Q</tt>).  As in
	all menus, type <tt>?</tt> for interactive help.
	<tty>Error: Space at beginning of line.
What now? [eQ?]</tty>
      </li>
      <li>
	Regular usage: ldapvi has compared your changed file with the
	original contents and reports on the changes found:
	<tty><green>add: 2</green>, <blue>rename: 1</blue>, modify: 0, <red>delete: 1</red>
Action? [yYqQvVebB*rsf+?] </tty>
      </li>
    </ul>
    <p>
      If all is well, you are now in the main loop.  Your options are:
    </p>

    <p title="Edit - diff - fail">To continue, type <tt>y</tt>.</p>
    <ul>
      <li><tt>y</tt> -- commit changes<br/></li>
    </ul>
    <p>
      ldapvi will contact the LDAP server apply all changes.  First,
      entries are processed in order of the changed file, then all
      entries missing from the file are deleted.
    </p>
    <ul>
      <li><tt>e</tt> -- open editor again</li>
    </ul>
    <p>
      If any LDAP operation fails while processing the file, ldapvi will
      stop, report the error, and wait for your choice.  To correct such
      an error, go back to the editor.  Your will find all previously
      processed entries removed from the file, with the failing change
      at the top.  After changing the file, you will be back at the
      prompt.
    </p>
    <tty>Action? [yYqQvVebB*rsf+?] <b>y</b>
ldap_modify: Strong(er) authentication required (8)
        additional info: modifications require authentication
Error at: cn=blub4,dc=lichteblau,dc=com
add: 0, rename: 0, <yellow>modify: 1</yellow>, delete: 0
Action? [yYqQvVebB*rsf+?] </tty>
    <ul>
      <li><tt>Y</tt> -- commit, ignoring errors<br/></li>
    </ul>
    <p>
      Apply all changes as if invoked
      with <a href="#parameter-continue"><tt>--continue</tt></a>
      ignoring all errors without further warning.  (Make sure to save
      changes to an external file before using this option if they were
      important.  Invalid changes will be lost otherwise.)
    </p>

    <p title="Reviewing changes">
      Before applying the changes, you can inspect them in either LDIF
      syntax or ldapvi's special changerecord syntax.
    </p>
    <ul>
      <li><tt>v</tt> -- view changes as LDIF change records</li>
    </ul>
    <ul>
      <li><tt>V</tt> -- view changes as ldapvi change records</li>
    </ul>
    <p>
      LDIF syntax is useful if you want to copy and paste changes into a
      file for later processing with other LDAP tools.  ldapvi syntax is
      usually easier to read (less Base 64) and can also be entered
      directly into the editor.
    </p>
    <ul>
      <li><tt>+</tt> -- rewrite file to include schema comments</li>
    </ul>
    <p>
      This will update the file to include schema comments and re-enter
      the editor afterwards.  This works like
      the <a href="#parameter-may"><tt>--may</tt></a> command line
      option, but is based on the current contents of the file rather
      than the original entries, useful when changing the class of an
      entry.
    </p>
    <p>
      Note that this command will rewrite the entire file and wipe out
      all comments present before invoking it.
    </p>

    <p name="key-b" title="Logging in">
      One way to bind to the LDAP server is to specify user name and
      credentials at startup using command line options or configuration
      files.  The other is to simply start without authentication and
      login later.
    </p>
    <p>
      When relying on binding after editing, keep in mind that some
      information will not be returned by the LDAP server unless user
      authorization permits it in the first place.  For example,
      a <tt>userPassword</tt> can usually only be displayed and edited
      if you are bound as that user or root upon startup.
    </p>
    <ul>
      <li><tt>b</tt> -- show login dialog and rebind</li>
    </ul>
    <p>
      This option will ask for your user name and password (in the case
      of simple authentication) or various SASL parameters (as
      requested by the SASL library).
    </p>
    <p>
      For simple authentication, the user name can be either an DN or a
      search filter.  In the latter case, it must be written with
      parentheses around it.
    </p>
    <tty>Action? [yYqQvVebB*rsf+?] <b>b</b>

--- Login
Type M-h for help on key bindings.

Filter or DN: <b>(cn=admin)</b>
    Password: <b>********</b>
OK, bound as cn=admin,dc=lichteblau,dc=com.</tty>
    <p>
      Same example with SASL:
    </p>
    <tty>Action? [yYqQvVebB*rsf+?] <b>b</b>
SASL/DIGEST-MD5 authentication started

--- SASL login
Type M-h for help on key bindings.

 authorization name: 
authentication name: <b>admin</b>
           password: <b>********</b>
SASL username: admin
SASL SSF: 128
SASL installing layers
Bound as authzid=, authcid=admin.</tty>
    <p>
      Note that all non-password values are saved
      into <tt>~/.ldapvi_history</tt>, so after entering them once,
      "cursor up" or incremental search (<tt>C-r</tt>) will save you
      from having to type them again.
    </p>
    <ul>
      <li><tt>B</tt> -- toggle SASL</li>
    </ul>
    <p>
      Use this key to switch between simple authentication and SASL at
      run time:
    </p>
    <tty>Action? [yYqQvVebB*rsf+?] <b>B</b>
SASL authentication enabled.
SASL mechanism: DIGEST-MD5 (use '*' to change)
Type 'b' to log in.</tty>
    <ul>
      <li><tt>*</tt> -- set SASL mechanism</li>
    </ul>
    <p>
      When the SASL dialog is shown, it is too late to switch the SASL
      mechanism.  Type <tt>*</tt> to set it at run time.
    </p>
    <tty>Action? [yYqQvVebB*rsf+?] <b>*</b>
SASL mechanism: <b>DIGEST-MD5</b>
Type 'b' to log in.</tty>

    <p title="&#34;Oops&#34;">
      You can skip one change to proceed with the rest.
    </p>
    <ul>
      <li><tt>s</tt> -- skip one entry</li>
    </ul>
    <p>
      Removes the topmost entry from the data file.
    </p>
    <ul>
      <li><tt>f</tt> -- forget all deletions</li>
    </ul>
    <p>
      This is useful if you have deleted entries from the file
      accidentally (or intentionally) and still want to commit other
      change records in the same file.
    </p>
    <p>
      This option does not affect explicit deletion records.
    </p>

    <p title="Bailing out">There is a gentle way to quit and a hard one.</p>
    <ul>
      <li><tt>q</tt> -- save changes as LDIF and quit</li>
    </ul>
    <ul>
      <li><tt>Q</tt> -- discard changes and quit</li>
    </ul>
    <p>
      <tt>q</tt> will save your changes to a new file, print the file
      name, and quit only then.  This way your changes do not get lost
      and you can feed them into ldapmodify at a later time.
    </p>
    <tty>Action? [yYqQvVebB*rsf+?] <b>q</b>
Your changes have been saved to ,ldapvi-xenon-20094.ldif.</tty>

<!--
wofuer was das doch gleich da?
    <ul>
      <li><tt>r</tt> - - reconnect to server</li>
    </ul>
-->
  </chapter>

  <chapter name="arguments" title="Command line arguments">
    <p>
      Normal <tt>ldapvi</tt> invocations look similar
      to <tt>ldapsearch</tt>(1), taking an optional search filter and
      zero or more attribute descriptions as unnamed arguments.
    </p>
    <code>ldapvi [OPTION]... [FILTER] [AD]...</code>
    <p>
      In addition, ldapvi can also simulate behaviour of other LDAP
      command line tools, e.g. as an interactive substitute for
      ldapmodify or even for a simple non-interactive usage.  See below
      under <a href="#arguments-tools">command line tool compatibility</a>.
    </p>
    <p title="Index of options"/>
    <list-options/>

    <section name="connection" title="Connection parameters">
      <p>
	The <tt>host</tt> option specifies the LDAP server to connect
	to.  It is required for startup (unless specified in a
	configuration file).
      </p>

      <parameter short="h" long="host" args="hostname"
		 brief="LDAP server to connect to">
	Three styles of host name are recognized.
	<ul>
	  <li>A domain name.</li>
	  <li><tt>ldap://hostname[:port]</tt></li>
	  <li><tt>ldaps://hostname[:port]</tt></li>
	</ul>
	To specify a port number or tunnelling through SSL, the URL form
	must be used.
      </parameter>
    </section>

    <section name="authentication" title="Authentication">
      <p>
	Note that you can also bind to the server interactively after
	performing the search using <a href="#key-b">the <tt>b</tt>
	command</a>.
      </p>
      <parameter long="bind" args="simple|sasl" brief="Disable or enable SASL">
	<p>
	  Initially, ldapvi defaults to simple authentication.  If any
	  SASL parameter is given, the mode is set to <tt>sasl</tt>.
	  Conversely, <a href="#parameter-user"><tt>-D</tt></a> sets it
	  to <tt>simple</tt>.
	</p>
	<p>This parameter sets it explicitly.</p>
      </parameter>
      <parameter long="bind-dialog"
		 args="never|auto|always"
		 brief="Interactive login dialog">
	<p>
	  This option controls whether ldapvi will ask for
	  authentication parameters interactively.
	</p>
	<p>
	  The default is <tt>auto</tt>, which means that simple binds
	  will be done interactively if a user name is provided but no
	  password, and similarly for SASL.
	</p>
	<p>
	  <tt>always</tt> forces display of a login dialog even if
	  defaults are known.  <tt>never</tt> skips the login dialog
	  completely.
	</p>
	<p>
	  Note that this option has effect only for the initial bind
	  operation.  In the main loop, all binds are done interactively.
	</p>
	<p>
	  See also: <a href="#parameter-sasl-quiet"><tt>-Q</tt></a>
	  and <a href="#parameter-sasl-interactive"><tt>-I</tt></a>.
	</p>
      </parameter>
      <parameter short="D" long="user" args="dn|filter"
		 brief="User to bind as (simple bind)">
	The user name can be specified as a distinguished name
	<code>uid=foo,ou=bar,dc=acme,dc=com</code>
	or as a search filter
	<code>(uid=foo)</code>
	<p>
	  Note the use of parenthesis, which can be omitted from search
	  filters usually but are required here.  For this searching
	  bind to work, your client library must be configured with
	  appropriate default search parameters.
	</p>
	<p>
	  Exactly one entry must match.
	</p>
      </parameter>
      <parameter short="w" long="password" args="secret"
		 brief="User's password">
	Beware that passwords in a simple bind are transmitted in clear
	text unless the connection is encrypted through SSL.
	<p>
	  This option is valid for both simple authorization and SASL.
	</p>
      </parameter>
      <parameter short="y" long="password-file" args="filename"
		 brief="File containing user's password">
	Beware that passwords in a simple bind are transmitted in clear
	text unless the connection is encrypted through SSL.
	<p>
	  This option is valid for both simple authorization and SASL.
	</p>
      </parameter>
      <p title="SASL authentication">
	If any of the SASL arguments is specified, ldapvi uses SASL
	by default.
      </p>
      <p>
	If you are unsure which SASL parameters to try for your server,
	start with <tt>-Y DIGEST-MD5 -U <i>username</i></tt>.
      </p>
      <parameter short="I" long="sasl-interactive"
		 brief="Use SASL Interactive mode">
	Always ask for SASL parameters interactively.

	<p>
	  This option is an alias for
	  <a href="#parameter-bind-dialog"><tt>--bind-dialog always</tt></a>
	  and
	  <a href="#parameter-bind"><tt>--bind sasl</tt></a>.
	</p>
      </parameter>
      <parameter short="Q" long="sasl-quiet"
		 brief="Use SASL Quiet mode">
	Never ask for SASL parameters interactively at all.

	<p>
	  This option is an alias for
	  <a href="#parameter-bind-dialog"><tt>--bind-dialog never</tt></a>
	  and
	  <a href="#parameter-bind"><tt>--bind sasl</tt></a>.
	</p>
      </parameter>
      <parameter short="O" long="sasl-secprops" args="properties"
		 brief="SASL security properties">
	OpenLDAP's <a
		      href="http://www.lichteblau.com/ldapvi/slapd.conf.5.txt">slapd.conf</a>(5)
	manual page has some information on these (search for sasl-secprops).
      </parameter>
      <parameter short="R" long="sasl-realm" args="realm"
		 brief="SASL realm">
	The <a
	href="http://www.lichteblau.com/ldapvi/cyrus-sasl/sysadmin.html#realms">SASL
	realm</a> [Cyrus SASL documentation].
      </parameter>
      <parameter short="U"
		 long="sasl-authcid"
		 brief="SASL authentication identity"
		 args="username">
	The <a
	href="http://www.lichteblau.com/ldapvi/cyrus-sasl/sysadmin.html#authid">authentication
		 ID</a> [Cyrus SASL documentation].
	<p>
	  (Basically, your username.)
	</p>
      </parameter>
      <parameter short="X"
		 long="sasl-authzid"
		 brief="SASL authorization identity"
		 args="u:username|dn:dn">
	The <a
	href="http://www.lichteblau.com/ldapvi/cyrus-sasl/sysadmin.html#authid">authorization
		 ID</a> [Cyrus SASL documentation].
      	<p>
	  (See <a
	  href="http://www.openldap.org/doc/admin/sasl.html#SASL Proxy Authorization"
		  >SASL Proxy Authorization</a>
	  [openldap.org] in the OpenLDAP Administrator's Guide.)
	</p>
      </parameter>
      <parameter short="Y"
		 long="sasl-mech"
		 brief="SASL mechanism"
		 args="mechanism">
      	<p>
	  The SASL mechanism to use.  Possible values depend on the
	  server, but <tt>DIGEST-MD5</tt> support is mandated by
	  RFC&#160;2829 for all servers using passwords.
	</p>
      </parameter>
    </section>

    <section name="search" title="Search parameters">
      <p>Where and how to look for entries.</p>
      <parameter short="b" long="base" args="dn" brief="Search base">
	The entry at which to start the search.
	<p>
	  Conflicts with <a href="#parameter-discover"><tt>--discover</tt></a>.
	</p>
      </parameter>
      <parameter short="s" long="scope" values="base|one|sub"
		 brief="Search scope">
	<ul>
	  <li><tt>base</tt>: Retrieve at most the entry at <tt>base</tt>.</li>
	  <li>
	    <tt>one</tt>: Search for entries exactly one level
	    below <tt>base</tt>.
	  </li>
	  <li>
	    <tt>sub</tt>: Search the entire subtree starting at <tt>base</tt>.
	  </li>
	</ul>
      </parameter>
      <parameter short="S" long="sort" args="keys"
		 brief="Search control">
	Use the search control to instruct the server to sort results
	on <i>keys</i>.  ldapvi will fail if the server does not support
	the control.  Unfortunately, few servers do.
      </parameter>
    </section>

    <section name="handy" title="Handy parameters">
      <parameter short="d" long="discover" brief="Auto-detect naming contexts">
	With this option, ldapvi will first read the root DSE, then repeat
	the search for each naming context found and present the
	concatenation of all search results.
	<p>
	  Conflicts with <a href="#parameter-base"><tt>--base</tt></a>.
	</p>
	<p>
	  With <a href="#parameter-config"><tt>--config</tt></a>, show
	  a <tt>BASE</tt> configuration line for each context.
	</p>
      </parameter>
      <parameter short="o"
		 long="class"
		 args="objectClass"
		 brief="Class to add">
	Read the server's schema for the specified objectclass to find out
	which attributes an entry of this class must have and can have.
	Then open the editor with an entry template containing one line
	for each such attribute the user needs to fill out.  Optional
	attributes are included as comments.
	<p>
	  The option can be repeated to include
	  additional, <i>auxiliary</i> classes.
	</p>
	<p>
	  A distinguished name for the entry template can be specified
	  using <a href="#parameter-base"><tt>--base</tt></a>.
	</p>
      </parameter>
      <parameter short="m" long="may" brief="Show schema comments.">
	Show schema comments for existing entries.  Specificially, show
	optional attributes as comments, if not present.
      </parameter>
    </section>

    <section name="misc" title="Miscellaneous options">
      <parameter long="add"
		 brief="Treat attrval records as new entries to add.">
	<p>
	  This option applies only to
	  the <a
	  href="#parameter-in"><tt>--in</tt></a>/<a
	  href="#parameter-ldapmodify"><tt>--ldapmodify</tt></a> mode:
	</p>
	<p>
	  Add new entries (default would be to replace existing attributes).
	</p>
      </parameter>
      <parameter short="A" long="empty" brief="Start with empty file">
	Do not search, start with an empty file instead.
	<p>
	  This is the little brother of
	  the <a href="#parameter-class"><tt>--class</tt> parameter</a>,
	  which is more interesting for the original use case of this
	  option, adding new entries.
	</p>
	<p>
	  However, it is still useful because allows the interactive
	  entry of <tt>delete</tt>, <tt>modify</tt>, or <tt>rename</tt>
	  changerecords.
	</p>
      </parameter>
      <parameter short="a"
		 long="deref"
		 values="never|searching|finding|always"
		 brief="Alias dereferencing mode">
	Default is <tt>never</tt>.
      </parameter>
      <parameter long="config"
		 brief="Print parameters in ldap.conf syntax"
		 suppress-configuration="suppress-configuration">
	Print a configuration file in standard <tt>ldap.conf</tt> syntax
	which reflects current command line arguments.  The file is
	written to standard output.  Use this option to create an
	initial configuration file after experimenting with search
	parameters.  Useful in conjunction
	with <a href="#parameter-discover"><tt>--discover</tt></a>.
      </parameter>
      <parameter short="c"
		 long="continue"
		 brief="Ignore LDAP errors and continue">
	When LDAP errors occur while applying changes, print the messages
	but continue processing.  This mode can also be specified
	interactively using the 'Y' key.
      </parameter>
      <parameter long="encoding"
		 values="ASCII|UTF-8|binary"
		 brief="The encoding to allow">
	This option controls how ldapvi deals with non-ASCII bytes in
	attribute values.
	<ul>
	  <li>
	    <tt>ASCII</tt>: If an attribute value contains any non-ASCII
	    character, use Base 64 encoding for this value
	  </li>
	  <li>
	    <tt>UTF-8</tt>: Use auto-detection.  If an attribute value
	    parses as correct UTF-8, pass it through to the file or
	    terminal unchanged.  Otherwise, fall back to Base 64.  Mark
	    the file's encoding as UTF-8 for Emacs and VIM.
	  </li>
	  <li>
	    <tt>binary</tt>: Do not inspect attribute values at all, let
	    arbitrary data through, including zero bytes.  Do not use
	    Base 64.
	  </li>
	</ul>
	<p>
	  The default is <tt>UTF-8</tt>.
	</p>
      </parameter>
      <parameter short="M" long="managedsait" brief="manageDsaIT control">
	Use this option to edit referral entries.
      </parameter>
      <parameter short="Z" long="starttls" brief="Require startTLS.">
	After opening an unencrypted LDAP connection, use startTLS to
	enable SSL.  (This is an alternative to LDAP connections
	tunnelled through SSL, specified using <tt>ldaps://</tt> URLs.)
      </parameter>
      <parameter long="tls"
		 values="never|allow|try|strict"
		 brief="Level of TLS strictness">
	This option controls the level of certificate checking
	strictness.  Default is <tt>strict</tt>.
	<p>
          Note: This only takes effect when ldaps:// or -Z are used.
          Strict mode does not prevet ldap:// from being connected to without TLS.
	</p>
      </parameter>
      <parameter long="read" args="DN" brief="Read this entry">
	A rather trivial option.  It means the same as:
	<code>-b DN -s base '(objectclass=*)' + *</code>
      </parameter>
      <parameter short="v" long="verbose" brief="Note every update">
	Print the distinguished name of every entry as it is being
	processed.
      </parameter>
<!--
      <parameter short="q" long="quiet" brief="Disable progress output">
	Make ldapvi shut up a little.
      </parameter>
      <parameter short="!"
		 long="noquestions"
		 brief="Don't ask for confirmation">
	documentme
      </parameter>
  -->
      <parameter short="H" long="help" brief="Print usage information"
		 suppress-configuration="suppress-configuration">
	Print help on command line arguments.
      </parameter>
      <parameter long="unpaged-help" brief="Disable pager for --help">
	Disable the use of a pager
	for <a href="#parameter-rename"><tt>--help</tt></a>.
      </parameter>
      <parameter long="deleteoldrdn" brief="Delete the old RDN">
	When changing the relative distinguished name to a new attribute
	value, delete the old attribute value instead of keeping it.
	<p>
	  This option applies only to
	  the <a href="#parameter-rename"><tt>--rename</tt></a> mode.
	</p>
      </parameter>
      <parameter long="ldif" brief="Use LDIF syntax internally">
	Use standard LDIF syntax in the editor.  The default is to use
	ldapvi syntax.
      </parameter>
      <parameter long="ldapvi" brief="Use ldapvi syntax externally">
	Use ldapvi syntax when reading and writing files.  The default
	is to use LDIF syntax.
      </parameter>
    </section>

    <section name="tools" title="Command line tool compatibility">
      <p>
	ldapvi invocation modes inspired by LDAP command line tools:
	<extra-parameter long="out" brief="Print entries"/>
	<extra-parameter long="in" brief="Load change records"/>
	<extra-parameter long="delete" brief="Edit a delete record"/>
	<extra-parameter long="rename" brief="Edit a rename record"/>
      </p>
      <mode-table>
	<mode label="Print LDIF, similar to ldapsearch">
	  ldapvi <b>--out</b> [OPTION]... <b>[FILTER] [AD]...</b>
	</mode>
	<mode label="Load LDIF change records, similar to ldapmodify">
	  ldapvi <b>--in</b> [OPTION]... <b>[FILENAME]</b>
	</mode>
	<mode label="Edit delete records, similar to ldapdelete">
	  ldapvi <b>--delete</b> [OPTION]... <b>DN...</b>
	</mode>
	<mode label="Edit rename records, similar to ldapmodrdn">
	  ldapvi <b>--rename</b> [OPTION]... <b>DN1 DN2</b><!--<br/>
	  ldapvi <b>-&#45;modrdn</b> [OPTION]... <b>DN RDN</b>-->
	</mode>
      </mode-table>
      <p>
	All of these are more verbose and interactive than the standard
	command line tools.  There are additional aliases for closer
	compatibility:
	<extra-parameter long="ldapsearch"
			 brief="Print entries noninteractively"/>
	<extra-parameter long="ldapmodify"
			 brief="Apply change records noninteractively"/>
	<extra-parameter long="ldapdelete"
			 brief="Delete an entry noninteractively"/>
	<extra-parameter long="ldapmoddn"
			 brief="Rename an entry noninteractively"/>
      </p>
      <mode-table>
	<mode short="--quiet --out"><b>--ldapsearch</b></mode>
	<mode short="--noninteractive --in"><b>--ldapmodify</b></mode>
	<mode short="--noninteractive --delete"><b>--ldapdelete</b></mode>
	<mode short="--noninteractive --rename"><b>--ldapmoddn</b></mode>
<!--
	<mode short="-&#45;noninteractive -&#45;modrdn"><b>-&#45;ldapmodrdn</b></mode>
-->
      </mode-table>
      <p>
	Please keep in mind that all these invocation modes are only
	meant to imitate LDAP command line tools <i>as far as
	possible</i> while still working within the design of ldapvi.
	An option-by-option emulation of the OpenLDAP command line tools
	is <i>not</i> a goal, and minor differences in look and feel are
	to be expected.
      </p>
      <p title="Format conversion"/>
      <mode-table>
	<mode label="Convert LDIF on stdin to ldapvi format on stdout">
	  ldapvi --in | cat
	</mode>
	<mode label="Convert ldapvi format on stdin to LDIF on stdout">
	  ldapvi --in --ldif --ldapvi | cat
	</mode>
      </mode-table>
    </section>
  </chapter>

  <chapter name="config" title="Configuration file format">
    <p>
      The are two ways to configure ldapvi.  It has its own
      configuration files <tt>~/.ldapvirc</tt>
      (or <tt>/etc/ldapvi.conf</tt>) which support multiple configuration
      profiles and all of its custom options.  Alternatively, it can
      fall back to <tt>libldap</tt>'s standard configuration
      files, <tt>/etc/ldap.conf</tt> and <tt>~/.ldaprc</tt>.
    </p>

    <p title="Files and profiles">
      On startup, ldapvi will first look for <tt>~/.ldapvirc</tt>,
      or <tt>/etc/ldapvi.conf</tt> if the former does not exist.
    </p>
    <ul>
      <li>
	If <tt>--profile</tt> <i>name</i> is specified at the command
	line, one of these configuration files must exist and it must
	contain the named profile.  Otherwise ldapvi quits with an
	error.
      </li>
      <li>
	If no <tt>--profile</tt> was given, ldapvi looks for a profile
	called <tt>default</tt>.  If no such profile can be found or the
	files do not exist, ldapvi falls back to <tt>libldap</tt>
	configuration files.
      </li>
      <li>
	By default, if a profile is used, it suppresses loading of
	the <tt>libldap</tt> configuration files <tt>/etc/ldap.conf</tt>
	and <tt>~/.ldaprc</tt>.  If you want these files to take effect
	anyway, you can set <tt><a href="#parameter-ldap-conf">ldap-conf</a>:
	yes</tt> in the profile.
      </li>
    </ul>

    <p title="Environment variables">The choice of text editor is made
      using environment variables.  <tt>$VISUAL</tt>
      and <tt>$EDITOR</tt> are looked up in this order.  If neither is
      set, ldapvi falls back to <tt>vi</tt>.
    </p>

    <p title="Profile syntax">
      The configuration file has <a href="#syntax">ldapvi syntax</a>,
      except with header lines of the
      form <tt>profile</tt>&#160;<i>name</i>.
    </p>
    <p>
      Every configuration file option corresponds to a command line
      parameter.  
    </p>
    <p>
      For the named command line parameters, the long name is used in
      the configuration.  For details, refer to the documentation of
      each parameter: <list-configuration-options/>
    </p>
    <p>
      The two unnamed kinds of command line arguments are the search
      filter and the list of attribute descriptions to be returned.  The
      former is named &#x2799;&#160;<tt>filter</tt> in the configuration
      file.  The latter are given as &#x2799;&#160;<tt>ad</tt>, one line
      each.
    </p>
    <p>
      For boolean flags, given without a value at the command line,
      use <tt>yes</tt> as their value in the configuration
      file.  (<tt>no</tt> is also allowed and has no effect.)
    </p>
    <p title="Example">
      With the following configuration file, ldapvi
      ignores <tt>libldap</tt> configuration, because a <tt>default</tt>
      profile is given.
    </p>
    <ul>
      <li>
	The default profile falls back to <tt>libldap</tt>
	configuration, but enables schema comments.
      </li>
      <li>
	<tt>ldapvi -p otherhost</tt> profile reads all entries from
	<tt>otherhost</tt>.
      </li>
      <li>
	<tt>ldapvi -p adduser</tt> will open a template for a new user
	entry to be filled in.
      </li>
      <li>
	<tt>ldapvi -p root</tt> will retrieve the root DSE with its
	operational attributes.
      </li>
    </ul>
    <code>profile default
ldap-conf: yes
may: yes

profile otherhost
host: ldap://otherhost
discover: yes

profile adduser
host: ldap://localhost
base: uid=FILLMEIN,ou=passwd,dc=lichteblau,dc=com
class: person
class: posixAccount

profile root
host: ldap://localhost
base: 
scope: base
filter: (objectclass=*)
ad: +</code>
  </chapter>

  <chapter name="syntax" title="ldapvi syntax explained">
    <p>
      <i>ldapvi syntax</i> is somewhat LDIF-like, but not the same as
      standard LDIF.  This chapter includes examples explaining the
      difference between the two formats.  (A precise, technical
      definition of ldapvi syntax is given in the <a href="#bnf">next
      section</a>.)
    </p>

    <p>
      &#x2799; In <b>interactive editing</b>, the default is
      <b>ldapvi syntax</b>, explained below, unless overridden
      using <a href="#parameter-ldif"><tt>--ldif</tt></a>.
    </p>
    <p>
      &#x2799; For external <b>input and output</b>
      (see <a
      href="#parameter-in"><tt>--in</tt></a>, <a
      href="#parameter-out"><tt>--out</tt></a>), the default
      is <b>standard LDIF</b> syntax, unless overridden
      using <a href="#parameter-ldapvi"><tt>--ldapvi</tt></a>.
    </p>

    <section name="basics" title="Basics">
      <p>Comments are lines starting with a sharpsign:</p>
      <code># like this</code>
      <p>
	They are allowed both between entries and in the middle of entries
	(but not in the middle of an attribute value).
      </p>

      <p>Empty lines are used to separate entries:</p>
      <code>0 dc=lichteblau,dc=com
<b># don't touch the number!</b>
objectClass: top
objectClass: dcObject
objectClass: organization
o: lichteblau
dc: lichteblau

<b># more than one empty line would be OK here, too</b>
add cn=admin,dc=lichteblau,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator</code>
      <p>
	So far this looks pretty much like LDIF, except for the
	record <i>key</i> that appears instead of the <tt>dn:</tt> LDIF
	uses to start an entry.
      </p>
      <ul>
	<li>
	  Numbers as keys reference entries read from the server.  ldapvi
	  uses them to find the original entry when comparing your changed
	  file with its unchanged copy.
	</li>
	<li>
	  Special key <tt>add</tt> is used for new entries that are to be
	  added to the tree.  Except for not having a number key, its
	  syntax is the same as for normal entries.
	</li>
	<li>
	  In addition, there are special keys for <i>change records</i>:
	  <tt>rename</tt>, <tt>delete</tt>, and <tt>modify</tt>.  Change
	  records have special syntax and
	  are <a href="#syntax-changerecords">explained below</a> in
	  detail.
	</li>
      </ul>
      <p>
	First though, more on low-level syntax issues.
      </p>
    </section>

    <section name="encodings" title="Value encodings">
      <p>
	All non-empty, non-comment "lines" have the same base syntax: A
	left-hand and a right-hand side, separated by an optional
	encoding marker and a space.  (Depending on the encoding used, a
	such a logical line may include newline characters.)
      </p>
      <p>
	The syntax of the right-hand side depends on the encoding marker.
	For simple ASCII text without special characters, there are
	multiple valid encodings that can be used.
      </p>
      <p>
	This includes the first line of a record with the distinguished
	name, its base syntax is the same as for the attribute lines.  For
	traditional reasons, ldapvi prints this line without a colon, but
	that is not a requirement:
      </p>
      <code><b># rather than writing this:</b>
add cn=admin,dc=lichteblau,dc=com

<b># we could have included a colon:</b>
add: cn=admin,dc=lichteblau,dc=com

<b># or actually, this:</b>
add:; cn=admin,dc=lichteblau,dc=com</code>
      <p>
	Or, vice versa, we could have omitted the colon from those
	attribute values.  ldapvi prints it only so that entries looks for
	familiar to eyes used to LDIF.
      </p>
      <p>
	Value encodings are:
      </p>
      <ul>
	<li><tt>ad: value</tt>: LDIF-compatible</li>
	<li><tt>ad:: value</tt>: Base 64</li>
	<li><tt>ad value</tt>: backslashed (short form)</li>
	<li><tt>ad:; value</tt>: backslashed (long form)</li>
	<li><tt>ad:<i>n</i> value</tt>: binary</li>
	<li><tt>ad:&lt; value</tt>: input from file</li>
	<li><tt>ad:crypt value</tt>: userPassword {CRYPT}-hash</li>
	<li><tt>ad:cryptmd5 value</tt>: userPassword {CRYPT}-hash</li>
	<li><tt>ad:md5 value</tt>: userPassword {MD5}-hash</li>
	<li><tt>ad:smd5 value</tt>: userPassword {SMD5}-hash</li>
	<li><tt>ad:sha value</tt>: userPassword {SHA}-hash</li>
	<li><tt>ad:ssha value</tt>: userPassword {SSHA}-hash</li>
      </ul>
      <p title="LDIF-compatible encoding">
	Lines with just a colon and a space are parsed according to normal
	LDIF rules.  Values must be ASCII-only and must not contain zero
	bytes, LF, or CR.  In addition, they must not start with a space,
	a colon, or a less-than sign.
      </p>
      <p>
	This encoding allows LDIF-style line folding: If a line ends, and
	the first character of the next line, if any, is a space, the
	nextline and the space are elided and parsing continues on the
	next line.
      </p>
      <p>
	Note: The language for attribute value lines described above is
	the common subset of LDIF's attrval-spec and the actual syntax
	accepted by ldapvi for this value encoding.  ldapvi will only
	ever print out values in this encoding if they follow these
	rules and hence are valid LDIF, but is more liberal in parsing
	them.  It accepts space, colon, or less-than sign as the first
	character.  It can allow them without ambiguity because, in
	contrast to LDIF, it does not ignore an arbitrary number of
	space characters after the colon.
      </p>
      <p>
	Examples of valid LDIF values:
      </p>
      <code><b># normally, one would write:</b>
objectClass: posixAccount

<b># but with line folding, the same value can be broken into two lines:</b>
objectClass: posix
 Account

<b># in contrast to ldapvi backslashed format, this encoding does not
# interpret backslashes specially at all:</b>
cn: this is a value containing a backslash\
 but no newline
</code>
      <p>
	Examples of attribute values not representable in
	LDIF-compatible encoding:
      </p>
      <code><b># must not start with '&lt;':</b>
<b># [accepted by ldapvi but not LDIF]</b>
<strike>document: &lt;?xml version="1.0" encoding="UTF-8"&gt;&lt;foo/&gt;</strike>

<b># cannot start with a space:</b>
<b># [LDIF would ignore the space]</b>
<strike>foo:  ...</strike>

<b># must not start with a colon:</b>
<b># [accepted by ldapvi but not LDIF]</b>
<strike>foo: ::::::::</strike>

<b># must not contain non-ASCII bytes:</b>
<strike>surname: M&#252;ller</strike>

<b># cannot represent newlines:</b>
<strike>mail: From david@lichteblau.com Mon Apr  1 00:11:22 2006
Return-path: &lt;david@lichteblau.com&gt;
Envelope-to: lists@mail.askja.de</strike></code>

      <p title="Base 64 encoding">
	Base 64 can be used just as in LDIF.  
      </p>
      <code><b># This is what the XML from above looks like in strict LDIF:</b>
document:: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPjxmb28vPg==</code>

      <p title="ldapvi backslashed encoding">
	This is the format ldapvi falls back to if a value cannot be
	represented in LDIF-compatible encoding without resorting to
	Base 64.  Any character is valid in this encoding, except for
	two characters with a special meaning:
      </p>
      <ul>
	<li>newline terminates the value unless escaped with a backslash</li>
	<li>backslash escapes the following character</li>
      </ul>
      <p>
	Examples of valid backslashed attributes:
      </p>
      <code><b># any funny characters are OK</b>
document:; &lt;?xml version="1.0" encoding="UTF-8"&gt;
foo:;  ...
foo:; ::::::::
surname:; M&#252;ller

<b># backslash escapes newline</b>
mail:; From david@lichteblau.com Mon Apr  1 00:11:22 2006\
Return-path: &lt;david@lichteblau.com&gt;\
Envelope-to: lists@mail.askja.de

<b># No LDIF line folding, however, so this value contains a space:</b>
cn:; David\
 Lichteblau
</code>
      <p>
	Counter-example:
      </p>
      <code><b># Parsable first line, followed by garbage on the second:</b>
<strike>cn:; David
 Lichteblau</strike></code>
      <p>
	Finally, in most situations <tt>:;</tt> can be omitted, leaving
	just a space between the left-hand and right-hand side of the
	line.  The only exception is a line with an empty left-hand side,
	which occurs in <a href="#syntax-changerecords">modify records</a>.
      </p>
      <code>foo:; bar
<b># is the same as:</b>
foo bar</code>

      <p title="Binary encoding">
	Decimal numbers are valid as encoding markers and specify the
	number of bytes to read after the separating space.  No special
	characters exist in this syntax.  This encoding is not meant for
	interactive use, but for the sake of completeness, here is an
	example:
      </p>
      <code><b># This entry has two attributes, givenname and cn:</b>
add cn=admin,ou=passwd,dc=blubba
givenname:5 Davidcn: admin</code>

      <p title="File inclusion">
	The less-than sign tells LDAP to read the contents of another
	file and use them as the attribute value.  This is another
	LDIF compatibility feature.
      </p>
      <code><b># oops</b>
add cn=haxor,ou=passwd,dc=blubba
comment:&lt; file:///etc/passwd</code>

      <p title="userPassword encodings">
	The encodings crypt, cryptmd5, md5, smd5, sha, and ssha are
	designed for the <tt>userPassword</tt> attribute.  ldapvi takes
	the right-hand side as the password, hashes it, and
	prepends <tt>{ENCODING}</tt> as appropriate.
      </p>
      <code>userPassword:crypt foo
<b># ...could result in:</b>
userPassword: {CRYPT}KgJTUDs14z57Q
<b># ...or:</b>
userPassword: {CRYPT}UoILyHlM1bPYU

<b># cryptmd5 gives $1$ notation</b>
userPassword:cryptmd5 foo
userPassword: {CRYPT}$1$iKeAY9mQ$vmo/m/6EoDqRuVtjSqLPr0

<b># while the other encodings prepend the marker of the same name:</b>
userPassword:md5 foo
userPassword: {MD5}AQ3GmMeoPXozyRU4wsEDXA==</code>
    </section>

    <section name="changerecords" title="Change records">
      Aside from the obvious <tt>add</tt> records mentioned above, there
      are three change record formats:
      <tt>rename</tt>, <tt>modify</tt>, and <tt>delete</tt>.

      <p title="rename records">
	Like every other record, <tt>rename</tt> states the (original)
	distinguished name of the name in the header line.  Next is one
	additional line stating the new distinguished name.
      </p>
      <p>
	The complication is that LDAP's moddn operation needs to be told
	what to do with the old relative DN if there is a new one.  The
	old one can be kept as an additional attribute value or deleted
	in favour of the new one.
      </p>
      <p>
	In ldapvi, this choice is made using the left-hand side of the
	second line.  It is either "add" or "replace".
      </p>
      <code><b># example for "deleteoldrdn" behaviour:</b>
rename: cn=blub4,dc=lichteblau,dc=com
replace: cn=blub3,dc=neu,dc=com

<b># alternatively, the old RDN can be kept:</b>
rename: cn=blub3,dc=lichteblau,dc=com
add: cn=blub4,dc=neu,dc=com</code>
      <p>
	In LDIF, the same changes would be written as:
      </p>
      <code><b># this is LDIF, not ldapvi syntax!</b>
dn: cn=blub4,dc=lichteblau,dc=com
changetype: modrdn
newrdn: cn=blub3
deleteoldrdn: 1
newsuperior: dc=neu,dc=com

dn: cn=blub3,dc=lichteblau,dc=com
changetype: modrdn
newrdn: cn=blub4
deleteoldrdn: 0
newsuperior: dc=neu,dc=com</code>

      <p title="modify records">
	These records state changes to attributes, processed in order.
	Attributes can be changed by replacing their existing values
	with a new set of values, adding those values to the existing
	ones, or removing only selected old values.
      </p>
      <p>
	Example:
      </p>
      <code><b># Let's add classes, delete a comment and remove cn entirely:</b>
modify: dc=bar,dc=lichteblau,dc=com
add: objectClass
: posixAccount
: specialAccount
delete: comment
: dummy user
replace: cn
</code>
      <p>
	In LDIF, this would be:
      </p>
      <code><b># this is LDIF, not ldapvi syntax!</b>
dn: dc=bar,dc=lichteblau,dc=com
changetype: modify
add: objectClass
objectClass: posixAccount
objectClass: specialAccount
-
delete: comment
comment: dummy user
-
replace: cn
-</code>

      <p title="delete records">
	These are rather simple, they consist just of the header line.
      </p>
      <code>delete: dc=acme,dc=com</code>
      <p>
	In LDIF, this would be:
      </p>
      <code><b># this is LDIF, not ldapvi syntax!</b>
dn: dc=acme,dc=com
changetype: delete</code>
    </section>

    <section name="ldif" title="Using LDIF syntax">
      <p>
	When invoked
	using <a href="#parameter-ldif"><tt>--ldif</tt></a>, ldapvi will
	use <a href="http://www.rfc-editor.org/rfc/rfc2849.txt">RFC
	2849</a> syntax instead of its own special syntax.
      </p>
      <p>
	However, there is a special marker in each entry:
      </p>
      <p>
	Existing entries are presented for editing with an additional
	marker on the second line, just after the <tt>dn:</tt> line.
	This line states the (numeric) <em>key</em> that would appear in
	the header line if the entry had been printed in ldapvi syntax.
      </p>
      <p>
	(New entries can have the same line, with <tt>add</tt> as their
	key, but records with neither <tt>ldapvi-key</tt>
	nor <tt>changetype</tt> are automatically assumed to be new
	entries to add.)
      </p>
      <p>Also, <tt>control:</tt> is not supported.</p>
      <p>
	Examples:
      </p>
      <code># Existing entry
dn: dc=lichteblau,dc=com
<b>ldapvi-key: 0</b>
objectClass: top
objectClass: dcObject
objectClass: organization
o: lichteblau
dc: lichteblau

# New entry
dn: cn=admin,dc=lichteblau,dc=com
# next line is optional
<i>ldapvi-key: add</i>
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator

# Changerecord (standard LDIF syntax)
dn: cn=blub4,dc=lichteblau,dc=com
<i>changetype: modify</i>
delete: seeAlso
seeAlso: cn=dort
-
</code>
    </section>
  </chapter>
  

  <chapter name="bnf" title="ldapvi syntax (BNF)">
    <p>
      As explained above, ldapvi has its own, vaguely LDIF-inspired
      syntax.  For a precise definition, see <tt>ldapvi-file</tt> below.
    </p>
    <p>
      LDIF is defined in
      <a href="http://www.rfc-editor.org/rfc/rfc2849.txt">RFC 2849</a>.
    </p>

    <p>
      RFC 2849 modifies the language generated by its BNF grammar with
      the "Notes on LDIF Syntax" (2) and (3) presented there.  These
      notes do not apply to ldapvi syntax as stated: Line folding and
      comments can be used, but are allowed specificially by our
      modified BNF, not hacked into the rules later.  Line folding is
      allowed only in LDIF-compatible attribute values and comments.
      ldapvi files cannot be read line-by-line without knowing the
      encoding of those lines, since newlines are permitted in certain
      attribute value representations.
    </p>

    <p>
      The following rules are used as defined in RFC 2849 and not
      reproduced here: AttributeDescription, SAFE-STRING, BASE64-STRING,
      SPACE.
    </p>

    <p title="Changes to the RFC 2849 BNF grammar"/>
    <code>ldapvi-file = vspace ldapvi-record
              *(vspace SEP vspace ldapvi-record) vspace
ldapvi-record = ldapvi-attrval-record
	        / ldapvi-rename-record
		/ ldapvi-modify-record
ldapvi-attrval-record = *(comment) dn-spec 1*(*(comment) attrval-spec)
ldapvi-rename-record = *(comment)
                       "rename" distinguishedName SEP
		       ("add" / "replace") value-spec SEP
ldapvi-modify-record = *(comment)
                       "modify" distinguishedName SEP
		       1*(*(comment) mod-spec)
mod-spec = ("delete" / "add" / "replace") ad-value SEP
	   *(value-enc SEP)

vspace = *(comment / sep)
comment = "#" *(ldif-char) *(SEP " " *(ldif-char)) SEP

dn-spec = key distinguishedName SEP
key = number / "add"
distinguishedName = value-spec                  ;encoding an RFC 2253 DN

attrval-spec = AttributeDescription value-spec SEP
value-spec = value-simple / value-enc
value-simple = SPACE escaped-string             ;escape CR/LF with '\\\\'
value-enc = (":;" SPACE escaped-string /        ;ditto
             ":" SPACE 0*1(SAFE-STRING          ;LDIF compatible
                           *(SEP " " *SAFE-CHAR)) /
             "::" SPACE BASE64-STRING /         ;ditto
             ":" number SPACE 0*1(octet) /      ;exactly `number' octets
             ":&lt;" SPACE url /                   ;only file:// supported
             ":crypt" SPACE password /          ;for userPassword
             ":cryptmd5" SPACE password /
             ":md5" SPACE password /
             ":smd5" SPACE password /
             ":sha" SPACE password /
             ":ssha" SPACE password /
             ;; other encoding markers reserved
            )

octet = %x00-ff
number = 1*(%x30-39)                            ;any decimal number
ldif-char = unescaped-char / %5c                ;any except for CR/LF.
unescaped-char = %x00-%x09 / %x0a-%x0c / %x0d-%5b / %x5d-%ff
escaped-string = *(unescaped-char / %x5c %x0a / %x5c %x0d / %x5c %x5c)
password = 0*ldif-char
SEP = LF                                        ;this is a unix program!

ad-value = value-spec  ;parsing as an AttributeDescription</code>
  </chapter>

  <chapter name="bugs" title="Reporting bugs">
    <p>
      Please report bugs to the ldapvi mailing list for archival
      purposes.
    </p>
    <p>
      Address: <a href="mailto:ldapvi@lists.askja.de">ldapvi@lists.askja.de</a>
    </p>
  </chapter>
</manual>
