Thunderbird Addon Demonstrating Autocomplete With Addrbook And LDAP

  • Revision slug: Thunderbird_Addon_Demonstrating_Autocomplete_With_Addrbook_And_LDAP
  • Revision title: Thunderbird Addon Demonstrating Autocomplete With Addrbook And LDAP
  • Revision id: 131122
  • Created:
  • Creator: simon.at.orcl
  • Is current revision? No
  • Comment page created, 681 words added

Revision Content

This Addon creates a textbox at the end of Thunderbird main window into which you can type name and E-Mail addresses that will be autocompleted by searching the local addressbooks and the globally configured LDAP server, extra work has been done to make it with Thunderbird 2.x (Gecko 1.8) and 3.x (Gecko 1.9).

Here is a quick walkthrough:

First, in the overlay, both autocompleteseach (Gecko 1.9) and searchSessions (Gecko 1.8) are specified:


        <textbox flex="1" id="ldap-autocomp" timeout="300"
                 maxrows="4"
                 autoFill="true"
                 autoFillAfterMatch="true"
                 forceComplete="true"
                 minResultsForPopup="3"
                 ignoreBlurWhileSearching="true"
                 type="autocomplete"
                 autocompletesearch="mydomain addrbook"  
                 searchSessions="addrbook" />             


Then, in the js code, the LDAP search session gets added:

 

  // This function originates from setupLdapAutocompleteSession:
  // http://hg.mozilla.org/comm-central/f...oseCommands.js
  //
  // It was modified in the following ways:
  // - Modified to support both Gecko 1.8.x and 1.9+
  // - Modified to take in an array of textbox ids to which the LDAP
  //   autocomplete should be attached
  // - Removed mail.autoComplete.commentColumn support to keep code simple
  // - Removed observers on pref changes to keep code simple 
  //

setupLDAPAutoComplete: function(textBoxIds) {
    var autocompleteLdap = false;
    var autocompleteDirectory = null;
    autocompleteLdap = getPref("ldap_2.autoComplete.useDirectory");
 
    if (!autocompleteLdap) {
      return;
    }
    else {
      autocompleteDirectory = getPref("ldap_2.autoComplete.directoryServer");
    }
    var LDAPSession= Components.classes["@mozilla.org/autocompleteSession;1?type=ldap"];
    LDAPSession = LDAPSession.createInstance().QueryInterface(Components.interfaces.nsILDAPAutoCompleteSession);
    var url;
    try {
      // Gecko 1.9 way
      url = getPref(autocompleteDirectory + ".uri", true);
      LDAPSession.serverURL = Components.classes["@mozilla.org/network/io-service;1"].
        getService(Components.interfaces.nsIIOService).
          newURI(url, null, null).
            QueryInterface(Components.interfaces.nsILDAPURL);
    }
    catch(ex) {
      // Try gecko 1.8 way
      var serverURL = Components.classes[
          "@mozilla.org/network/ldap-url;1"].
          createInstance().QueryInterface(
              Components.interfaces.nsILDAPURL);

      try {
          serverURL.spec = getPref(autocompleteDirectory + ".uri", true);
      } catch (ex) {
          dump("ERROR: " + ex + "\n");
      }
      LDAPSession.serverURL =  serverURL;
    }
    // get the login to authenticate as, if there is one
    try {
      LDAPSession.login = getPref(autocompleteDirectory + ".auth.dn", true);
    } catch (ex) {
      // if we don't have this pref, no big deal
    }

    try {
      LDAPSession.saslMechanism = getPref(autocompleteDirectory + ".auth.saslmech", true);
    } catch (ex) {
      // don't care if we don't have this pref
    }
   
    // set the LDAP protocol version correctly
    var protocolVersion;
    try {
      protocolVersion = getPref(autocompleteDirectory +".protocolVersion");
    } catch (ex) {
      // if we don't have this pref, no big deal
    }
   
    if (protocolVersion == "2") {
      LDAPSession.version = Components.interfaces.nsILDAPConnection.VERSION2;
    }
    // don't search on non-CJK strings shorter than this
    try {
      LDAPSession.minStringLength = getPref(autocompleteDirectory + ".autoComplete.minStringLength");
    } catch (ex) {
      // if this pref isn't there, no big deal.  just let
      // nsLDAPAutoCompleteSession use its default.
    }
    // don't search on CJK strings shorter than this
    try {
      LDAPSession.cjkMinStringLength = getPref(autocompleteDirectory + ".autoComplete.cjkMinStringLength");
    } catch (ex) {
      // if this pref isn't there, no big deal.  just let
      // nsLDAPAutoCompleteSession use its default.
    }
 
    // we don't try/catch here, because if this fails, we're outta luck
    var ldapFormatter = Components.classes["@mozilla.org/ldap-autocomplete-formatter;1?type=addrbook"].
      createInstance().QueryInterface(Components.interfaces.nsIAbLDAPAutoCompFormatter);
    // override autocomplete name format?
    try {
      ldapFormatter.nameFormat = getPref(autocompleteDirectory +".autoComplete.nameFormat",true);
    } catch (ex) {
      // if this pref isn't there, no big deal.  just let
      // nsAbLDAPAutoCompFormatter use its default.
    }
   
    // override autocomplete mail address format?
    try {
      ldapFormatter.addressFormat = getPref(autocompleteDirectory +".autoComplete.addressFormat",true);
    } catch (ex) {
      // if this pref isn't there, no big deal.  just let
      // nsAbLDAPAutoCompFormatter use its default.
    }

    // set the session's formatter, which also happens to
    // force a call to the formatter's getAttributes() method
    // -- which is why this needs to happen after we've set the
    // various formats
    LDAPSession.formatter = ldapFormatter;
 
    // override autocomplete entry formatting?
    try {
      LDAPSession.outputFormat = getPref(autocompleteDirectory +
                                           ".autoComplete.outputFormat",
                                         true);
    } catch (ex) {
      // if this pref isn't there, no big deal.  just let
      // nsLDAPAutoCompleteSession use its default.
    }
 
    // override default search filter template?
    try {
      LDAPSession.filterTemplate = getPref(
        autocompleteDirectory + ".autoComplete.filterTemplate",
        true);
    } catch (ex) {
      // if this pref isn't there, no big deal.  just let
      // nsLDAPAutoCompleteSession use its default
    }
   
    // override default maxHits (currently 100)
    try {
      // XXXdmose should really use .autocomplete.maxHits,
      // but there's no UI for that yet
      LDAPSession.maxHits = getPref(autocompleteDirectory + ".maxHits");
    } catch (ex) {
      // if this pref isn't there, or is out of range, no big deal.
      // just let nsLDAPAutoCompleteSession use its default.
    }

    for (i=0 ; i < textBoxIds.length ; i++ ) {
      var autoCompleteWidget = document.getElementById(textBoxIds[i]);
      autoCompleteWidget.addSession(LDAPSession);
    }
  }

Revision Source

<p>This Addon creates a textbox at the end of Thunderbird main window into which you can type name and E-Mail addresses that will be autocompleted by searching the local addressbooks and the globally configured LDAP server, extra work has been done to make it with Thunderbird 2.x (Gecko 1.8) and 3.x (Gecko 1.9).</p>
<p>Here is a quick walkthrough:</p>
<p>First, in the overlay, both autocompleteseach (Gecko 1.9) and searchSessions (Gecko 1.8) are specified:</p>
<p><code><br>
        &lt;textbox flex="1" id="ldap-autocomp" timeout="300" <br>
                 maxrows="4" <br>
                 autoFill="true" <br>
                 autoFillAfterMatch="true" <br>
                 forceComplete="true"<br>
                 minResultsForPopup="3" <br>
                 ignoreBlurWhileSearching="true"<br>
                 type="autocomplete"<br>
                 autocompletesearch="mydomain addrbook"   <br>
                 searchSessions="addrbook" /&gt;              </code></p>
<p><code><br>
</code>Then, in the js code, the LDAP search session gets added:</p>
<p> </p>
<p><code>  // This function originates from setupLdapAutocompleteSession: <br>
  // <a class=" external" href="http://hg.mozilla.org/comm-central/file/117e438feb4a/mail/components/compose/content/MsgComposeCommands.js" rel="freelink">http://hg.mozilla.org/comm-central/f...oseCommands.js</a><br>
  // <br>
  // It was modified in the following ways:<br>
  // - Modified to support both Gecko 1.8.x and 1.9+<br>
  // - Modified to take in an array of textbox ids to which the LDAP <br>
  //   autocomplete should be attached<br>
  // - Removed mail.autoComplete.commentColumn support to keep code simple<br>
  // - Removed observers on pref changes to keep code simple  <br>
  //</code></p>
<p><code>setupLDAPAutoComplete: function(textBoxIds) {<br>
    var autocompleteLdap = false;<br>
    var autocompleteDirectory = null;<br>
    autocompleteLdap = getPref("ldap_2.autoComplete.useDirectory");<br>
  <br>
    if (!autocompleteLdap) {<br>
      return;<br>
    }<br>
    else {<br>
      autocompleteDirectory = getPref("ldap_2.autoComplete.directoryServer");<br>
    }<br>
    var LDAPSession= Components.classes["@mozilla.org/autocompleteSession;1?type=ldap"];<br>
    LDAPSession = LDAPSession.createInstance().QueryInterface(Components.interfaces.nsILDAPAutoCompleteSession);<br>
    var url; <br>
    try {<br>
      // Gecko 1.9 way<br>
      url = getPref(autocompleteDirectory + ".uri", true);<br>
      LDAPSession.serverURL = Components.classes["@mozilla.org/network/io-service;1"].<br>
        getService(Components.interfaces.nsIIOService).<br>
          newURI(url, null, null).<br>
            QueryInterface(Components.interfaces.nsILDAPURL);<br>
    }<br>
    catch(ex) {<br>
      // Try gecko 1.8 way<br>
      var serverURL = Components.classes[<br>
          "@mozilla.org/network/ldap-url;1"].<br>
          createInstance().QueryInterface(<br>
              Components.interfaces.nsILDAPURL);<br>
<br>
      try {<br>
          serverURL.spec = getPref(autocompleteDirectory + ".uri", true);<br>
      } catch (ex) {<br>
          dump("ERROR: " + ex + "\n");<br>
      }<br>
      LDAPSession.serverURL =  serverURL;<br>
    }<br>
    // get the login to authenticate as, if there is one<br>
    try {<br>
      LDAPSession.login = getPref(autocompleteDirectory + ".auth.dn", true);<br>
    } catch (ex) {<br>
      // if we don't have this pref, no big deal<br>
    }<br>
<br>
    try {<br>
      LDAPSession.saslMechanism = getPref(autocompleteDirectory + ".auth.saslmech", true);<br>
    } catch (ex) {<br>
      // don't care if we don't have this pref<br>
    }<br>
    <br>
    // set the LDAP protocol version correctly<br>
    var protocolVersion;<br>
    try {<br>
      protocolVersion = getPref(autocompleteDirectory +".protocolVersion");<br>
    } catch (ex) {<br>
      // if we don't have this pref, no big deal<br>
    }<br>
    <br>
    if (protocolVersion == "2") {<br>
      LDAPSession.version = Components.interfaces.nsILDAPConnection.VERSION2;<br>
    }<br>
    // don't search on non-CJK strings shorter than this<br>
    try {<br>
      LDAPSession.minStringLength = getPref(autocompleteDirectory + ".autoComplete.minStringLength");<br>
    } catch (ex) {<br>
      // if this pref isn't there, no big deal.  just let<br>
      // nsLDAPAutoCompleteSession use its default.<br>
    }<br>
    // don't search on CJK strings shorter than this<br>
    try {<br>
      LDAPSession.cjkMinStringLength = getPref(autocompleteDirectory + ".autoComplete.cjkMinStringLength");<br>
    } catch (ex) {<br>
      // if this pref isn't there, no big deal.  just let<br>
      // nsLDAPAutoCompleteSession use its default.<br>
    }<br>
 <br>
    // we don't try/catch here, because if this fails, we're outta luck<br>
    var ldapFormatter = Components.classes["@mozilla.org/ldap-autocomplete-formatter;1?type=addrbook"].<br>
      createInstance().QueryInterface(Components.interfaces.nsIAbLDAPAutoCompFormatter);<br>
    // override autocomplete name format?<br>
    try {<br>
      ldapFormatter.nameFormat = getPref(autocompleteDirectory +".autoComplete.nameFormat",true);<br>
    } catch (ex) {<br>
      // if this pref isn't there, no big deal.  just let<br>
      // nsAbLDAPAutoCompFormatter use its default.<br>
    }<br>
    <br>
    // override autocomplete mail address format?<br>
    try {<br>
      ldapFormatter.addressFormat = getPref(autocompleteDirectory +".autoComplete.addressFormat",true);<br>
    } catch (ex) {<br>
      // if this pref isn't there, no big deal.  just let<br>
      // nsAbLDAPAutoCompFormatter use its default.<br>
    }<br>
<br>
    // set the session's formatter, which also happens to<br>
    // force a call to the formatter's getAttributes() method<br>
    // -- which is why this needs to happen after we've set the<br>
    // various formats<br>
    LDAPSession.formatter = ldapFormatter;<br>
  <br>
    // override autocomplete entry formatting?<br>
    try {<br>
      LDAPSession.outputFormat = getPref(autocompleteDirectory +<br>
                                           ".autoComplete.outputFormat",<br>
                                         true);<br>
    } catch (ex) {<br>
      // if this pref isn't there, no big deal.  just let<br>
      // nsLDAPAutoCompleteSession use its default.<br>
    }<br>
  <br>
    // override default search filter template?<br>
    try {<br>
      LDAPSession.filterTemplate = getPref(<br>
        autocompleteDirectory + ".autoComplete.filterTemplate",<br>
        true);<br>
    } catch (ex) {<br>
      // if this pref isn't there, no big deal.  just let<br>
      // nsLDAPAutoCompleteSession use its default<br>
    }<br>
    <br>
    // override default maxHits (currently 100)<br>
    try {<br>
      // XXXdmose should really use .autocomplete.maxHits,<br>
      // but there's no UI for that yet<br>
      LDAPSession.maxHits = getPref(autocompleteDirectory + ".maxHits");<br>
    } catch (ex) {<br>
      // if this pref isn't there, or is out of range, no big deal.<br>
      // just let nsLDAPAutoCompleteSession use its default.<br>
    }<br>
<br>
    for (i=0 ; i &lt; textBoxIds.length ; i++ ) {<br>
      var autoCompleteWidget = document.getElementById(textBoxIds[i]);<br>
      autoCompleteWidget.addSession(LDAPSession);<br>
    }<br>
  }</code></p>
Revert to this revision