NS_IMETHODIMP nsAbLDAPProcessReplicationData::OnLDAPMessage(nsILDAPMessage *aMessage)
{
  NS_ENSURE_ARG_POINTER(aMessage);

  if (!mInitialized)
    return NS_ERROR_NOT_INITIALIZED;

  PRInt32 messageType;
  nsresult rv = aMessage->GetType(&messageType);
  if (NS_FAILED(rv)) {
    Done(PR_FALSE);
    return rv;
  }

  switch (messageType)
  {
  case nsILDAPMessage::RES_BIND:
    rv = OnLDAPMessageBind(aMessage);
    if (NS_FAILED(rv))
      rv = Abort();
    break;
  case nsILDAPMessage::RES_SEARCH_ENTRY:
    rv = OnLDAPSearchEntry(aMessage);
    break;
  case nsILDAPMessage::RES_SEARCH_RESULT:
    rv = OnLDAPSearchResult(aMessage);
    break;
  default:
    // for messageTypes we do not handle return NS_OK to LDAP and move ahead.
    rv = NS_OK;
    break;
  }

  return rv;
}
/**
 * Messages received are passed back via this function.
 *
 * @arg aMessage  The message that was returned, NULL if none was.
 *
 * void OnLDAPMessage (in nsILDAPMessage aMessage)
 */
NS_IMETHODIMP
nsLDAPAutoCompleteSession::OnLDAPMessage(nsILDAPMessage *aMessage)
{
    PRInt32 messageType;

    // Just in case.
    // XXXdmose the semantics of NULL are currently undefined, but are likely
    // to be defined once we insert timeout handling code into the XPCOM SDK
    // At that time we should figure out if this still the right thing to do.
    if (!aMessage) {
        return NS_OK;
    }

    // Figure out what sort of message was returned.
    nsresult rv = aMessage->GetType(&messageType);
    if (NS_FAILED(rv)) {
        NS_ERROR("nsLDAPAutoCompleteSession::OnLDAPMessage(): unexpected "
                 "error in aMessage->GetType()");

        // Don't call FinishAutoCompleteLookup(), as this could conceivably
        // be an anomaly, and perhaps the next message will be ok. If this
        // really was a problem, this search should eventually get
        // reaped by a timeout (once that code gets implemented).
        return NS_ERROR_UNEXPECTED;
    }

    // If this message is not associated with the current operation,
    // discard it, since it is probably from a previous (aborted)
    // operation.
    bool isCurrent;
    rv = IsMessageCurrent(aMessage, &isCurrent);
    if (NS_FAILED(rv)) {
        // IsMessageCurrent will have logged any necessary errors
        return rv;
    }
    if ( ! isCurrent ) {
        PR_LOG(sLDAPAutoCompleteLogModule, PR_LOG_DEBUG,
               ("nsLDAPAutoCompleteSession::OnLDAPMessage(): received message "
                "from operation other than current one; discarded"));
        return NS_OK;
    }

    // XXXdmose - we may want a small state machine either here or
    // or in the nsLDAPConnection object, to make sure that things are
    // happening in the right order and timing out appropriately. This will
    // certainly depend on how timeouts are implemented, and how binding
    // gets is dealt with by nsILDAPService. Also need to deal with the case
    // where a bind callback happens after onStopLookup was called.
    switch (messageType) {

    case nsILDAPMessage::RES_BIND:

        // A bind has completed
        if (mState != BINDING) {
            PR_LOG(sLDAPAutoCompleteLogModule, PR_LOG_DEBUG,
                   ("nsLDAPAutoCompleteSession::OnLDAPMessage(): LDAP bind "
                    "entry returned after OnStopLookup() called; ignoring"));

            // XXXdmose when nsLDAPService integration happens, need to make
            // sure that the possibility of having an already bound
            // connection, due to a previously unaborted bind, doesn't cause
            // any problems.

            return NS_OK;
        }

        rv = OnLDAPMessageBind(aMessage);
        if (NS_FAILED(rv)) {
            mState = UNBOUND;
            FinishAutoCompleteLookup(nsIAutoCompleteStatus::failureItems,
                                     rv, UNBOUND);
        }
        else
            mState = SEARCHING;

        return rv;

    case nsILDAPMessage::RES_SEARCH_ENTRY:

        // Ignore this if OnStopLookup was already called.
        if (mState != SEARCHING) {
            PR_LOG(sLDAPAutoCompleteLogModule, PR_LOG_DEBUG,
                   ("nsLDAPAutoCompleteSession::OnLDAPMessage(): LDAP search "
                    "entry returned after OnStopLoookup() called; ignoring"));
            return NS_OK;
        }

        // A search entry has been returned.
        return OnLDAPSearchEntry(aMessage);

    case nsILDAPMessage::RES_SEARCH_RESULT:

        // Ignore this if OnStopLookup was already called.
        if (mState != SEARCHING) {
            PR_LOG(sLDAPAutoCompleteLogModule, PR_LOG_DEBUG,
                   ("nsLDAPAutoCompleteSession::OnLDAPMessage(): LDAP search "
                    "result returned after OnStopLookup called; ignoring"));
            return NS_OK;
        }

        // The search is finished; we're all done.
        return OnLDAPSearchResult(aMessage);

    default:

        // Given the LDAP operations nsLDAPAutoCompleteSession uses, we should
        // never get here. If we do get here in a release build, it's
        // probably a bug, but maybe it's the LDAP server doing something
        // weird. Might as well try and continue anyway. The session should
        // eventually get reaped by the timeout code, if necessary.
        //
        NS_ERROR("nsLDAPAutoCompleteSession::OnLDAPMessage(): unexpected "
                 "LDAP message received");
        return NS_OK;
    }
}
NS_IMETHODIMP nsAbQueryLDAPMessageListener::OnLDAPMessage(nsILDAPMessage *aMessage)
{
    nsresult rv;

    rv = Initiate();
    NS_ENSURE_SUCCESS(rv, rv);

    PRInt32 messageType;
    rv = aMessage->GetType(&messageType);
    NS_ENSURE_SUCCESS(rv, rv);

    PRBool cancelOperation = PR_FALSE;

    // Enter lock
    {
        nsAutoLock lock (mLock);

        if (mFinished)
            return NS_OK;

        if (messageType == nsILDAPMessage::RES_SEARCH_RESULT)
            mFinished = PR_TRUE;
        else if (mCanceled)
        {
            mFinished = PR_TRUE;
            cancelOperation = PR_TRUE;
        }
    }
    // Leave lock

    if (!mDirectoryQuery)
        return NS_ERROR_NULL_POINTER;

    nsCOMPtr<nsIAbDirectoryQueryResult> queryResult;
    if (!cancelOperation)
    {
        switch (messageType)
        {
        case nsILDAPMessage::RES_BIND:
            rv = OnLDAPMessageBind (aMessage);
            NS_ENSURE_SUCCESS(rv, rv);
            break;
        case nsILDAPMessage::RES_SEARCH_ENTRY:
            if (!mFinished && !mWaitingForPrevQueryToFinish)
            {
                rv = OnLDAPMessageSearchEntry (aMessage,
                                               getter_AddRefs (queryResult));
            }
            break;
        case nsILDAPMessage::RES_SEARCH_RESULT:
            mWaitingForPrevQueryToFinish = PR_FALSE;
            rv = OnLDAPMessageSearchResult (aMessage, getter_AddRefs (queryResult));
            NS_ENSURE_SUCCESS(rv, rv);
        default:
            break;
        }
    }
    else
    {
        if (mSearchOperation)
            rv = mSearchOperation->AbandonExt ();

        rv = QueryResultStatus (nsnull, getter_AddRefs (queryResult), nsIAbDirectoryQueryResult::queryResultStopped);
        // reset because we might re-use this listener...except don't do this
        // until the search is done, so we'll ignore results from a previous
        // search.
        if (messageType == nsILDAPMessage::RES_SEARCH_RESULT)
            mCanceled = mFinished = PR_FALSE;

    }

    if (queryResult && mQueryListener)
        rv = mQueryListener->OnQueryItem (queryResult);

    return rv;
}