Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 94168)
+++ channels/chan_sip.c	(working copy)
@@ -310,6 +310,7 @@
 	AUTH_UNKNOWN_DOMAIN = -5,
 	AUTH_PEER_NOT_DYNAMIC = -6,
 	AUTH_ACL_FAILED = -7,
+	AUTH_DIGEST_FORMAT_FAILED = -8
 };
 
 /*! \brief States for outbound registrations (with register= lines in sip.conf */
@@ -1034,14 +1035,14 @@
 	ast_mutex_t pvt_lock;			/*!< Dialog private lock */
 	enum invitestates invitestate;		/*!< Track state of SIP_INVITEs */
 	int method;				/*!< SIP method that opened this dialog */
+	unsigned long randdata;			/*!< Random data for nonce */
+	int qop;				/*!< Quality of Protection flag, if set qop="auth". */
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(callid);	/*!< Global CallID */
-		AST_STRING_FIELD(randdata);	/*!< Random data */
 		AST_STRING_FIELD(accountcode);	/*!< Account code */
 		AST_STRING_FIELD(realm);	/*!< Authorization realm */
 		AST_STRING_FIELD(nonce);	/*!< Authorization nonce */
 		AST_STRING_FIELD(opaque);	/*!< Opaque nonsense */
-		AST_STRING_FIELD(qop);		/*!< Quality of Protection, since SIP wasn't complicated enough yet. */
 		AST_STRING_FIELD(domain);	/*!< Authorization domain */
 		AST_STRING_FIELD(from);		/*!< The From: header */
 		AST_STRING_FIELD(useragent);	/*!< User agent in SIP request */
@@ -1130,7 +1131,7 @@
 	struct sip_route *route;		/*!< Head of linked list of routing steps (fm Record-Route) */
 	int route_persistant;			/*!< Is this the "real" route? */
 	struct sip_auth *peerauth;		/*!< Realm authentication */
-	int noncecount;				/*!< Nonce-count */
+	unsigned long noncecount;		/*!< Nonce-count */
 	char lastmsg[256];			/*!< Last Message sent/received */
 	int amaflags;				/*!< AMA Flags */
 	int pendinginvite;			/*!< Any pending invite ? (seqno of this) */
@@ -1384,7 +1385,6 @@
 		AST_STRING_FIELD(realm);	/*!< Authorization realm */
 		AST_STRING_FIELD(nonce);	/*!< Authorization nonce */
 		AST_STRING_FIELD(opaque);	/*!< Opaque nonsense */
-		AST_STRING_FIELD(qop);		/*!< Quality of Protection, since SIP wasn't complicated enough yet. */
 		AST_STRING_FIELD(domain);	/*!< Authorization domain */
 		AST_STRING_FIELD(username);	/*!< Who we are registering as */
 		AST_STRING_FIELD(authuser);	/*!< Who we *authenticate* as */
@@ -1394,6 +1394,7 @@
 		AST_STRING_FIELD(callback);	/*!< Contact extension */
 		AST_STRING_FIELD(random);
 	);
+	int qop;			/*!< Quality of Protection flag, if set qop="auth". */
 	int portno;			/*!<  Optional port override */
 	int expire;			/*!< Sched ID of expiration */
 	int expiry;			/*!< Value to use for the Expires header */
@@ -1406,7 +1407,7 @@
 	int callid_valid;		/*!< 0 means we haven't chosen callid for this registry yet. */
 	unsigned int ocseq;		/*!< Sequence number we got to for REGISTERs for this registry */
 	struct sockaddr_in us;		/*!< Who the server thinks we are */
-	int noncecount;			/*!< Nonce-count */
+	unsigned long noncecount;	/*!< Nonce-count */
 	char lastmsg[256];		/*!< Last Message sent/received */
 };
 
@@ -1545,7 +1546,7 @@
 static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req);
 static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
 static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
-static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
+static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, unsigned long rand, enum xmittype reliable, const char *header, int stale);
 static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
 static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, int reliable);
 static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmittype reliable, int newbranch);
@@ -5111,6 +5112,8 @@
 	ast_mutex_init(&p->pvt_lock);
 
 	p->method = intended_method;
+	p->randdata = 0;
+	p->noncecount = 0;
 	p->initid = -1;
 	p->waitid = -1;
 	p->autokillid = -1;
@@ -6872,7 +6875,7 @@
 }
 
 /*! \brief Respond with authorization request */
-static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *randdata, enum xmittype reliable, const char *header, int stale)
+static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, unsigned long randdata, enum xmittype reliable, const char *header, int stale)
 {
 	struct sip_request resp;
 	char tmp[512];
@@ -6882,13 +6885,17 @@
 		ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
 		return -1;
 	}
-	/* Stale means that they sent us correct authentication, but 
-	   based it on an old challenge (nonce) */
-	snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", global_realm, randdata, stale ? ", stale=true" : "");
+	/* 
+	 * Create Digest authentication request, as difined in SIP RFC-3261.
+	 * 
+	 * Stale means that they sent us correct authentication, but 
+	 *  based it on an old challenge (nonce)
+	 */
+	snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s", global_realm, randdata, randdata, stale ? ", stale=true" : "");
 	respprep(&resp, p, msg, req);
 	add_header(&resp, header, tmp);
 	add_header_contentLength(&resp, 0);
-	append_history(p, "AuthChal", "Auth challenge sent for %s - nc %d", p->username, p->noncecount);
+	append_history(p, "AuthChal", "Auth challenge sent for %s - nc %lu", p->username, p->noncecount);
 	return send_response(p, &resp, reliable, seqno);
 }
 
@@ -8525,11 +8532,11 @@
 		ast_string_field_set(p, nonce, r->nonce);
 		ast_string_field_set(p, domain, r->domain);
 		ast_string_field_set(p, opaque, r->opaque);
-		ast_string_field_set(p, qop, r->qop);
+		p->qop = r->qop;
 		p->noncecount = ++r->noncecount;
 
 		memset(digest,0,sizeof(digest));
-		if(!build_reply_digest(p, sipmethod, digest, sizeof(digest)))
+		if (!build_reply_digest(p, sipmethod, digest, sizeof(digest)))
 			add_header(&req, "Authorization", digest);
 		else
 			ast_log(LOG_NOTICE, "No authorization available for authentication of registration to %s@%s\n", r->username, r->hostname);
@@ -9173,25 +9180,10 @@
 	const char *authtoken;
 	char a1_hash[256];
 	char resp_hash[256]="";
-	char tmp[BUFSIZ * 2];                /* Make a large enough buffer */
-	char *c;
-	int  wrongnonce = FALSE;
-	int  good_response;
-	const char *usednonce = p->randdata;
+	int  good_response, good_nonce;
+	unsigned long recvnonce;	/* received nonce value in digest */
+	struct ast_http_digest digest;
 
-	/* table of recognised keywords, and their value in the digest */
-	enum keys { K_RESP, K_URI, K_USER, K_NONCE, K_LAST };
-	struct x {
-		const char *key;
-		const char *s;
-	} *i, keys[] = {
-		[K_RESP] = { "response=", "" },
-		[K_URI] = { "uri=", "" },
-		[K_USER] = { "username=", "" },
-		[K_NONCE] = { "nonce=", "" },
-		[K_LAST] = { NULL, NULL}
-	};
-
 	/* Always OK if no secret */
 	if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret))
 		return AUTH_SUCCESSFUL;
@@ -9207,7 +9199,7 @@
 	auth_headers(WWW_AUTH, &respheader, &reqheader);
 
 	authtoken =  get_header(req, reqheader);	
-	if (ignore && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
+	if (ignore && p->randdata && ast_strlen_zero(authtoken)) {
 		/* This is a retransmitted invite/register/etc, don't reconstruct authentication
 		   information */
 		if (!reliable) {
@@ -9218,9 +9210,10 @@
 			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 		}
 		return AUTH_CHALLENGE_SENT;
-	} else if (ast_strlen_zero(p->randdata) || ast_strlen_zero(authtoken)) {
+	} else if (!p->randdata || ast_strlen_zero(authtoken)) {
 		/* We have no auth, so issue challenge and request authentication */
-		ast_string_field_build(p, randdata, "%08lx", ast_random());	/* Create nonce for challenge */
+		p->randdata = ast_random();	/* Create nonce for challenge */
+		p->noncecount = 0;
 		transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
 		/* Schedule auto destroy in 32 seconds */
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -9232,45 +9225,37 @@
 	/* Whoever came up with the authentication section of SIP can suck my %&#$&* for not putting
 	   an example in the spec of just what it is you're doing a hash on. */
 
-
-	/* Make a copy of the response and parse it */
-	ast_copy_string(tmp, authtoken, sizeof(tmp));
-	c = tmp;
-
-	while(c && *(c = ast_skip_blanks(c)) ) { /* lookup for keys */
-		for (i = keys; i->key != NULL; i++) {
-			const char *separator = ",";	/* default */
-
-			if (strncasecmp(c, i->key, strlen(i->key)) != 0)
-				continue;
-			/* Found. Skip keyword, take text in quotes or up to the separator. */
-			c += strlen(i->key);
-			if (*c == '"') { /* in quotes. Skip first and look for last */
-				c++;
-				separator = "\"";
-			}
-			i->s = c;
-			strsep(&c, separator);
-			break;
-		}
-		if (i->key == NULL) /* not found, jump after space or comma */
-			strsep(&c, " ,");
-	}
-
-	/* Verify that digest username matches  the username we auth as */
-	if (strcmp(username, keys[K_USER].s)) {
-		ast_log(LOG_WARNING, "username mismatch, have <%s>, digest has <%s>\n",
-			username, keys[K_USER].s);
+	/* Parse digest */
+	if (ast_parse_digest(authtoken, &digest, 0, pedanticsipchecking))
+		return AUTH_DIGEST_FORMAT_FAILED; /* Bad digest */
+	/* 
+	 * First: Verify that digest username matches the username we auth as
+	 */
+	if (strcmp(username, digest.username)) {
+		ast_log(LOG_WARNING, "Username mismatch, have <%s>, digest has <%s>\n",
+			username, digest.username);
 		/* Oops, we're trying something here */
 		return AUTH_USERNAME_MISMATCH;
 	}
 
-	/* Verify nonce from request matches our nonce.  If not, send 401 with new nonce */
-	if (strcasecmp(p->randdata, keys[K_NONCE].s)) { /* XXX it was 'n'casecmp ? */
-		wrongnonce = TRUE;
-		usednonce = keys[K_NONCE].s;
+	/*
+	 * This nonce value generated by asterisk
+	 * and must be returned as unsigned long in hexdecimal format
+	 */
+	if (sscanf(digest.nonce, "%lx", &recvnonce) != 1) {
+		ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", digest.nonce);
+		/* XXX Resent digest request with new nonce ? XXX */
+		p->randdata = ast_random();
+		p->noncecount = 0;
+		transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, TRUE);
+
+		/* Schedule auto destroy in 32 seconds */
+		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+		return AUTH_CHALLENGE_SENT;
 	}
 
+
+	/* Generate A1 and A1 MD5 hash */
 	if (!ast_strlen_zero(md5secret))
 		ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
 	else {
@@ -9278,51 +9263,85 @@
 		snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret);
 		ast_md5_hash(a1_hash, a1);
 	}
-
-	/* compute the expected response to compare with what we received */
+	
+	/*
+	 * Compute the expected response to compare with what we received
+	 * We use received nonce (and cnonce value, if qop and cnonce exist)
+	 */
 	{
 		char a2[256];
 		char a2_hash[256];
 		char resp[256];
 
-		snprintf(a2, sizeof(a2), "%s:%s", sip_methods[sipmethod].text,
-				S_OR(keys[K_URI].s, uri));
+		snprintf(a2, sizeof(a2), "%s:%s", sip_methods[sipmethod].text, digest.uri); /* "uri" in Digest must exist */
 		ast_md5_hash(a2_hash, a2);
-		snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, usednonce, a2_hash);
+
+		if (digest.qop && *digest.cnonce) {
+			/* 
+			 * Generate RFC-2617 responce.
+			 * Note: cnonce MUST always exist, if qop="auth"
+			 * for http protocol, but I don't know about SIP
+			 */
+			snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", a1_hash, recvnonce, digest.nc, digest.cnonce, a2_hash);
+		} else {
+			/* Generate RFC 2069 responce */
+			snprintf(resp, sizeof(resp), "%s:%08lx:%s", a1_hash, recvnonce, a2_hash);
+		}
 		ast_md5_hash(resp_hash, resp);
 	}
 
-	good_response = keys[K_RESP].s &&
-			!strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash));
-	if (wrongnonce) {
-		ast_string_field_build(p, randdata, "%08lx", ast_random());
-		if (good_response) {
+	 /* Verify response and nonce. */
+	good_response = !strncmp(digest.response, resp_hash, strlen(resp_hash));
+	good_nonce = (p->randdata == recvnonce);
+
+	if (pedanticsipchecking && digest.qop) {
+		/* In pedantic mode we check nonce count for RFC-2617 response */
+		unsigned long nc;
+		sscanf(digest.nc, "%lx", &nc);
+		
+		if (p->noncecount <= nc)
+			p->noncecount = nc;
+		else {
 			if (sipdebug)
-				ast_log(LOG_NOTICE, "Correct auth, but based on stale nonce received from '%s'\n", get_header(req, "To"));
-			/* We got working auth token, based on stale nonce . */
+				ast_log(LOG_NOTICE, "Correct auth, but received nc '%lu', less '%lu'\n", nc, p->noncecount);
+			/* Resent auth request with new nonce */
+			p->randdata = ast_random();
+			p->noncecount = 0;
 			transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, TRUE);
-		} else {
-			/* Everything was wrong, so give the device one more try with a new challenge */
-			if (sipdebug)
-				ast_log(LOG_NOTICE, "Bad authentication received from '%s'\n", get_header(req, "To"));
-			transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, FALSE);
+
+			/* Schedule auto destroy in 32 seconds */
+			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+			return AUTH_CHALLENGE_SENT;
 		}
+	}
 
-		/* Schedule auto destroy in 32 seconds */
-		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-		return AUTH_CHALLENGE_SENT;
-	} 
-	if (good_response) {
+	if (good_response && good_nonce) {
+		 /* Digest verification complete */
 		append_history(p, "AuthOK", "Auth challenge succesful for %s", username);
 		return AUTH_SUCCESSFUL;
 	}
 
-	/* Ok, we have a bad username/secret pair */
-	/* Tell the UAS not to re-send this authentication data, because
-	   it will continue to fail
-	*/
+	if (!good_response) {
+		/*
+		 * If response not match, we have a bad username/secret pair
+		 * Tell the UAS not to re-send this authentication data,
+		 * because   it will continue to fail
+		 */
+		if (sipdebug)
+			ast_log(LOG_NOTICE, "Bad authentication received from '%s'\n", get_header(req, "To"));
+		return AUTH_SECRET_FAILED;
+	}
+	
+	/* Responce is good, but nonce not match */
+	if (sipdebug)
+		ast_log(LOG_NOTICE, "Correct auth, but based on stale nonce received from '%s'\n", get_header(req, "To"));
+	/* Resent auth request with actual nonce */
+	p->noncecount = 0;
+	transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, TRUE);
 
-	return AUTH_SECRET_FAILED;
+	/* Schedule auto destroy in 32 seconds */
+	sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+	return AUTH_CHALLENGE_SENT;
 }
 
 /*! \brief Change onhold state of a peer using a pvt structure */
@@ -9391,7 +9410,7 @@
  */
 static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, int reliable)
 {
-	ast_string_field_build(p, randdata, "%08lx", ast_random());	/* Create nonce for challenge */
+	p->randdata = ast_random();	/* Create nonce for challenge */
 	transmit_response_with_auth(p, "401 Unauthorized", req, p->randdata, reliable, "WWW-Authenticate", 0);
 }
 
@@ -9553,7 +9572,11 @@
 	if (res < 0) {
 		switch (res) {
 		case AUTH_SECRET_FAILED:
-			/* Wrong password in authentication. Go away, don't try again until you fixed it */
+		case AUTH_DIGEST_FORMAT_FAILED:
+			/* 
+			 * Wrong Digest format or password in authentication.
+			 * Go away, don't try again until you fixed it
+			 */
 			transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
 			break;
 		case AUTH_USERNAME_MISMATCH:
@@ -12951,57 +12974,26 @@
 	with  for receiving calls from.  */
 static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, int sipmethod,  char *digest, int digest_len)
 {
-	char tmp[512];
-	char *c;
-	char oldnonce[256];
+	struct ast_http_digest d; /* Digest fields */
+	const char *authreq;
 
-	/* table of recognised keywords, and places where they should be copied */
-	const struct x {
-		const char *key;
-		const ast_string_field *field;
-	} *i, keys[] = {
-		{ "realm=", &p->realm },
-		{ "nonce=", &p->nonce },
-		{ "opaque=", &p->opaque },
-		{ "qop=", &p->qop },
-		{ "domain=", &p->domain },
-		{ NULL, 0 },
-	};
-
-	ast_copy_string(tmp, get_header(req, header), sizeof(tmp));
-	if (ast_strlen_zero(tmp)) 
+	authreq = get_header(req, header);
+	if (ast_parse_digest(authreq, &d, 1, pedanticsipchecking)) {
+		ast_log(LOG_WARNING, "Wrong Digest request.\n");
 		return -1;
-	if (strncasecmp(tmp, "Digest ", strlen("Digest "))) {
-		ast_log(LOG_WARNING, "missing Digest.\n");
-		return -1;
 	}
-	c = tmp + strlen("Digest ");
-	ast_copy_string(oldnonce, p->nonce, sizeof(oldnonce));
-	while (c && *(c = ast_skip_blanks(c))) {	/* lookup for keys */
-		for (i = keys; i->key != NULL; i++) {
-			char *src, *separator;
-			if (strncasecmp(c, i->key, strlen(i->key)) != 0)
-				continue;
-			/* Found. Skip keyword, take text in quotes or up to the separator. */
-			c += strlen(i->key);
-			if (*c == '"') {
-				src = ++c;
-				separator = "\"";
-			} else {
-				src = c;
-				separator = ",";
-			}
-			strsep(&c, separator); /* clear separator and move ptr */
-			ast_string_field_ptr_set(p, i->field, src);
-			break;
-		}
-		if (i->key == NULL) /* not found, try ',' */
-			strsep(&c, ",");
-	}
-	/* Reset nonce count */
-	if (strcmp(p->nonce, oldnonce)) 
+
+	/* New nonce value received - reset nonce count */
+	if (strcmp(d.nonce, p->nonce)) 
 		p->noncecount = 0;
 
+	/* save auth data */
+	ast_string_field_set(p, realm, d.realm);
+	ast_string_field_set(p, nonce, d.nonce);
+	ast_string_field_set(p, domain, d.domain);
+	ast_string_field_set(p, opaque, d.opaque);
+	p->qop = d.qop;
+
 	/* Save auth data for following registrations */
 	if (p->registry) {
 		struct sip_registry *r = p->registry;
@@ -13011,7 +13003,7 @@
 			ast_string_field_set(r, nonce, p->nonce);
 			ast_string_field_set(r, domain, p->domain);
 			ast_string_field_set(r, opaque, p->opaque);
-			ast_string_field_set(r, qop, p->qop);
+			r->qop = p->qop;
 			r->noncecount = 0;
 		}
 	}
@@ -13032,7 +13024,7 @@
 	char resp[256];
 	char resp_hash[256];
 	char uri[256];
-	char cnonce[80];
+	unsigned long cnonce;
 	const char *username;
 	const char *secret;
 	const char *md5secret;
@@ -13045,7 +13037,7 @@
 	else
 		snprintf(uri, sizeof(uri), "sip:%s@%s",p->username, ast_inet_ntoa(p->sa.sin_addr));
 
-	snprintf(cnonce, sizeof(cnonce), "%08lx", ast_random());
+	cnonce = ast_random();
 
  	/* Check if we have separate auth credentials */
  	if ((auth = find_realm_authentication(authl, p->realm))) {
@@ -13075,18 +13067,18 @@
 	ast_md5_hash(a2_hash,a2);
 
 	p->noncecount++;
-	if (!ast_strlen_zero(p->qop))
-		snprintf(resp,sizeof(resp),"%s:%s:%08x:%s:%s:%s", a1_hash, p->nonce, p->noncecount, cnonce, "auth", a2_hash);
+	if (p->qop)
+		snprintf(resp,sizeof(resp),"%s:%s:%08lx:%08lx:auth:%s", a1_hash, p->nonce, p->noncecount, cnonce, a2_hash);
 	else
 		snprintf(resp,sizeof(resp),"%s:%s:%s", a1_hash, p->nonce, a2_hash);
 	ast_md5_hash(resp_hash, resp);
 	/* XXX We hard code our qop to "auth" for now.  XXX */
-	if (!ast_strlen_zero(p->qop))
-		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\", qop=auth, cnonce=\"%s\", nc=%08x", username, p->realm, uri, p->nonce, resp_hash, p->opaque, cnonce, p->noncecount);
+	if (p->qop)
+		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", qop=\"auth\", opaque=\"%s\", cnonce=\"%08lx\", nc=%08lx", username, p->realm, uri, p->nonce, resp_hash, p->opaque, cnonce, p->noncecount);
 	else
-		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\"", username, p->realm, uri, p->nonce, resp_hash, p->opaque);
+		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\"", username, p->realm, uri, p->nonce, resp_hash);
 
-	append_history(p, "AuthResp", "Auth response sent for %s in realm %s - nc %d", username, p->realm, p->noncecount);
+	append_history(p, "AuthResp", "Auth response sent for %s in realm %s - nc %lu", username, p->realm, p->noncecount);
 
 	return 0;
 }
@@ -16535,6 +16527,9 @@
 		case AUTH_ACL_FAILED:
 			reason = "Device does not match ACL";
 			break;
+		case AUTH_DIGEST_FORMAT_FAILED:
+			reason = "Wrong Digest format";
+			break;
 		default:
 			reason = "Unknown failure";
 			break;
@@ -16754,7 +16749,7 @@
 			check_pendings(p);
 		}
 		/* Got an ACK that we did not match. Ignore silently */
-		if (!p->lastinvite && ast_strlen_zero(p->randdata))
+		if (!p->lastinvite && !p->randdata)
 			p->needdestroy = 1;
 		break;
 	default:
