NS_IMETHODIMP
nsAbLDAPAutoCompFormatter::FormatException(PRInt32 aState, 
                                           nsresult aErrorCode, 
                                           nsIAutoCompleteItem **aItem) 
{
    PRInt32 errorKey;
    nsresult rv;

    // create an nsIAutoCompleteItem to hold the returned value
    //
    nsCOMPtr<nsIAutoCompleteItem> item = do_CreateInstance(
        NS_AUTOCOMPLETEITEM_CONTRACTID, &rv);

    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompFormatter::FormatException(): couldn't"
                 " create " NS_AUTOCOMPLETEITEM_CONTRACTID "\n");
        return NS_ERROR_NOT_AVAILABLE;
    }

    // get the string bundle service
    //
    nsString errMsg, ldapErrMsg, alertMsg, ldapHint;
    nsString errCodeNum;

    nsCOMPtr<nsIStringBundleService> stringBundleSvc(do_GetService(
                                            NS_STRINGBUNDLE_CONTRACTID, &rv)); 
    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException():"
                 " error getting string bundle service");
        return rv;
    }

    // get the string bundles relevant here: the main LDAP bundle,
    // and the ldap AutoCompletion-specific bundle
    //
    nsCOMPtr<nsIStringBundle> ldapBundle, ldapACBundle;

    rv = stringBundleSvc->CreateBundle(
        LDAP_ERROR_BUNDLE,
        getter_AddRefs(ldapBundle));
    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException():"
                 " error creating string bundle "
                 LDAP_ERROR_BUNDLE);
        return rv;
    } 

    rv = stringBundleSvc->CreateBundle(
        LDAP_AUTOCOMPLETE_ERROR_BUNDLE,
        getter_AddRefs(ldapACBundle));
    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException():"
                 " error creating string bundle "
                 LDAP_AUTOCOMPLETE_ERROR_BUNDLE);
        return rv;
    }

    // get the general error that goes in the dropdown and the window
    // title
    //
    rv = ldapACBundle->GetStringFromID(aState, getter_Copies(errMsg));
    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException():"
                 " error getting general error from bundle "
                 LDAP_AUTOCOMPLETE_ERROR_BUNDLE);
        return rv;
    }

    // for LDAP errors
    //
    if (NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_LDAP) {

        errorKey = NS_ERROR_GET_CODE(aErrorCode);

        // put the number itself in string form
        //
        errCodeNum.AppendInt(errorKey);

        // get the LDAP error message itself
        //
        rv = ldapBundle->GetStringFromID(NS_ERROR_GET_CODE(aErrorCode), 
                                                getter_Copies(ldapErrMsg));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException"
                     "(): error getting string 2 from bundle "
                     LDAP_ERROR_BUNDLE);
            return rv;
        }
  
    } else {

        // put the entire nsresult in string form
        //
        errCodeNum.AppendLiteral("0x");
        errCodeNum.AppendInt(aErrorCode, 16);    

        // figure out the key to index into the string bundle
        //
        const PRInt32 HOST_NOT_FOUND_ERROR=5000;
        const PRInt32 GENERIC_ERROR=9999;
        errorKey = ( (aErrorCode == NS_ERROR_UNKNOWN_HOST) ? 
                     HOST_NOT_FOUND_ERROR : GENERIC_ERROR );

        // get the specific error message itself
        rv = ldapACBundle->GetStringFromID(errorKey,
                                           getter_Copies(ldapErrMsg));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException"
                     "(): error getting specific non LDAP error-string "
                     "from bundle "
                     LDAP_AUTOCOMPLETE_ERROR_BUNDLE);
            return rv;
        }
    }

    // and try to find a hint about what the user should do next
    //
    const PRInt32 HINT_BASE=10000;
    const PRInt32 GENERIC_HINT_CODE = 9999;
    rv = ldapACBundle->GetStringFromID(HINT_BASE + errorKey, 
                                       getter_Copies(ldapHint));
    if (NS_FAILED(rv)) {
        rv = ldapACBundle->GetStringFromID(HINT_BASE + GENERIC_HINT_CODE,
                                           getter_Copies(ldapHint));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException()"
                     "(): error getting hint string from bundle "
                     LDAP_AUTOCOMPLETE_ERROR_BUNDLE);
            return rv;
        }
    }
        
    const PRUnichar *stringParams[3] = { errCodeNum.get(),
                                         ldapErrMsg.get(), ldapHint.get() };

    rv = ldapACBundle->FormatStringFromName(
        NS_LITERAL_STRING("errorAlertFormat").get(), stringParams, 3,
        getter_Copies(alertMsg));
    if (NS_FAILED(rv)) {
        NS_WARNING("Failed to format warning string\n");
    }

    // put the error message, between angle brackets, into the XPIDL |value|
    // attribute.  Note that the hardcoded string is only used since 
    // stringbundles have already failed us.
    //
    if (errMsg.Length()) {
        nsString tErrMsg(NS_LITERAL_STRING("<"));
        tErrMsg.Append(errMsg);
        tErrMsg.AppendLiteral(">");
        rv = item->SetValue(tErrMsg);
    } else {
        rv = item->SetValue(
            NS_LITERAL_STRING("<Unknown LDAP autocompletion error>"));
    }

    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompFormatter::FormatException(): "
                 "item->SetValue failed");
        return rv;
    }
    
    // pass the alert message in as the param; if that fails, proceed anyway
    //
    nsCOMPtr<nsISupportsString> alert(do_CreateInstance(
                                           NS_SUPPORTS_STRING_CONTRACTID,
                                           &rv));
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompFormatter::FormatException(): "
                   "could not create nsISupportsString");
    } else {
        rv = alert->SetData(alertMsg);
        if (NS_FAILED(rv)) {
            NS_WARNING("nsAbLDAPAutoCompFormatter::FormatException(): "
                     "alert.Set() failed");
        } else {
            rv = item->SetParam(alert);
            if (NS_FAILED(rv)) {
                NS_WARNING("nsAbLDAPAutoCompFormatter::FormatException(): "
                           "item->SetParam failed");
            }
        }
    }

    // this is a remote addressbook, set the class name so the autocomplete 
    // item can be styled to show this
    //
    rv = item->SetClassName("remote-err");
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompleteFormatter::FormatException():"
                   " item->SetClassName() failed");
    }

    // all done; return the item
    //
    NS_IF_ADDREF(*aItem = item);
    return NS_OK;
}
NS_IMETHODIMP nsAbQueryLDAPMessageListener::OnLDAPInit(nsILDAPConnection *aConn, nsresult aStatus)
{
    nsresult rv;
    nsXPIDLString passwd;

    // Make sure that the Init() worked properly
    NS_ENSURE_SUCCESS(aStatus, aStatus);

    if (!mDirectoryQuery)
        return NS_ERROR_NULL_POINTER;

    // If mLogin is set, we're expected to use it to get a password.
    //
    if (!mDirectoryQuery->mLogin.IsEmpty()) {
// XXX hack until nsUTF8AutoString exists
#define nsUTF8AutoString nsCAutoString
        nsUTF8AutoString spec;
        PRBool status;

        // we're going to use the URL spec of the server as the "realm" for
        // wallet to remember the password by / for.
        //
        rv = mDirectoryQuery->mDirectoryUrl->GetSpec(spec);
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbQueryLDAPMessageListener::OnLDAPInit(): GetSpec"
                     " failed\n");
            return NS_ERROR_FAILURE;
        }

        // get the string bundle service
        //
        nsCOMPtr<nsIStringBundleService>
        stringBundleSvc(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbQueryLDAPMessageListener::OnLDAPInit():"
                     " error getting string bundle service");
            return rv;
        }

        // get the LDAP string bundle
        //
        nsCOMPtr<nsIStringBundle> ldapBundle;
        rv = stringBundleSvc->CreateBundle(
                 "chrome://mozldap/locale/ldap.properties",
                 getter_AddRefs(ldapBundle));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbQueryLDAPMessageListener::OnLDAPInit():"
                     " error creating string bundle"
                     " chrome://mozldap/locale/ldap.properties");
            return rv;
        }

        // get the title for the authentication prompt
        //
        nsXPIDLString authPromptTitle;
        rv = ldapBundle->GetStringFromName(
                 NS_LITERAL_STRING("authPromptTitle").get(),
                 getter_Copies(authPromptTitle));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbQueryLDAPMessageListener::OnLDAPInit():"
                     "error getting 'authPromptTitle' string from bundle "
                     "chrome://mozldap/locale/ldap.properties");
            return rv;
        }

        // get the host name for the auth prompt
        //
        nsCAutoString host;
        rv = mUrl->GetAsciiHost(host);
        if (NS_FAILED(rv)) {
            return NS_ERROR_FAILURE;
        }

        // hostTemp is only necessary to work around a code-generation
        // bug in egcs 1.1.2 (the version of gcc that comes with Red Hat 6.2),
        // which is the default compiler for Mozilla on linux at the moment.
        //
        NS_ConvertASCIItoUCS2 hostTemp(host);
        const PRUnichar *hostArray[1] = { hostTemp.get() };

        // format the hostname into the authprompt text string
        //
        nsXPIDLString authPromptText;
        rv = ldapBundle->FormatStringFromName(
                 NS_LITERAL_STRING("authPromptText").get(),
                 hostArray, sizeof(hostArray) / sizeof(const PRUnichar *),
                 getter_Copies(authPromptText));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbQueryLDAPMessageListener::OnLDAPInit():"
                     "error getting 'authPromptText' string from bundle "
                     "chrome://mozldap/locale/ldap.properties");
            return rv;
        }


        // get the window watcher service, so we can get an auth prompter
        //
        nsCOMPtr<nsIWindowWatcher> windowWatcherSvc =
            do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbQueryLDAPMessageListener::OnLDAPInit():"
                     " couldn't get window watcher service.");
            return rv;
        }

        // get the addressbook window, as it will be used to parent the auth
        // prompter dialog
        //
        nsCOMPtr<nsIDOMWindow> abDOMWindow;
        rv = windowWatcherSvc->GetWindowByName(
                 NS_LITERAL_STRING("addressbookWindow").get(), nsnull,
                 getter_AddRefs(abDOMWindow));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbQueryLDAPMessageListener::OnLDAPInit():"
                     " error getting addressbook Window");
            return rv;
        }

        // get the auth prompter itself
        //
        nsCOMPtr<nsIAuthPrompt> authPrompter;
        rv = windowWatcherSvc->GetNewAuthPrompter(
                 abDOMWindow, getter_AddRefs(authPrompter));
        if (NS_FAILED(rv)) {
            NS_ERROR("nsAbQueryLDAPMessageListener::OnLDAPInit():"
                     " error getting auth prompter");
            return rv;
        }

        // get authentication password, prompting the user if necessary
        //
        rv = authPrompter->PromptPassword(
                 authPromptTitle.get(), authPromptText.get(),
                 NS_ConvertUTF8toUCS2(spec).get(),
                 nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY, getter_Copies(passwd),
                 &status);
        if (NS_FAILED(rv) || !status) {
            return NS_ERROR_FAILURE;
        }
    }

    // Initiate the LDAP operation
    nsCOMPtr<nsILDAPOperation> ldapOperation =
        do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsILDAPMessageListener> proxyListener;
    rv = NS_GetProxyForObject(NS_UI_THREAD_EVENTQ,
                              NS_GET_IID(nsILDAPMessageListener),
                              NS_STATIC_CAST(nsILDAPMessageListener *, this),
                              PROXY_SYNC | PROXY_ALWAYS,
                              getter_AddRefs(proxyListener));

    rv = ldapOperation->Init(mConnection, proxyListener, nsnull);
    NS_ENSURE_SUCCESS(rv, rv);

    // Bind
    rv = ldapOperation->SimpleBind(NS_ConvertUCS2toUTF8(passwd));
    NS_ENSURE_SUCCESS(rv, rv);

    return rv;
}