Index: channels/chan_agent.c
===================================================================
--- channels/chan_agent.c	(revision 353685)
+++ channels/chan_agent.c	(working copy)
@@ -554,7 +554,18 @@
 	struct ast_frame *f = NULL;
 	static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
 	int cur_time = time(NULL);
+	struct ast_channel *owner = NULL;
+
 	ast_mutex_lock(&p->lock);
+	if (p->owner) {
+		ast_channel_ref(p->owner);
+		owner = p->owner;
+		/* Haven't used lock yet, so it should be safe to unlock it and retrieve the channel lock. */
+		ast_mutex_unlock(&p->lock);
+		ast_channel_lock(owner);
+		ast_mutex_lock(&p->lock);
+	}
+
 	CHECK_FORMATS(ast, p);
 	if (!p->start) {
 		p->start = cur_time;
@@ -584,14 +595,13 @@
 			int howlong = cur_time - p->start;
 			if (p->autologoff && (howlong >= p->autologoff)) {
 				ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
-				if (p->owner || p->chan) {
-					while (p->owner && ast_channel_trylock(p->owner)) {
-						DEADLOCK_AVOIDANCE(&p->lock);
+				if (owner || p->chan) {
+					if (owner) {
+						ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
+						ast_channel_unlock(owner);
+						ast_channel_unref(owner);
+						owner = NULL;
 					}
-					if (p->owner) {
-						ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
-						ast_channel_unlock(p->owner);
-					}
 
 					while (p->chan && ast_channel_trylock(p->chan)) {
 						DEADLOCK_AVOIDANCE(&p->lock);
@@ -652,6 +662,12 @@
 		}
 	}
 
+	if (owner) {
+		ast_channel_unlock(owner);
+		ast_channel_unref(owner);
+		owner = NULL;
+	}
+
 	CLEANUP(ast,p);
 	if (p->chan && !p->chan->_bridge) {
 		if (strcasecmp(p->chan->tech->type, "Local")) {
@@ -887,7 +903,14 @@
 static int agent_hangup(struct ast_channel *ast)
 {
 	struct agent_pvt *p = ast->tech_pvt;
+	struct ast_channel *indicate_chan = NULL;
 
+	if (p->pending) {
+		AST_LIST_LOCK(&agents);
+		AST_LIST_REMOVE(&agents, p, list);
+		AST_LIST_UNLOCK(&agents);
+	}
+
 	ast_mutex_lock(&p->lock);
 	p->owner = NULL;
 	ast->tech_pvt = NULL;
@@ -909,7 +932,7 @@
 	if (p->start && (ast->_state != AST_STATE_UP)) {
 		p->start = 0;
 	} else
-		p->start = 0; 
+		p->start = 0;
 	if (p->chan) {
 		p->chan->_bridge = NULL;
 		/* If they're dead, go ahead and hang up on the agent now */
@@ -918,15 +941,21 @@
 			ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
 			ast_channel_unlock(p->chan);
 		} else if (p->loginstart) {
-			ast_channel_lock(p->chan);
-			ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
-				S_OR(p->moh, NULL),
-				!ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
-			ast_channel_unlock(p->chan);
+			ast_channel_ref(p->chan); /* Ref p->chan since we are going to use it after unlocking the pvt later. */
+			indicate_chan = p->chan;
 		}
 	}
 	ast_mutex_unlock(&p->lock);
 
+	if (indicate_chan) {
+		ast_channel_lock(indicate_chan);
+		ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
+			S_OR(p->moh, NULL),
+			!ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
+		ast_channel_unlock(indicate_chan);
+		ast_channel_unref(indicate_chan);
+	}
+
 	/* Only register a device state change if the agent is still logged in */
 	if (!p->loginstart) {
 		p->logincallerid[0] = '\0';
@@ -934,11 +963,6 @@
 		ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
 	}
 
-	if (p->pending) {
-		AST_LIST_LOCK(&agents);
-		AST_LIST_REMOVE(&agents, p, list);
-		AST_LIST_UNLOCK(&agents);
-	}
 	if (p->abouttograb) {
 		/* Let the "about to grab" thread know this isn't valid anymore, and let it
 		   kill it later */
@@ -1508,13 +1532,24 @@
 	char *status = NULL;
 	struct ast_channel *bridge;
 
-	if (!ast_strlen_zero(id))
+	if (!ast_strlen_zero(id)) {
 		snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
+	}
 	astman_send_ack(s, m, "Agents will follow");
 	AST_LIST_LOCK(&agents);
 	AST_LIST_TRAVERSE(&agents, p, list) {
-        	ast_mutex_lock(&p->lock);
+		struct ast_channel *owner = NULL;
+		ast_mutex_lock(&p->lock);
+		if (p->owner) {
+			ast_channel_ref(p->owner);
+			owner = p->owner;
+			/* Haven't used lock yet, so it should be safe to unlock it and retrieve the channel lock. */
+			ast_mutex_unlock(&p->lock);
+			ast_channel_lock(owner);
+			ast_mutex_lock(&p->lock);
+		}
 
+
 		/* Status Values:
 		   AGENT_LOGGEDOFF - Agent isn't logged in
 		   AGENT_IDLE      - Agent is logged in, and waiting for call
@@ -1528,16 +1563,14 @@
 
 		if (p->chan) {
 			loginChan = ast_strdupa(p->chan->name);
-			if (p->owner && p->owner->_bridge) {
+			if (owner && owner->_bridge) {
 				talkingto = S_COR(p->chan->caller.id.number.valid,
 					p->chan->caller.id.number.str, "n/a");
-				ast_channel_lock(p->owner);
-				if ((bridge = ast_bridged_channel(p->owner))) {
+				if ((bridge = ast_bridged_channel(owner))) {
 					talkingtoChan = ast_strdupa(bridge->name);
 				} else {
 					talkingtoChan = "n/a";
 				}
-				ast_channel_unlock(p->owner);
 				status = "AGENT_ONCALL";
 			} else {
 				talkingto = "n/a";
@@ -1551,6 +1584,12 @@
 			status = "AGENT_LOGGEDOFF";
 		}
 
+		if (owner) {
+			ast_channel_unlock(owner);
+			ast_channel_unref(owner);
+			owner = NULL;
+		}
+
 		astman_append(s, "Event: Agents\r\n"
 			"Agent: %s\r\n"
 			"Name: %s\r\n"
@@ -1582,14 +1621,20 @@
 			ret = 0;
 			if (p->owner || p->chan) {
 				if (!soft) {
+					struct ast_channel *owner = NULL;
 					ast_mutex_lock(&p->lock);
+					if (p->owner) {
+						ast_channel_ref(p->owner);
+						owner = p->owner;
+						ast_channel_lock(owner);
+						ast_mutex_lock(&p->lock);
+					}
 
-					while (p->owner && ast_channel_trylock(p->owner)) {
-						DEADLOCK_AVOIDANCE(&p->lock);
-					}
-					if (p->owner) {
+					if (owner) {
 						ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
-						ast_channel_unlock(p->owner);
+						ast_channel_unlock(owner);
+						ast_channel_unref(owner);
+						owner = NULL;
 					}
 
 					while (p->chan && ast_channel_trylock(p->chan)) {
@@ -1726,7 +1771,16 @@
 
 	AST_LIST_LOCK(&agents);
 	AST_LIST_TRAVERSE(&agents, p, list) {
+		struct ast_channel *owner = NULL;
 		ast_mutex_lock(&p->lock);
+		if (p->owner) {
+			ast_channel_ref(p->owner);
+			owner = p->owner;
+			/* Haven't used lock yet, so it should be safe to unlock it and retrieve the channel lock. */
+			ast_mutex_unlock(&p->lock);
+			ast_channel_lock(owner);
+			ast_mutex_lock(&p->lock);
+		}
 		if (p->pending) {
 			if (p->group)
 				ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
@@ -1739,10 +1793,11 @@
 				username[0] = '\0';
 			if (p->chan) {
 				snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
-				if (p->owner && ast_bridged_channel(p->owner))
+				if (owner && ast_bridged_channel(owner)) {
 					snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
-				 else 
+				} else {
 					strcpy(talkingto, " is idle");
+				}
 				online_agents++;
 			} else {
 				strcpy(location, "not logged in");
@@ -1755,6 +1810,12 @@
 				username, location, talkingto, music);
 			count_agents++;
 		}
+
+		if (owner) {
+			ast_channel_unlock(owner);
+			ast_channel_unref(owner);
+			owner = NULL;
+		}
 		ast_mutex_unlock(&p->lock);
 	}
 	AST_LIST_UNLOCK(&agents);
@@ -1795,21 +1856,40 @@
 
 	AST_LIST_LOCK(&agents);
 	AST_LIST_TRAVERSE(&agents, p, list) {
+		struct ast_channel *owner = NULL;
+
 		agent_status = 0;       /* reset it to offline */
 		ast_mutex_lock(&p->lock);
+		if (p->owner) {
+			ast_channel_ref(p->owner);
+			owner = p->owner;
+			/* Haven't used lock yet, so it should be safe to unlock it and retrieve the channel lock. */
+			ast_mutex_unlock(&p->lock);
+			ast_channel_lock(owner);
+			ast_mutex_lock(&p->lock);
+		}
+
 		if (!ast_strlen_zero(p->name))
 			snprintf(username, sizeof(username), "(%s) ", p->name);
 		else
 			username[0] = '\0';
 		if (p->chan) {
 			snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
-			if (p->owner && ast_bridged_channel(p->owner)) 
-				snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
-			else 
+			if (p->owner && ast_bridged_channel(owner)) {
+				snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(owner)->name);
+			} else {
 				strcpy(talkingto, " is idle");
+			}
 			agent_status = 1;
 			online_agents++;
 		}
+
+		if (owner) {
+			ast_channel_unlock(owner);
+			ast_channel_unref(owner);
+			owner = NULL;
+		}
+
 		if (!ast_strlen_zero(p->moh))
 			snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
 		if (agent_status)
@@ -2381,12 +2461,23 @@
 
 	AST_LIST_LOCK(&agents);
 	AST_LIST_TRAVERSE(&agents, p, list) {
+		struct ast_channel *owner = NULL;
+
 		data_agent = ast_data_add_node(data_root, "agent");
 		if (!data_agent) {
 			continue;
 		}
 
 		ast_mutex_lock(&p->lock);
+		if (p->owner) {
+			ast_channel_ref(p->owner);
+			owner = p->owner;
+			/* Haven't used lock yet, so it should be safe to unlock it and retrieve the channel lock. */
+			ast_mutex_unlock(&p->lock);
+			ast_channel_lock(owner);
+			ast_mutex_lock(&p->lock);
+		}
+
 		if (!(p->pending)) {
 			ast_data_add_str(data_agent, "id", p->agent);
 			ast_data_add_structure(agent_pvt, data_agent, p);
@@ -2397,17 +2488,27 @@
 				if (!data_channel) {
 					ast_mutex_unlock(&p->lock);
 					ast_data_remove_node(data_root, data_agent);
+					if (owner) {
+						ast_channel_unlock(owner);
+						ast_channel_unref(owner);
+						owner = NULL;
+					}
 					continue;
 				}
 				ast_channel_data_add_structure(data_channel, p->chan, 0);
-				if (p->owner && ast_bridged_channel(p->owner)) {
+				if (owner && ast_bridged_channel(owner)) {
 					data_talkingto = ast_data_add_node(data_agent, "talkingto");
 					if (!data_talkingto) {
 						ast_mutex_unlock(&p->lock);
 						ast_data_remove_node(data_root, data_agent);
+						if (owner) {
+							ast_channel_unlock(owner);
+							ast_channel_unref(owner);
+							owner = NULL;
+						}
 						continue;
 					}
-					ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(p->owner), 0);
+					ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
 				}
 			} else {
 				ast_data_add_node(data_agent, "talkingto");
@@ -2415,6 +2516,13 @@
 			}
 			ast_data_add_str(data_agent, "musiconhold", p->moh);
 		}
+
+		if (owner) {
+			ast_channel_unlock(owner);
+			ast_channel_unref(owner);
+			owner = NULL;
+		}
+
 		ast_mutex_unlock(&p->lock);
 
 		/* if this agent doesn't match remove the added agent. */

