NS_IMETHODIMP
nsAbLDAPAutoCompFormatter::GetAttributes(nsACString &aResult)
{
    nsCAutoString searchAttrs;
    nsresult rv = ProcessFormat(mNameFormat, 0, 0, &searchAttrs);
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
                   "ProcessFormat() failed");
        return rv;
    }
    rv = ProcessFormat(mAddressFormat, 0, 0, &searchAttrs);
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
                   "ProcessFormat() failed");
        return rv;
    }
    rv = ProcessFormat(mCommentFormat, 0, 0, &searchAttrs);
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
                   "ProcessFormat() failed");
        return rv;
    }

    aResult = searchAttrs;
    return NS_OK;
}
NS_IMETHODIMP
nsAbLDAPAutoCompFormatter::Format(nsILDAPMessage *aMsg, 
                                  nsIAutoCompleteItem **aItem) 
{
    nsresult rv;

    nsCOMPtr<nsIMsgHeaderParser> msgHdrParser = 
        do_GetService("@mozilla.org/messenger/headerparser;1", &rv);
    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompFormatter::Format(): do_GetService()"
                 " failed trying to obtain"
                 " '@mozilla.org/messenger/headerparser;1'");
        return NS_ERROR_NOT_AVAILABLE;
    }

    // generate the appropriate string
    //
    nsCAutoString name;
    rv = ProcessFormat(mNameFormat, aMsg, &name, 0);
    if (NS_FAILED(rv)) {
        // Something went wrong lower down the stack; a message should
        // have already been logged there.  Return an error, rather
        // than trying to generate a bogus nsIAutoCompleteItem
        //
        return rv;
    }

    nsCAutoString address;
    rv = ProcessFormat(mAddressFormat, aMsg, &address, 0);
    if (NS_FAILED(rv)) {
        // Something went wrong lower down the stack; a message should have 
        // already been logged there.  Return an error, rather than trying to 
        // generate a bogus nsIAutoCompleteItem.
        //
        return rv;
    }

    nsCString value;
    rv = msgHdrParser->MakeFullAddressString(name.get(), address.get(), 
                                             getter_Copies(value));
    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompFormatter::Format(): call to"
                 " MakeFullAddressString() failed");
        return 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::Format(): couldn't"
                 " create " NS_AUTOCOMPLETEITEM_CONTRACTID "\n");
        return NS_ERROR_NOT_AVAILABLE;
    }

    // this is that part that actually gets autocompleted to
    //
    rv = item->SetValue(NS_ConvertUTF8toUTF16(value));
    if (NS_FAILED(rv)) {
        NS_ERROR("nsAbLDAPAutoCompFormatter::Format(): "
                 "item->SetValue failed");
        return rv;
    }

    // generate the appropriate string to appear as a comment off to the side
    //
    nsCAutoString comment;
    rv = ProcessFormat(mCommentFormat, aMsg, &comment, 0);
    if (NS_SUCCEEDED(rv)) {
        rv = item->SetComment(NS_ConvertUTF8toUTF16(comment).get());
        if (NS_FAILED(rv)) {
            NS_WARNING("nsAbLDAPAutoCompFormatter::Format():"
                       " item->SetComment() failed");
        }
    }

    rv = item->SetClassName("remote-abook");
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompleteFormatter::Format():"
                   " item->SetClassName() failed");
    }

    // all done; return the item
    NS_IF_ADDREF(*aItem = item);
    return NS_OK;
}
NS_IMETHODIMP
nsAbLDAPAutoCompFormatter::GetAttributes(PRUint32 *aCount, char ** *aAttrs)
{
    if (!aCount || !aAttrs) {
        return NS_ERROR_INVALID_POINTER;
    }

    nsCStringArray mSearchAttrs;
    nsresult rv = ProcessFormat(mNameFormat, 0, 0, &mSearchAttrs);
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
                   "ProcessFormat() failed");
        return rv;
    }
    rv = ProcessFormat(mAddressFormat, 0, 0, &mSearchAttrs);
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
                   "ProcessFormat() failed");
        return rv;
    }
    rv = ProcessFormat(mCommentFormat, 0, 0, &mSearchAttrs);
    if (NS_FAILED(rv)) {
        NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
                   "ProcessFormat() failed");
        return rv;
    }

    // none of the formatting templates require any LDAP attributes
    //
    PRUint32 count = mSearchAttrs.Count();   // size of XPCOM array we'll need
    if (!count) {
        NS_ERROR("nsAbLDAPAutoCompFormatter::GetAttributes(): "
                 "current output format (if set) requires no search "
                 "attributes");
        return NS_ERROR_NOT_INITIALIZED;
    }

    // build up the raw XPCOM array to return
    //
    PRUint32 rawSearchAttrsSize = 0;        // grown as XPCOM array is built
    char **rawSearchAttrs = 
        static_cast<char **>(nsMemory::Alloc(count * sizeof(char *)));
    if (!rawSearchAttrs) {
        NS_ERROR("nsAbLDAPAutoCompFormatter::GetAttributes(): out of "
		 "memory");
        return NS_ERROR_OUT_OF_MEMORY;
    }

    // Loop through the string array, and build up the C-array.
    //
    while (rawSearchAttrsSize < count) {
        if (!(rawSearchAttrs[rawSearchAttrsSize] = 
              ToNewCString(*(mSearchAttrs.CStringAt(rawSearchAttrsSize))))) {
            NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(rawSearchAttrsSize, 
                                                  rawSearchAttrs);
            NS_ERROR("nsAbLDAPAutoCompFormatter::GetAttributes(): out "
		     "of memory");
            return NS_ERROR_OUT_OF_MEMORY;
        }
        rawSearchAttrsSize++;
    }

    *aCount = rawSearchAttrsSize;
    *aAttrs = rawSearchAttrs;

    return NS_OK;

}