static pj_status_t process_auth( pj_pool_t *req_pool,
				 const pjsip_www_authenticate_hdr *hchal,
				 const pjsip_uri *uri,
				 pjsip_tx_data *tdata,
				 pjsip_auth_clt_sess *sess,
				 pjsip_cached_auth *cached_auth,
				 pjsip_authorization_hdr **h_auth)
{
    const pjsip_cred_info *cred;
    pjsip_authorization_hdr *sent_auth = NULL;
    pjsip_hdr *hdr;
    pj_status_t status;

    /* See if we have sent authorization header for this realm (and scheme) */
    hdr = tdata->msg->hdr.next;
    while (hdr != &tdata->msg->hdr) {
	if ((hchal->type == PJSIP_H_WWW_AUTHENTICATE &&
	     hdr->type == PJSIP_H_AUTHORIZATION) ||
	    (hchal->type == PJSIP_H_PROXY_AUTHENTICATE &&
	     hdr->type == PJSIP_H_PROXY_AUTHORIZATION))
	{
	    sent_auth = (pjsip_authorization_hdr*) hdr;
	    if (pj_stricmp(&hchal->challenge.common.realm,
			   &sent_auth->credential.common.realm)==0 &&
		pj_stricmp(&hchal->scheme, &sent_auth->scheme)==0)
	    {
		/* If this authorization has empty response, remove it. */
		if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
		    sent_auth->credential.digest.response.slen == 0)
		{
		    /* This is empty authorization, remove it. */
		    hdr = hdr->next;
		    pj_list_erase(sent_auth);
		    continue;
		} else
		if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
		    pj_stricmp(&sent_auth->credential.digest.algorithm,
		               &hchal->challenge.digest.algorithm)!=0)
		{
		    /* Same 'digest' scheme but different algo */
		    hdr = hdr->next;
		    continue;
		} else {
		    /* Found previous authorization attempt */
		    break;
		}
	    }
	}
	hdr = hdr->next;
    }

    /* If we have sent, see if server rejected because of stale nonce or
     * other causes.
     */
    if (hdr != &tdata->msg->hdr) {
	pj_bool_t stale;

	/* Detect "stale" state */
	stale = hchal->challenge.digest.stale;
	if (!stale) {
	    /* If stale is false, check is nonce has changed. Some servers
	     * (broken ones!) want to change nonce but they fail to set
	     * stale to true.
	     */
	    stale = pj_strcmp(&hchal->challenge.digest.nonce,
			      &sent_auth->credential.digest.nonce);
	}

	if (stale == PJ_FALSE) {
	    /* Our credential is rejected. No point in trying to re-supply
	     * the same credential.
	     */
	    PJ_LOG(4, (THIS_FILE, "Authorization failed for %.*s@%.*s: "
		       "server rejected with stale=false",
		       sent_auth->credential.digest.username.slen,
		       sent_auth->credential.digest.username.ptr,
		       sent_auth->credential.digest.realm.slen,
		       sent_auth->credential.digest.realm.ptr));
	    return PJSIP_EFAILEDCREDENTIAL;
	}

	cached_auth->stale_cnt++;
	if (cached_auth->stale_cnt >= PJSIP_MAX_STALE_COUNT) {
	    /* Our credential is rejected. No point in trying to re-supply
	     * the same credential.
	     */
	    PJ_LOG(4, (THIS_FILE, "Authorization failed for %.*s@%.*s: "
		       "maximum number of stale retries exceeded",
		       sent_auth->credential.digest.username.slen,
		       sent_auth->credential.digest.username.ptr,
		       sent_auth->credential.digest.realm.slen,
		       sent_auth->credential.digest.realm.ptr));
	    return PJSIP_EAUTHSTALECOUNT;
	}

	/* Otherwise remove old, stale authorization header from the mesasge.
	 * We will supply a new one.
	 */
	pj_list_erase(sent_auth);
    }

    /* Find credential to be used for the challenge. */
    cred = auth_find_cred( sess, &hchal->challenge.common.realm,
			   &hchal->scheme);
    if (!cred) {
	const pj_str_t *realm = &hchal->challenge.common.realm;
	PJ_LOG(4,(THIS_FILE,
		  "Unable to set auth for %s: can not find credential for %.*s/%.*s",
		  tdata->obj_name,
		  realm->slen, realm->ptr,
		  hchal->scheme.slen, hchal->scheme.ptr));
	return PJSIP_ENOCREDENTIAL;
    }

    /* Respond to authorization challenge. */
    status = auth_respond( req_pool, hchal, uri, cred,
			   &tdata->msg->line.req.method,
			   sess->pool, cached_auth, h_auth);
    return status;
}
static pj_status_t process_auth( pj_pool_t *req_pool,
				 const pjsip_www_authenticate_hdr *hchal,
				 const pjsip_uri *uri,
				 pjsip_tx_data *tdata,
				 pjsip_auth_clt_sess *sess,
				 pjsip_cached_auth *cached_auth,
				 pjsip_authorization_hdr **h_auth)
{
    const pjsip_cred_info *cred;
    pjsip_authorization_hdr *sent_auth = NULL;
    pjsip_hdr *hdr;
    pj_status_t status;

     
    hdr = tdata->msg->hdr.next;
    while (hdr != &tdata->msg->hdr) {
	if ((hchal->type == PJSIP_H_WWW_AUTHENTICATE &&
	     hdr->type == PJSIP_H_AUTHORIZATION) ||
	    (hchal->type == PJSIP_H_PROXY_AUTHENTICATE &&
	     hdr->type == PJSIP_H_PROXY_AUTHORIZATION))
	{
	    sent_auth = (pjsip_authorization_hdr*) hdr;
	    if (pj_stricmp(&hchal->challenge.common.realm,
			   &sent_auth->credential.common.realm)==0 &&
		pj_stricmp(&hchal->scheme, &sent_auth->scheme)==0)
	    {
		 
		if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
		    sent_auth->credential.digest.response.slen == 0)
		{
		     
		    hdr = hdr->next;
		    pj_list_erase(sent_auth);
		    continue;
		} else
		if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
		    pj_stricmp(&sent_auth->credential.digest.algorithm,
		               &hchal->challenge.digest.algorithm)!=0)
		{
		     
		    hdr = hdr->next;
		    continue;
		} else {
		     
		    break;
		}
	    }
	}
	hdr = hdr->next;
    }

     
    if (hdr != &tdata->msg->hdr) {
	pj_bool_t stale;

	 
	stale = hchal->challenge.digest.stale;
	if (!stale) {
	     
	    stale = pj_strcmp(&hchal->challenge.digest.nonce,
			      &sent_auth->credential.digest.nonce);
	}

	if (stale == PJ_FALSE) {
	     
	    PJ_LOG(4, (THIS_FILE, "Authorization failed for %.*s@%.*s: "
		       "server rejected with stale=false",
		       sent_auth->credential.digest.username.slen,
		       sent_auth->credential.digest.username.ptr,
		       sent_auth->credential.digest.realm.slen,
		       sent_auth->credential.digest.realm.ptr));
	    return PJSIP_EFAILEDCREDENTIAL;
	}

	cached_auth->stale_cnt++;
	if (cached_auth->stale_cnt >= PJSIP_MAX_STALE_COUNT) {
	     
	    PJ_LOG(4, (THIS_FILE, "Authorization failed for %.*s@%.*s: "
		       "maximum number of stale retries exceeded",
		       sent_auth->credential.digest.username.slen,
		       sent_auth->credential.digest.username.ptr,
		       sent_auth->credential.digest.realm.slen,
		       sent_auth->credential.digest.realm.ptr));
	    return PJSIP_EAUTHSTALECOUNT;
	}

	 
	pj_list_erase(sent_auth);
    }

     
    cred = auth_find_cred( sess, &hchal->challenge.common.realm,
			   &hchal->scheme);
    if (!cred) {
	const pj_str_t *realm = &hchal->challenge.common.realm;
	PJ_LOG(4,(THIS_FILE,
		  "Unable to set auth for %s: can not find credential for %.*s/%.*s",
		  tdata->obj_name,
		  realm->slen, realm->ptr,
		  hchal->scheme.slen, hchal->scheme.ptr));
	return PJSIP_ENOCREDENTIAL;
    }

     
    status = auth_respond( req_pool, hchal, uri, cred,
			   &tdata->msg->line.req.method,
			   sess->pool, cached_auth, h_auth);
    return status;
}