Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 7516)
+++ channels/chan_sip.c	(working copy)
@@ -492,10 +492,12 @@
 
 /*! \brief sip_history: Structure for saving transactions within a SIP dialog */
 struct sip_history {
-	char event[80];
-	struct sip_history *next;
+	AST_LIST_ENTRY(sip_history) list;
+	char event[0];	/* actually more, depending on needs */
 };
 
+AST_LIST_HEAD_NOLOCK(sip_history_head, sip_history); /*!< history list, entry in sip_pvt */
+
 /*! \brief sip_auth: Creadentials for authentication to other SIP services */
 struct sip_auth {
 	char realm[AST_MAX_EXTENSION];  /*!< Realm in which these credentials are valid */
@@ -687,7 +689,7 @@
 	struct ast_rtp *rtp;			/*!< RTP Session */
 	struct ast_rtp *vrtp;			/*!< Video RTP session */
 	struct sip_pkt *packets;		/*!< Packets scheduled for re-transmission */
-	struct sip_history *history;		/*!< History of this SIP dialog */
+	struct sip_history_head *history;	/*!< History of this SIP dialog */
 	struct ast_variable *chanvars;		/*!< Channel variables to set for call */
 	struct sip_pvt *next;			/*!< Next call in chain */
 	struct sip_invite_param *options;	/*!< Options for INVITE */
@@ -1123,40 +1125,49 @@
 
 /*! \brief  append_history: Append to SIP dialog history */
 /*	Always returns 0 */
-static int append_history(struct sip_pvt *p, const char *event, const char *data)
+#define append_history(p, event, fmt , args... )	append_history_full(p, "%-15s " fmt, event, ## args)
+
+static int append_history_full(struct sip_pvt *p, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+
+static void append_history_va(struct sip_pvt *p, const char *fmt, va_list ap)
 {
-	struct sip_history *hist, *prev;
-	char *c;
+	char buf[80], *c = buf; /* max history length */
+	struct sip_history *hist;
+	int l;
 
-	if (!recordhistory || !p)
-		return 0;
-	if(!(hist = malloc(sizeof(struct sip_history)))) {
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	strsep(&c, "\r\n"); /* Trim up everything after \r or \n */
+	l = strlen(buf) + 1;
+	hist = calloc(1, sizeof(*hist) + l);
+	if (!hist) {
 		ast_log(LOG_WARNING, "Can't allocate memory for history");
-		return 0;
+		return;
 	}
-	memset(hist, 0, sizeof(struct sip_history));
-	snprintf(hist->event, sizeof(hist->event), "%-15s %s", event, data);
-	/* Trim up nicely */
-	c = hist->event;
-	while(*c) {
-		if ((*c == '\r') || (*c == '\n')) {
-			*c = '\0';
-			break;
-		}
-		c++;
+	if (p->history == NULL)
+		p->history = calloc(1, sizeof(struct sip_history_head));
+	if (p->history == NULL) {
+		ast_log(LOG_WARNING, "Can't allocate memory for history head");
+		free(hist);
+		return;
 	}
-	/* Enqueue into history */
-	prev = p->history;
-	if (prev) {
-		while(prev->next)
-			prev = prev->next;
-		prev->next = hist;
-	} else {
-		p->history = hist;
-	}
-	return 0;
+	memcpy(hist->event, buf, l);
+	AST_LIST_INSERT_TAIL(p->history, hist, list);
 }
 
+static int append_history_full(struct sip_pvt *p, const char *fmt, ...)
+{
+        va_list ap;
+
+	if (!recordhistory || !p)
+		return 0;
+        va_start(ap, fmt);
+        append_history_va(p, fmt, ap);
+        va_end(ap);
+
+        return 0;
+}
+
 /*! \brief  retrans_pkt: Retransmit SIP message if no answer ---*/
 static int retrans_pkt(void *data)
 {
@@ -1168,8 +1179,6 @@
 	ast_mutex_lock(&pkt->owner->lock);
 
 	if (pkt->retrans < MAX_RETRANS) {
-		char buf[80];
-
 		pkt->retrans++;
  		if (!pkt->timer_t1) {	/* Re-schedule using timer_a and timer_t1 */
 			if (sipdebug && option_debug > 3)
@@ -1201,9 +1210,8 @@
 			else
 				ast_verbose("Retransmitting #%d (no NAT) to %s:%d:\n%s\n---\n", pkt->retrans, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->sa.sin_addr), ntohs(pkt->owner->sa.sin_port), pkt->data);
 		}
-		snprintf(buf, sizeof(buf), "ReTx %d", reschedule);
 
-		append_history(pkt->owner, buf, pkt->data);
+		append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data);
 		__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
 		ast_mutex_unlock(&pkt->owner->lock);
 		return  reschedule;
@@ -1214,7 +1222,7 @@
 		if ((pkt->method == SIP_OPTIONS) && sipdebug)
 			ast_log(LOG_WARNING, "Cancelling retransmit of OPTIONs (call id %s) \n", pkt->owner->callid);
 	}
-	append_history(pkt->owner, "MaxRetries", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
+	append_history(pkt->owner, "MaxRetries", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
  		
 	pkt->retransid = -1;
 
@@ -1326,13 +1334,10 @@
 /*! \brief  sip_scheddestroy: Schedule destruction of SIP call ---*/
 static int sip_scheddestroy(struct sip_pvt *p, int ms)
 {
-	char tmp[80];
 	if (sip_debug_test_pvt(p))
 		ast_verbose("Scheduling destruction of call '%s' in %d ms\n", p->callid, ms);
-	if (recordhistory) {
-		snprintf(tmp, sizeof(tmp), "%d ms", ms);
-		append_history(p, "SchedDestroy", tmp);
-	}
+	if (recordhistory)
+		append_history(p, "SchedDestroy", "%d ms", ms);
 
 	if (p->autokillid > -1)
 		ast_sched_del(sched, p->autokillid);
@@ -1464,31 +1469,22 @@
 static int send_response(struct sip_pvt *p, struct sip_request *req, int reliable, int seqno)
 {
 	int res;
-	char iabuf[INET_ADDRSTRLEN];
-	struct sip_request tmp;
-	char tmpmsg[80];
 
 	if (sip_debug_test_pvt(p)) {
+		char iabuf[INET_ADDRSTRLEN];
 		if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)
 			ast_verbose("%sTransmitting (NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port), req->data);
 		else
 			ast_verbose("%sTransmitting (no NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port), req->data);
 	}
-	if (reliable) {
-		if (recordhistory) {
-			parse_copy(&tmp, req);
-			snprintf(tmpmsg, sizeof(tmpmsg), "%s / %s", tmp.data, get_header(&tmp, "CSeq"));
-			append_history(p, "TxRespRel", tmpmsg);
-		}
-		res = __sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable > 1), req->method);
-	} else {
-		if (recordhistory) {
-			parse_copy(&tmp, req);
-			snprintf(tmpmsg, sizeof(tmpmsg), "%s / %s", tmp.data, get_header(&tmp, "CSeq"));
-			append_history(p, "TxResp", tmpmsg);
-		}
-		res = __sip_xmit(p, req->data, req->len);
+	if (recordhistory) {
+		struct sip_request tmp;
+		parse_copy(&tmp, req);
+		append_history(p, reliable ? "TxRespRel" : "TxResp", "%s / %s", tmp.data, get_header(&tmp, "CSeq"));
 	}
+	res = (reliable) ?
+		__sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable > 1), req->method) :
+		__sip_xmit(p, req->data, req->len);
 	if (res > 0)
 		return 0;
 	return res;
@@ -1498,31 +1494,22 @@
 static int send_request(struct sip_pvt *p, struct sip_request *req, int reliable, int seqno)
 {
 	int res;
-	char iabuf[INET_ADDRSTRLEN];
-	struct sip_request tmp;
-	char tmpmsg[80];
 
 	if (sip_debug_test_pvt(p)) {
+		char iabuf[INET_ADDRSTRLEN];
 		if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)
 			ast_verbose("%sTransmitting (NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port), req->data);
 		else
 			ast_verbose("%sTransmitting (no NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port), req->data);
 	}
-	if (reliable) {
-		if (recordhistory) {
-			parse_copy(&tmp, req);
-			snprintf(tmpmsg, sizeof(tmpmsg), "%s / %s", tmp.data, get_header(&tmp, "CSeq"));
-			append_history(p, "TxReqRel", tmpmsg);
-		}
-		res = __sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable > 1), req->method);
-	} else {
-		if (recordhistory) {
-			parse_copy(&tmp, req);
-			snprintf(tmpmsg, sizeof(tmpmsg), "%s / %s", tmp.data, get_header(&tmp, "CSeq"));
-			append_history(p, "TxReq", tmpmsg);
-		}
-		res = __sip_xmit(p, req->data, req->len);
+	if (recordhistory) {
+		struct sip_request tmp;
+		parse_copy(&tmp, req);
+		append_history(p, reliable ? "TxReqRel" : "TxReq", "%s / %s", tmp.data, get_header(&tmp, "CSeq"));
 	}
+	res = (reliable) ?
+		__sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable > 1), req->method) :
+		__sip_xmit(p, req->data, req->len);
 	return res;
 }
 
@@ -2094,7 +2074,6 @@
 {
 	struct sip_pvt *cur, *prev = NULL;
 	struct sip_pkt *cp;
-	struct sip_history *hist;
 
 	if (sip_debug_test_pvt(p))
 		ast_verbose("Destroying call '%s'\n", p->callid);
@@ -2144,10 +2123,14 @@
 			ast_mutex_unlock(&p->owner->lock);
 	}
 	/* Clear history */
-	while(p->history) {
-		hist = p->history;
-		p->history = p->history->next;
-		free(hist);
+	if (p->history) {
+		while(!AST_LIST_EMPTY(p->history)) {
+			struct sip_history *hist = AST_LIST_FIRST(p->history);
+			AST_LIST_REMOVE_HEAD(p->history, list);
+			free(hist);
+		}
+		free(p->history);
+		p->history = NULL;
 	}
 
 	cur = iflist;
@@ -3629,7 +3622,7 @@
 
 	/* Manager Hold and Unhold events must be generated, if necessary */
 	if (sin.sin_addr.s_addr && !sendonly) {	        
-	        append_history(p, "Unhold", req->data);
+	        append_history(p, "Unhold", "%s", req->data);
 
 		if (callevents && ast_test_flag(p, SIP_CALL_ONHOLD)) {
 			manager_event(EVENT_FLAG_CALL, "Unhold",
@@ -3642,7 +3635,7 @@
 		ast_clear_flag(p, SIP_CALL_ONHOLD);
 	} else {	        
 		/* No address for RTP, we're on hold */
-	        append_history(p, "Hold", req->data);
+	        append_history(p, "Hold", "%s", req->data);
 
 	        if (callevents && !ast_test_flag(p, SIP_CALL_ONHOLD)) {
 			manager_event(EVENT_FLAG_CALL, "Hold",
@@ -5230,11 +5223,8 @@
 	if (!r)
 		return 0;
 
-	if (r->call && recordhistory) {
-		char tmp[80];
-		snprintf(tmp, sizeof(tmp), "Account: %s@%s", r->username, r->hostname);
-		append_history(r->call, "RegistryRenew", tmp);
-	}
+	if (r->call && recordhistory)
+		append_history(r->call, "RegistryRenew", "Account: %s@%s", r->username, r->hostname);
 	/* Since registry's are only added/removed by the the monitor thread, this
 	   may be overkill to reference/dereference at all here */
 	if (sipdebug)
@@ -5335,11 +5325,8 @@
 			ast_log(LOG_WARNING, "Unable to allocate registration call\n");
 			return 0;
 		}
-		if (recordhistory) {
-			char tmp[80];
-			snprintf(tmp, sizeof(tmp), "Account: %s@%s", r->username, r->hostname);
-			append_history(p, "RegistryInit", tmp);
-		}
+		if (recordhistory)
+			append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname);
 		/* Find address to hostname */
 		if (create_addr(p, r->hostname)) {
 			/* we have what we hope is a temporary network error,
@@ -6316,7 +6273,7 @@
 		ast_verbose(VERBOSE_PREFIX_2 "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
 		p->stateid = -1;
 		p->subscribed = NONE;
-		append_history(p, "Subscribestatus", state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
+		append_history(p, "Subscribestatus", "%s", state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
 		break;
 	default:	/* Tell user */
 		p->laststate = state;
@@ -8509,9 +8467,7 @@
 static int sip_show_history(int fd, int argc, char *argv[])
 {
 	struct sip_pvt *cur;
-	struct sip_history *hist;
 	size_t len;
-	int x;
 	int found = 0;
 
 	if (argc != 4)
@@ -8523,19 +8479,18 @@
 	cur = iflist;
 	while(cur) {
 		if (!strncasecmp(cur->callid, argv[3], len)) {
+			struct sip_history *hist;
+			int x = 0;
+
 			ast_cli(fd,"\n");
 			if (cur->subscribed != NONE)
 				ast_cli(fd, "  * Subscription\n");
 			else
 				ast_cli(fd, "  * SIP Call\n");
-			x = 0;
-			hist = cur->history;
-			while(hist) {
-				x++;
-				ast_cli(fd, "%d. %s\n", x, hist->event);
-				hist = hist->next;
-			}
-			if (!x)
+			if (cur->history)
+				AST_LIST_TRAVERSE(cur->history, hist, list)
+					ast_cli(fd, "%d. %s\n", x++, hist->event);
+			if (x == 0)
 				ast_cli(fd, "Call '%s' has no history\n", cur->callid);
 			found++;
 		}
@@ -8551,7 +8506,7 @@
   lifespan for SIP dialog */
 void sip_dump_history(struct sip_pvt *dialog)
 {
-	int x;
+	int x = 0;
 	struct sip_history *hist;
 
 	if (!dialog)
@@ -8562,17 +8517,12 @@
 		ast_log(LOG_DEBUG, "  * Subscription\n");
 	else
 		ast_log(LOG_DEBUG, "  * SIP Call\n");
-	x = 0;
-	hist = dialog->history;
-	while(hist) {
-		x++;
-		ast_log(LOG_DEBUG, "  %d. %s\n", x, hist->event);
-		hist = hist->next;
-	}
+	if (dialog->history)
+		AST_LIST_TRAVERSE(dialog->history, hist, list)
+			ast_log(LOG_DEBUG, "  %d. %s\n", x++, hist->event);
 	if (!x)
 		ast_log(LOG_DEBUG, "Call '%s' has no history\n", dialog->callid);
 	ast_log(LOG_DEBUG, "\n---------- END SIP HISTORY for '%s' \n", dialog->callid);
-	
 }
 
 
@@ -8853,11 +8801,8 @@
  			/* No old challenge */
 		return -1;
 	}
-	if (recordhistory) {
-		char tmp[80];
-		snprintf(tmp, sizeof(tmp), "Try: %d", p->authtries);
-		append_history(p, "RegistryAuth", tmp);
-	}
+	if (recordhistory)
+		append_history(p, "RegistryAuth", "Try: %d", p->authtries);
  	if (sip_debug_test_pvt(p) && p->registry)
  		ast_verbose("Responding to challenge, registration to domain/host name %s\n", p->registry->hostname);
 	return transmit_register(p->registry, SIP_REGISTER, digest, respheader); 
@@ -8998,6 +8943,8 @@
 
  	/* Check if we have separate auth credentials */
  	if ((auth = find_realm_authentication(authl, p->realm))) {
+		ast_log(LOG_WARNING, "use realm [%s] from peer [%s][%s]\n",
+			auth->username, p->peername, p->username);
  		username = auth->username;
  		secret = auth->secret;
  		md5secret = auth->md5secret;
@@ -10802,7 +10750,7 @@
 
 			transmit_response(p, "200 OK", req);
 			transmit_state_notify(p, firststate, 1, 1);	/* Send first notification */
-			append_history(p, "Subscribestatus", ast_extension_state2str(firststate));
+			append_history(p, "Subscribestatus", "%s", ast_extension_state2str(firststate));
 
 			/* remove any old subscription from this peer for the same exten/context,
 			   as the peer has obviously forgotten about it and it's wasteful to wait
@@ -11123,12 +11071,8 @@
 			goto retrylock;
 		}
 		memcpy(&p->recv, &sin, sizeof(p->recv));
-		if (recordhistory) {
-			char tmp[80];
-			/* This is a response, note what it was for */
-			snprintf(tmp, sizeof(tmp), "%s / %s", req.data, get_header(&req, "CSeq"));
-			append_history(p, "Rx", tmp);
-		}
+		if (recordhistory) /* This is a response, note what it was for */
+			append_history(p, "Rx", "%s / %s", req.data, get_header(&req, "CSeq"));
 		nounlock = 0;
 		if (handle_request(p, &req, &sin, &recount, &nounlock) == -1) {
 			/* Request failed */
