diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index 82d576dc1022fff644ab48e00b0c573827ecb00b..5fdb9a13dd301ed8b811f7c623d5ea25b9583f33 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -1,10 +1,13 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2006, Digium, Inc.
+ * Copyright (C) 1999 - 2007, Digium, Inc.
  *
  * Mark Spencer <markster@digium.com>
  *
+ * SLA Implementation by:
+ * Russell Bryant <russell@digium.com>
+ *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
  * any of the maintainers of this project for assistance;
@@ -18,9 +21,10 @@
 
 /*! \file
  *
- * \brief Meet me conference bridge
+ * \brief Meet me conference bridge and Shared Line Appearances
  *
  * \author Mark Spencer <markster@digium.com>
+ * \author (SLA) Russell Bryant <russell@digium.com>
  * 
  * \ingroup applications
  */
@@ -346,6 +350,11 @@ struct ast_conf_user {
 	AST_LIST_ENTRY(ast_conf_user) list;
 };
 
+enum sla_which_trunk_refs {
+	ALL_TRUNK_REFS,
+	INACTIVE_TRUNK_REFS,
+};
+
 enum sla_trunk_state {
 	SLA_TRUNK_STATE_IDLE,
 	SLA_TRUNK_STATE_RINGING,
@@ -364,6 +373,10 @@ struct sla_station {
 	);
 	AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
 	struct ast_dial *dial;
+	/*! Ring timeout for this station, for any trunk.  If a ring timeout
+	 *  is set for a specific trunk on this station, that will take
+	 *  priority over this value. */
+	unsigned int ring_timeout;
 };
 
 struct sla_station_ref {
@@ -386,7 +399,10 @@ struct sla_trunk {
 	/*! Number of stations that have this trunk on hold. */
 	unsigned int hold_stations;
 	struct ast_channel *chan;
-	pthread_t station_thread;
+	/*! Ring timeout to use when this trunk is ringing on this specific
+	 *  station.  This takes higher priority than a ring timeout set at
+	 *  the station level. */
+	unsigned int ring_timeout;
 };
 
 struct sla_trunk_ref {
@@ -394,6 +410,7 @@ struct sla_trunk_ref {
 	struct sla_trunk *trunk;
 	enum sla_trunk_state state;
 	struct ast_channel *chan;
+	unsigned int ring_timeout;
 };
 
 static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
@@ -401,9 +418,16 @@ static AST_RWLIST_HEAD_STATIC(sla_trunks, sla_trunk);
 
 static const char sla_registrar[] = "SLA";
 
+/*! \brief Event types that can be queued up for the SLA thread */
 enum sla_event_type {
+	/*! A station has put the call on hold */
 	SLA_EVENT_HOLD,
-	SLA_EVENT_UNHOLD
+	/*! A station has taken the call off of hold */
+	SLA_EVENT_UNHOLD,
+	/*! The state of a dial has changed */
+	SLA_EVENT_DIAL_STATE,
+	/*! The state of a ringing trunk has changed */
+	SLA_EVENT_RINGING_TRUNK,
 };
 
 struct sla_event {
@@ -413,6 +437,36 @@ struct sla_event {
 	AST_LIST_ENTRY(sla_event) entry;
 };
 
+/*! \brief A station that failed to be dialed 
+ * \note Only used by the SLA thread. */
+struct sla_failed_station {
+	struct sla_station *station;
+	struct timeval last_try;
+	AST_LIST_ENTRY(sla_failed_station) entry;
+};
+
+/*! \brief A trunk that is ringing */
+struct sla_ringing_trunk {
+	struct sla_trunk *trunk;
+	/*! The time that this trunk started ringing */
+	struct timeval ring_begin;
+	AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
+	AST_LIST_ENTRY(sla_ringing_trunk) entry;
+};
+
+enum sla_station_hangup {
+	SLA_STATION_HANGUP_NORMAL,
+	SLA_STATION_HANGUP_TIMEOUT,
+};
+
+/*! \brief A station that is ringing */
+struct sla_ringing_station {
+	struct sla_station *station;
+	/*! The time that this station started ringing */
+	struct timeval ring_begin;
+	AST_LIST_ENTRY(sla_ringing_station) entry;
+};
+
 /*!
  * \brief A structure for data used by the sla thread
  */
@@ -421,7 +475,9 @@ static struct sla {
 	pthread_t thread;
 	ast_cond_t cond;
 	ast_mutex_t lock;
-	AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) ringing_trunks;
+	AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
+	AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
+	AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
 	AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
 	unsigned int stop:1;
 } sla = {
@@ -929,25 +985,33 @@ static int sla_show_trunks(int fd, int argc, char **argv)
 {
 	const struct sla_trunk *trunk;
 
-	ast_cli(fd, "--- Configured SLA Trunks -----------------------------------\n"
-	            "-------------------------------------------------------------\n\n");
+	ast_cli(fd, "\n"
+	            "--- Configured SLA Trunks -----------------------------------\n"
+	            "-------------------------------------------------------------\n"
+	            "---\n");
 	AST_RWLIST_RDLOCK(&sla_trunks);
 	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
 		struct sla_station_ref *station_ref;
+		char ring_timeout[16] = "(none)";
+		if (trunk->ring_timeout)
+			snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
 		ast_cli(fd, "--- Trunk Name:      %s\n"
 		            "--- ==> Device:      %s\n"
 					"--- ==> AutoContext: %s\n"
+					"--- ==> RingTimeout: %s\n"
 					"--- ==> Stations ...\n",
 					trunk->name, trunk->device, 
-					S_OR(trunk->autocontext, "(none)"));
+					S_OR(trunk->autocontext, "(none)"), 
+					ring_timeout);
 		AST_RWLIST_RDLOCK(&sla_stations);
 		AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
-			ast_cli(fd, "--- =====> Station name: %s\n", station_ref->station->name);
+			ast_cli(fd, "---    ==> Station name: %s\n", station_ref->station->name);
 		AST_RWLIST_UNLOCK(&sla_stations);
-		ast_cli(fd, "\n");
+		ast_cli(fd, "---\n");
 	}
 	AST_RWLIST_UNLOCK(&sla_trunks);
-	ast_cli(fd, "-------------------------------------------------------------\n");
+	ast_cli(fd, "-------------------------------------------------------------\n"
+	            "\n");
 
 	return RESULT_SUCCESS;
 }
@@ -973,26 +1037,44 @@ static int sla_show_stations(int fd, int argc, char **argv)
 {
 	const struct sla_station *station;
 
-	ast_cli(fd, "--- Configured SLA Stations ---------------------------------\n"
-	            "-------------------------------------------------------------\n\n");
+	ast_cli(fd, "\n" 
+	            "--- Configured SLA Stations ---------------------------------\n"
+	            "-------------------------------------------------------------\n"
+	            "---\n");
 	AST_RWLIST_RDLOCK(&sla_stations);
 	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
 		struct sla_trunk_ref *trunk_ref;
+		char ring_timeout[16] = "(none)";
+		if (station->ring_timeout) {
+			snprintf(ring_timeout, sizeof(ring_timeout), 
+				"%u", station->ring_timeout);
+		}
 		ast_cli(fd, "--- Station Name:    %s\n"
 		            "--- ==> Device:      %s\n"
 					"--- ==> AutoContext: %s\n"
+					"--- ==> RingTimeout: %s\n"
 					"--- ==> Trunks ...\n",
-					station->name, station->device, 
-					S_OR(station->autocontext, "(none)"));
+					station->name, station->device,
+					S_OR(station->autocontext, "(none)"), ring_timeout);
 		AST_RWLIST_RDLOCK(&sla_trunks);
-		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry)
-			ast_cli(fd, "--- =====> Trunk Name: %s State: %s\n", 
-				trunk_ref->trunk->name, trunkstate2str(trunk_ref->state));
+		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
+			if (trunk_ref->ring_timeout) {
+				snprintf(ring_timeout, sizeof(ring_timeout),
+					"%u", trunk_ref->ring_timeout);
+			} else
+				strcpy(ring_timeout, "(none)");
+			ast_cli(fd, "---    ==> Trunk Name: %s\n", 
+				trunk_ref->trunk->name);
+			ast_cli(fd, "---       ==> State:       %s\n", 
+				trunkstate2str(trunk_ref->state));
+			ast_cli(fd, "---       ==> RingTimeout: %s\n", ring_timeout);
+		}
 		AST_RWLIST_UNLOCK(&sla_trunks);
-		ast_cli(fd, "\n");
+		ast_cli(fd, "---\n");
 	}
 	AST_RWLIST_UNLOCK(&sla_stations);
-	ast_cli(fd, "-------------------------------------------------------------\n");
+	ast_cli(fd, "-------------------------------------------------------------\n"
+	            "\n");
 
 	return RESULT_SUCCESS;
 }
@@ -1100,10 +1182,43 @@ static void conf_queue_dtmf(const struct ast_conference *conf,
 	}
 }
 
-static void sla_queue_event(enum sla_event_type type, const struct ast_channel *chan,
-	struct ast_conference *conf)
+static void sla_queue_event_full(enum sla_event_type type, 
+	struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
 {
 	struct sla_event *event;
+
+	if (!(event = ast_calloc(1, sizeof(*event))))
+		return;
+
+	event->type = type;
+	event->trunk_ref = trunk_ref;
+	event->station = station;
+
+	if (!lock) {
+		AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
+		return;
+	}
+
+	ast_mutex_lock(&sla.lock);
+	AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
+	ast_cond_signal(&sla.cond);
+	ast_mutex_unlock(&sla.lock);
+}
+
+static void sla_queue_event_nolock(enum sla_event_type type)
+{
+	sla_queue_event_full(type, NULL, NULL, 0);
+}
+
+static void sla_queue_event(enum sla_event_type type)
+{
+	sla_queue_event_full(type, NULL, NULL, 1);
+}
+
+/*! \brief Queue a SLA event from the conference */
+static void sla_queue_event_conf(enum sla_event_type type, const struct ast_channel *chan,
+	struct ast_conference *conf)
+{
 	struct sla_station *station;
 	struct sla_trunk_ref *trunk_ref = NULL;
 	char *trunk_name;
@@ -1131,17 +1246,7 @@ static void sla_queue_event(enum sla_event_type type, const struct ast_channel *
 		return;
 	}
 
-	if (!(event = ast_calloc(1, sizeof(*event))))
-		return;
-
-	event->type = type;
-	event->trunk_ref = trunk_ref;
-	event->station = station;
-
-	ast_mutex_lock(&sla.lock);
-	AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
-	ast_cond_signal(&sla.cond);
-	ast_mutex_unlock(&sla.lock);
+	sla_queue_event_full(type, trunk_ref, station, 1);
 }
 
 /* Decrement reference counts, as incremented by find_conf() */
@@ -1936,12 +2041,10 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
 				} else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
 					switch (f->subclass) {
 					case AST_CONTROL_HOLD:
-						ast_log(LOG_DEBUG, "Got a HOLD frame!\n");
-						sla_queue_event(SLA_EVENT_HOLD, chan, conf);
+						sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
 						break;
 					case AST_CONTROL_UNHOLD:
-						ast_log(LOG_DEBUG, "Got a UNHOLD frame!\n");
-						sla_queue_event(SLA_EVENT_UNHOLD, chan, conf);
+						sla_queue_event_conf(SLA_EVENT_UNHOLD, chan, conf);
 					default:
 						break;
 					}
@@ -2916,7 +3019,7 @@ static void load_config_meetme(void)
 /*! \brief Find an SLA trunk by name
  * \note This must be called with the sla_trunks container locked
  */
-static struct sla_trunk *find_trunk(const char *name)
+static struct sla_trunk *sla_find_trunk(const char *name)
 {
 	struct sla_trunk *trunk = NULL;
 
@@ -2931,7 +3034,7 @@ static struct sla_trunk *find_trunk(const char *name)
 /*! \brief Find an SLA station by name
  * \note This must be called with the sla_stations container locked
  */
-static struct sla_station *find_station(const char *name)
+static struct sla_station *sla_find_station(const char *name)
 {
 	struct sla_station *station = NULL;
 
@@ -2943,7 +3046,7 @@ static struct sla_station *find_station(const char *name)
 	return station;
 }
 
-static struct sla_trunk_ref *find_trunk_ref(const struct sla_station *station,
+static struct sla_trunk_ref *sla_sla_find_trunk_ref(const struct sla_station *station,
 	const char *name)
 {
 	struct sla_trunk_ref *trunk_ref = NULL;
@@ -2956,7 +3059,7 @@ static struct sla_trunk_ref *find_trunk_ref(const struct sla_station *station,
 	return trunk_ref;
 }
 
-static struct sla_station_ref *create_station_ref(struct sla_station *station)
+static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
 {
 	struct sla_station_ref *station_ref;
 
@@ -2968,7 +3071,21 @@ static struct sla_station_ref *create_station_ref(struct sla_station *station)
 	return station_ref;
 }
 
-static void change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state, int inactive_only)
+static struct sla_ringing_station *sla_create_ringing_station(struct sla_station *station)
+{
+	struct sla_ringing_station *ringing_station;
+
+	if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
+		return NULL;
+
+	ringing_station->station = station;
+	ringing_station->ring_begin = ast_tvnow();
+
+	return ringing_station;
+}
+
+static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state, 
+	enum sla_which_trunk_refs inactive_only)
 {
 	struct sla_station *station;
 	struct sla_trunk_ref *trunk_ref;
@@ -3026,7 +3143,7 @@ static void *run_station(void *data)
 	if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations)) {
 		strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
 		admin_exec(NULL, conf_name);
-		change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, 0);
+		sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS);
 	}
 
 	ast_dial_join(station->dial);
@@ -3036,216 +3153,426 @@ static void *run_station(void *data)
 	return NULL;
 }
 
-static void *sla_thread(void *data)
+static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
 {
-	AST_LIST_HEAD_NOLOCK_STATIC(ringing_stations, sla_station_ref);
-	struct sla_failed_station {
-		struct sla_station *station;
-		struct timeval last_try;
-		AST_LIST_ENTRY(sla_failed_station) entry;
-	};
-	AST_LIST_HEAD_NOLOCK_STATIC(failed_stations, sla_failed_station);
+	char buf[80];
 	struct sla_station_ref *station_ref;
-	struct sla_failed_station *failed_station;
 
-	for (; !sla.stop;) {
-		struct sla_trunk_ref *trunk_ref = NULL;
-		struct sla_event *event;
-		enum ast_dial_result dial_res = AST_DIAL_RESULT_TRYING;
+	snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
+	admin_exec(NULL, buf);
+	sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS);
 
-		ast_mutex_lock(&sla.lock);
-		if (AST_LIST_EMPTY(&sla.ringing_trunks) && AST_LIST_EMPTY(&sla.event_q)) {
-			ast_cond_wait(&sla.cond, &sla.lock);
-			if (sla.stop)
-				break;
-			ast_log(LOG_DEBUG, "Ooh, I was woken up!\n");
-		}
+	while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
+		free(station_ref);
 
-		while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
-			switch (event->type) {
-			case SLA_EVENT_HOLD:
-				ast_log(LOG_DEBUG, "HOLD, station: %s  trunk: %s\n", 
-					event->station->name, event->trunk_ref->trunk->name);
-				ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
-				event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD;
-				ast_device_state_changed("SLA:%s_%s", 
-					event->station->name, event->trunk_ref->trunk->name);
-				change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 1);	
-				break;
-			case SLA_EVENT_UNHOLD:
-				ast_log(LOG_DEBUG, "UNHOLD, station: %s  trunk: %s\n", 
-					event->station->name, event->trunk_ref->trunk->name);
-				if (ast_atomic_dec_and_test((int *) &event->trunk_ref->trunk->hold_stations) == 1)
-					change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_UP, 0);
-				else {
-					event->trunk_ref->state = SLA_TRUNK_STATE_UP;
-					ast_device_state_changed("SLA:%s_%s",
-						event->station->name, event->trunk_ref->trunk->name);
-				}
+	free(ringing_trunk);
+}
+
+static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
+	enum sla_station_hangup hangup)
+{
+	struct sla_ringing_trunk *ringing_trunk;
+	struct sla_trunk_ref *trunk_ref;
+	struct sla_station_ref *station_ref;
+
+	ast_dial_join(ringing_station->station->dial);
+	ast_dial_destroy(ringing_station->station->dial);
+	ringing_station->station->dial = NULL;
+
+	if (hangup == SLA_STATION_HANGUP_NORMAL)
+		goto done;
+
+	/* If the station is being hung up because of a timeout, then add it to the
+	 * list of timed out stations on each of the ringing trunks.  This is so
+	 * that when doing further processing to figure out which stations should be
+	 * ringing, which trunk to answer, determining timeouts, etc., we know which
+	 * ringing trunks we should ignore. */
+	AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
+		AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
+			if (ringing_trunk->trunk == trunk_ref->trunk)
 				break;
-			}
-			free(event);
 		}
+		if (!trunk_ref)
+			continue;
+		if (!(station_ref = sla_create_station_ref(ringing_station->station)))
+			continue;
+		AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
+	}
+
+done:
+	free(ringing_station);
+}
+
+static void sla_dial_state_callback(struct ast_dial *dial)
+{
+	sla_queue_event(SLA_EVENT_DIAL_STATE);
+}
+
+static void sla_handle_dial_state_event(void)
+{
+	struct sla_ringing_station *ringing_station;
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
+		struct sla_trunk_ref *s_trunk_ref;
+		struct sla_ringing_trunk *ringing_trunk;
+		struct run_station_args args;
+		enum ast_dial_result dial_res;
+		pthread_attr_t attr;
+		pthread_t dont_care;
+		ast_mutex_t cond_lock;
+		ast_cond_t cond;
 
-		/* At this point, we know there are ringing trunks.  So, make sure that every
-		 * station that uses at least one of the ringing trunks, is ringing. */
-		AST_LIST_TRAVERSE(&sla.ringing_trunks, trunk_ref, entry) {
-			AST_LIST_TRAVERSE(&trunk_ref->trunk->stations, station_ref, entry) {
-				char *tech, *tech_data;
-				struct ast_dial *dial;
-				struct sla_station_ref *ringing_ref;
-				struct sla_failed_station *failed_station;
-				/* Did we fail to dial this station earlier?  If so, has it been
- 				 * a minute since we tried? */
-				AST_LIST_TRAVERSE_SAFE_BEGIN(&failed_stations, failed_station, entry) {
-					if (station_ref->station != failed_station->station)
+		switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
+		case AST_DIAL_RESULT_HANGUP:
+		case AST_DIAL_RESULT_INVALID:
+		case AST_DIAL_RESULT_FAILED:
+		case AST_DIAL_RESULT_TIMEOUT:
+		case AST_DIAL_RESULT_UNANSWERED:
+			AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
+			sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
+			break;
+		case AST_DIAL_RESULT_ANSWERED:
+			AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
+			/* Find the appropriate trunk to answer. */
+			AST_LIST_TRAVERSE(&ringing_station->station->trunks, s_trunk_ref, entry) {
+				ast_mutex_lock(&sla.lock);
+				AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
+					struct sla_station_ref *station_ref;
+					if (s_trunk_ref->trunk != ringing_trunk->trunk)
 						continue;
-					if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
-						AST_LIST_REMOVE_CURRENT(&failed_stations, entry);
-						free(failed_station);
-						failed_station = NULL;
+					/* This trunk on the station is ringing.  But, make sure this station
+					 * didn't already time out while this trunk was ringing. */
+					AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
+						if (station_ref->station == ringing_station->station)
+							break;
 					}
+					if (station_ref)
+						continue;
+					AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
 					break;
 				}
-				if (failed_station)
-					continue;
 				AST_LIST_TRAVERSE_SAFE_END
-				AST_LIST_TRAVERSE(&ringing_stations, ringing_ref, entry) {
-					if (station_ref->station == ringing_ref->station)
-						break;
-				}
-				if (ringing_ref)
-					continue;
-				if (!(dial = ast_dial_create()))
-					continue;
-				tech_data = ast_strdupa(station_ref->station->device);
-				tech = strsep(&tech_data, "/");
-				if (ast_dial_append(dial, tech, tech_data) == -1) {
-					ast_dial_destroy(dial);
-					continue;
-				}
-				if (ast_dial_run(dial, trunk_ref->trunk->chan, 1) != AST_DIAL_RESULT_TRYING) {
-					ast_dial_destroy(dial);
-					if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
-						continue;
-					failed_station->station = station_ref->station;
-					failed_station->last_try = ast_tvnow();
-					AST_LIST_INSERT_HEAD(&failed_stations, failed_station, entry);
+				ast_mutex_unlock(&sla.lock);
+				if (ringing_trunk)
+					break;
+			}
+			if (!ringing_trunk) {
+				ast_log(LOG_DEBUG, "Found no ringing trunk for station '%s' to answer!\n",
+					ringing_station->station->name);
+				break;
+			}
+			s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
+			ast_answer(ringing_trunk->trunk->chan);
+			sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS);
+			args.trunk_ref = s_trunk_ref;
+			args.station = ringing_station->station;
+			args.cond = &cond;
+			args.cond_lock = &cond_lock;
+			free(ringing_trunk);
+			free(ringing_station);
+			ast_mutex_init(&cond_lock);
+			ast_cond_init(&cond, NULL);
+			pthread_attr_init(&attr);
+			pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+			ast_mutex_lock(&cond_lock);
+			ast_pthread_create_background(&dont_care, &attr, run_station, &args);
+			ast_cond_wait(&cond, &cond_lock);
+			ast_mutex_unlock(&cond_lock);
+			ast_mutex_destroy(&cond_lock);
+			ast_cond_destroy(&cond);
+			pthread_attr_destroy(&attr);
+			break;
+		case AST_DIAL_RESULT_TRYING:
+		case AST_DIAL_RESULT_RINGING:
+		case AST_DIAL_RESULT_PROGRESS:
+		case AST_DIAL_RESULT_PROCEEDING:
+			break;
+		}
+		if (dial_res == AST_DIAL_RESULT_ANSWERED) {
+			/* Queue up reprocessing ringing trunks, and then ringing stations again */
+			sla_queue_event(SLA_EVENT_RINGING_TRUNK);
+			sla_queue_event(SLA_EVENT_DIAL_STATE);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+}
+
+static void sla_handle_ringing_trunk_event(void)
+{
+	struct sla_trunk_ref *trunk_ref;
+	struct sla_station_ref *station_ref;
+	struct sla_ringing_trunk *ringing_trunk;
+	struct sla_ringing_station *ringing_station;
+
+	ast_mutex_lock(&sla.lock);
+
+	/* Make sure that every station that uses at least one of the ringing
+	 * trunks, is ringing. */
+	AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
+		AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
+			char *tech, *tech_data;
+			struct ast_dial *dial;
+			struct sla_failed_station *failed_station;
+			struct sla_station_ref *timed_out_station;
+			/* Did we fail to dial this station earlier?  If so, has it been
+ 			 * a minute since we tried? */
+			AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
+				if (station_ref->station != failed_station->station)
 					continue;
+				if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
+					AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
+					free(failed_station);
+					failed_station = NULL;
 				}
-				if (!(ringing_ref = create_station_ref(station_ref->station))) {
-					ast_dial_join(dial);
-					ast_dial_destroy(dial);
+				break;
+			}
+			if (failed_station)
+				continue;
+			AST_LIST_TRAVERSE_SAFE_END
+			AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
+				if (station_ref->station == ringing_station->station)
+					break;
+			}
+			if (ringing_station)
+				continue;
+			/* If this station already timed out while this trunk was ringing,
+			 * do not dial it again for this ringing trunk. */
+			AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
+				if (station_ref->station == timed_out_station->station)
+					break;
+			}
+			if (timed_out_station)
+				continue;
+			if (!(dial = ast_dial_create()))
+				continue;
+			ast_dial_set_state_callback(dial, sla_dial_state_callback);
+			tech_data = ast_strdupa(station_ref->station->device);
+			tech = strsep(&tech_data, "/");
+			if (ast_dial_append(dial, tech, tech_data) == -1) {
+				ast_dial_destroy(dial);
+				continue;
+			}
+			if (ast_dial_run(dial, ringing_trunk->trunk->chan, 1) != AST_DIAL_RESULT_TRYING) {
+				ast_dial_destroy(dial);
+				if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
 					continue;
-				}
-				station_ref->station->dial = dial;
-				AST_LIST_INSERT_HEAD(&ringing_stations, ringing_ref, entry);
-				ast_log(LOG_DEBUG, "Started dialing station '%s'\n", station_ref->station->name);
+				failed_station->station = station_ref->station;
+				failed_station->last_try = ast_tvnow();
+				AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
+				continue;
+			}
+			if (!(ringing_station = sla_create_ringing_station(station_ref->station))) {
+				ast_dial_join(dial);
+				ast_dial_destroy(dial);
+				continue;
 			}
+			station_ref->station->dial = dial;
+			AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
+			ast_log(LOG_DEBUG, "Started dialing station '%s'\n", station_ref->station->name);
 		}
-		ast_mutex_unlock(&sla.lock);
-		/* Now, all of the stations that should be ringing, are ringing. */
-		
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&ringing_stations, station_ref, entry) {
-			struct sla_trunk_ref *s_trunk_ref;
-			struct run_station_args args;
-			pthread_attr_t attr;
-			pthread_t dont_care;
-			ast_mutex_t cond_lock;
-			ast_cond_t cond;
-
-			switch ((dial_res = ast_dial_state(station_ref->station->dial))) {
-			case AST_DIAL_RESULT_HANGUP:
-			case AST_DIAL_RESULT_INVALID:
-			case AST_DIAL_RESULT_FAILED:
-			case AST_DIAL_RESULT_TIMEOUT:
-			case AST_DIAL_RESULT_UNANSWERED:
-				AST_LIST_REMOVE_CURRENT(&ringing_stations, entry);
-				ast_dial_join(station_ref->station->dial);
-				ast_dial_destroy(station_ref->station->dial);
-				station_ref->station->dial = NULL;
-				free(station_ref);
-				break;
-			case AST_DIAL_RESULT_ANSWERED:
-				AST_LIST_REMOVE_CURRENT(&ringing_stations, entry);
-				/* Find the appropriate trunk to answer. */
-				AST_LIST_TRAVERSE(&station_ref->station->trunks, s_trunk_ref, entry) {
-					ast_mutex_lock(&sla.lock);
-					AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, trunk_ref, entry) {
-						if (s_trunk_ref->trunk == trunk_ref->trunk) {
-							AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
-							break;
-						}
-					}
-					AST_LIST_TRAVERSE_SAFE_END
-					ast_mutex_unlock(&sla.lock);
-					if (trunk_ref)
-						break;
-				}
-				if (!trunk_ref) {
-					ast_log(LOG_DEBUG, "Found no ringing trunk for station '%s' to answer!\n",
-						station_ref->station->name);
+	}
+	ast_mutex_unlock(&sla.lock);
+	/* Now, all of the stations that should be ringing, are ringing. */
+	
+	/* Find stations that shouldn't be ringing anymore. */
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
+		AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
+			struct sla_ringing_trunk *ringing_trunk;
+			ast_mutex_lock(&sla.lock);
+			AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
+				if (trunk_ref->trunk == ringing_trunk->trunk)
 					break;
-				}
-				s_trunk_ref->chan = ast_dial_answered(station_ref->station->dial);
-				ast_answer(trunk_ref->trunk->chan);
-				change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, 0);
-				args.trunk_ref = s_trunk_ref;
-				args.station = station_ref->station;
-				args.cond = &cond;
-				args.cond_lock = &cond_lock;
-				free(trunk_ref);
-				free(station_ref);
-				ast_mutex_init(&cond_lock);
-				ast_cond_init(&cond, NULL);
-				pthread_attr_init(&attr);
-				pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-				ast_mutex_lock(&cond_lock);
-				ast_pthread_create_background(&dont_care, &attr, run_station, &args);
-				ast_cond_wait(&cond, &cond_lock);
-				ast_mutex_unlock(&cond_lock);
-				ast_mutex_destroy(&cond_lock);
-				ast_cond_destroy(&cond);
-				pthread_attr_destroy(&attr);
-				break;
-			case AST_DIAL_RESULT_TRYING:
-			case AST_DIAL_RESULT_RINGING:
-			case AST_DIAL_RESULT_PROGRESS:
-			case AST_DIAL_RESULT_PROCEEDING:
-				break;
 			}
-			if (dial_res == AST_DIAL_RESULT_ANSWERED || !AST_LIST_EMPTY(&sla.event_q))
+			ast_mutex_unlock(&sla.lock);
+			if (ringing_trunk)
 				break;
 		}
-		AST_LIST_TRAVERSE_SAFE_END
-		/* Find stations that shouldn't be ringing anymore. */
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&ringing_stations, station_ref, entry) {
-			AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
-				struct sla_trunk_ref *ringing_ref;
-				ast_mutex_lock(&sla.lock);
-				AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_ref, entry) {
-					if (trunk_ref->trunk == ringing_ref->trunk)
-						break;
-				}
-				ast_mutex_unlock(&sla.lock);
-				if (ringing_ref)
+		if (!trunk_ref) {
+			AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
+			ast_dial_join(ringing_station->station->dial);
+			ast_dial_destroy(ringing_station->station->dial);
+			ringing_station->station->dial = NULL;
+			free(ringing_station);
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+}
+
+static void sla_handle_hold_event(struct sla_event *event)
+{
+	ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
+	event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD;
+	ast_device_state_changed("SLA:%s_%s", 
+		event->station->name, event->trunk_ref->trunk->name);
+	sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, INACTIVE_TRUNK_REFS);	
+}
+
+static void sla_handle_unhold_event(struct sla_event *event)
+{
+	if (ast_atomic_dec_and_test((int *) &event->trunk_ref->trunk->hold_stations) == 1)
+		sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS);
+	else {
+		event->trunk_ref->state = SLA_TRUNK_STATE_UP;
+		ast_device_state_changed("SLA:%s_%s",
+			event->station->name, event->trunk_ref->trunk->name);
+	}
+}
+
+/*! \brief Calculate the time until the next known event
+ *  \note Called with sla.lock locked */
+static int sla_process_timers(struct timespec *ts)
+{
+	struct sla_ringing_trunk *ringing_trunk;
+	struct sla_ringing_station *ringing_station;
+	unsigned int timeout = UINT_MAX;
+	struct timeval tv;
+	unsigned int change_made = 0;
+
+	/* Check for ring timeouts on ringing trunks */
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
+		int time_left, time_elapsed;
+		if (!ringing_trunk->trunk->ring_timeout)
+			continue;
+		time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
+		time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
+		if (time_left <= 0) {
+			AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
+			sla_stop_ringing_trunk(ringing_trunk);
+			change_made = 1;
+			continue;
+		}
+		if (time_left < timeout)
+			timeout = time_left;
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+
+	/* Check for ring timeouts on ringing stations */
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
+		unsigned int ring_timeout = 0;
+		int time_elapsed, time_left, final_trunk_time_left = INT_MIN;
+		struct sla_trunk_ref *trunk_ref;
+		/* If there are any ring timeouts specified for a specific trunk
+		 * on the station, then use the highest per-trunk ring timeout.
+		 * Otherwise, use the ring timeout set for the entire station. */
+		AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
+			struct sla_station_ref *station_ref;
+			int trunk_time_elapsed, trunk_time_left;
+			AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
+				if (ringing_trunk->trunk == trunk_ref->trunk)
 					break;
 			}
-			if (!trunk_ref) {
-				AST_LIST_REMOVE_CURRENT(&ringing_stations, entry);
-				ast_dial_join(station_ref->station->dial);
-				ast_dial_destroy(station_ref->station->dial);
-				station_ref->station->dial = NULL;
-				free(station_ref);
+			if (!ringing_trunk)
+				continue;
+			/* If there is a trunk that is ringing without a timeout, then the
+			 * only timeout that could matter is a global station ring timeout. */
+			if (!trunk_ref->ring_timeout) {
+				final_trunk_time_left = INT_MAX;
+				break;
 			}
+			/* This trunk on this station is ringing and has a timeout.
+			 * However, make sure this trunk isn't still ringing from a
+			 * previous timeout.  If so, don't consider it. */
+			AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
+				if (station_ref->station == ringing_station->station)
+					break;
+			}
+			if (station_ref)
+				continue;
+			trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
+			trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
+			if (trunk_time_left > final_trunk_time_left)
+				final_trunk_time_left = trunk_time_left;
 		}
-		AST_LIST_TRAVERSE_SAFE_END
+		if (final_trunk_time_left == INT_MAX && !ringing_station->station->ring_timeout)
+			continue;
+
+		ring_timeout = ringing_station->station->ring_timeout;
+		time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
+		time_left = (ring_timeout * 1000) - time_elapsed;
+		/* If the time left based on the per-trunk timeouts is smaller than the
+		 * global station ring timeout, use that. */
+		if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
+			time_left = final_trunk_time_left;
+		if (time_left <= 0) {
+			AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
+			sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
+			change_made = 1;
+			continue;
+		}
+		if (time_left < timeout)
+			timeout = time_left;
 	}
+	AST_LIST_TRAVERSE_SAFE_END
 
-	while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_stations, entry)))
-		free(station_ref);
+	/* queue reprocessing of ringing trunks */
+	if (change_made)
+		sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
+
+	if (timeout == UINT_MAX)
+		return 0;
+
+	if (ts) {
+		tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
+		ts->tv_sec = tv.tv_sec;
+		ts->tv_nsec = tv.tv_usec * 1000;
+	}
+
+	return 1;
+}
+
+static void *sla_thread(void *data)
+{
+	struct sla_failed_station *failed_station;
+	struct sla_ringing_station *ringing_station;
+
+	ast_mutex_lock(&sla.lock);
+
+	while (!sla.stop) {
+		struct sla_event *event;
+		struct timespec ts = { 0, };
+		unsigned int have_timeout = 0;
+
+		if (AST_LIST_EMPTY(&sla.event_q)) {
+			if ((have_timeout = sla_process_timers(&ts)))
+				ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
+			else
+				ast_cond_wait(&sla.cond, &sla.lock);
+			if (sla.stop)
+				break;
+			ast_log(LOG_DEBUG, "Ooh, I was woken up!\n");
+		}
+
+		if (have_timeout)
+			sla_process_timers(NULL);
 
-	while ((failed_station = AST_LIST_REMOVE_HEAD(&failed_stations, entry)))
+		while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
+			ast_mutex_unlock(&sla.lock);
+			switch (event->type) {
+			case SLA_EVENT_HOLD:
+				sla_handle_hold_event(event);
+				break;
+			case SLA_EVENT_UNHOLD:
+				sla_handle_unhold_event(event);				
+				break;
+			case SLA_EVENT_DIAL_STATE:
+				sla_handle_dial_state_event();
+				break;
+			case SLA_EVENT_RINGING_TRUNK:
+				sla_handle_ringing_trunk_event();
+				break;
+			}
+			free(event);
+			ast_mutex_lock(&sla.lock);
+		}
+	}
+
+	ast_mutex_unlock(&sla.lock);
+
+	while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
+		free(ringing_station);
+
+	while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
 		free(failed_station);
 
 	return NULL;
@@ -3376,7 +3703,7 @@ static int slastation_exec(struct ast_channel *chan, void *data)
 	}
 
 	AST_RWLIST_RDLOCK(&sla_stations);
-	station = find_station(station_name);
+	station = sla_find_station(station_name);
 	AST_RWLIST_UNLOCK(&sla_stations);
 
 	if (!station) {
@@ -3387,7 +3714,7 @@ static int slastation_exec(struct ast_channel *chan, void *data)
 
 	AST_RWLIST_RDLOCK(&sla_trunks);
 	if (!ast_strlen_zero(trunk_name))
-		trunk_ref = find_trunk_ref(station, trunk_name);
+		trunk_ref = sla_sla_find_trunk_ref(station, trunk_name);
 	else {
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
 			if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
@@ -3413,7 +3740,7 @@ static int slastation_exec(struct ast_channel *chan, void *data)
 			.cond_lock = &cond_lock,
 			.cond = &cond,
 		};
-		change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, 0);
+		sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS);
 		/* Create a thread to dial the trunk and dump it into the conference.
 		 * However, we want to wait until the trunk has been dialed and the
 		 * conference is created before continuing on here. */
@@ -3433,7 +3760,7 @@ static int slastation_exec(struct ast_channel *chan, void *data)
 		if (!trunk_ref->trunk->chan) {
 			ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
 			pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
-			change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, 0);
+			sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS);
 			return 0;
 		}
 	}
@@ -3455,7 +3782,7 @@ static int slastation_exec(struct ast_channel *chan, void *data)
 	if (res == 1) {	
 		strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
 		admin_exec(NULL, conf_name);
-		change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, 0);
+		sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS);
 	}
 	
 	pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
@@ -3475,6 +3802,27 @@ static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
 	return trunk_ref;
 }
 
+static struct sla_ringing_trunk *queue_ringing_trunk(struct sla_trunk *trunk)
+{
+	struct sla_ringing_trunk *ringing_trunk;
+
+	if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
+		return NULL;
+	
+	ringing_trunk->trunk = trunk;
+	ringing_trunk->ring_begin = ast_tvnow();
+
+	sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, 0);
+
+	ast_mutex_lock(&sla.lock);
+	AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
+	ast_mutex_unlock(&sla.lock);
+
+	sla_queue_event(SLA_EVENT_RINGING_TRUNK);
+
+	return ringing_trunk;
+}
+
 static int slatrunk_exec(struct ast_channel *chan, void *data)
 {
 	const char *trunk_name = data;
@@ -3482,10 +3830,10 @@ static int slatrunk_exec(struct ast_channel *chan, void *data)
 	struct ast_conference *conf;
 	struct ast_flags conf_flags = { 0 };
 	struct sla_trunk *trunk;
-	struct sla_trunk_ref *trunk_ref;
+	struct sla_ringing_trunk *ringing_trunk;
 
 	AST_RWLIST_RDLOCK(&sla_trunks);
-	trunk = find_trunk(trunk_name);
+	trunk = sla_find_trunk(trunk_name);
 	AST_RWLIST_UNLOCK(&sla_trunks);
 	if (!trunk) {
 		ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
@@ -3502,19 +3850,11 @@ static int slatrunk_exec(struct ast_channel *chan, void *data)
 	}
 	trunk->chan = chan;
 
-	if (!(trunk_ref = create_trunk_ref(trunk))) {
+	if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
 		return 0;
 	}
 
-	change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, 0);
-
-	ast_mutex_lock(&sla.lock);
-	if (AST_LIST_EMPTY(&sla.ringing_trunks))
-		ast_cond_signal(&sla.cond);
-	AST_LIST_INSERT_HEAD(&sla.ringing_trunks, trunk_ref, entry);
-	ast_mutex_unlock(&sla.lock);
-
 	snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
 	conf = build_conf(conf_name, "", "", 1, 1, 1);
 	if (!conf) {
@@ -3533,17 +3873,18 @@ static int slatrunk_exec(struct ast_channel *chan, void *data)
 
 	/* Remove the entry from the list of ringing trunks if it is still there. */
 	ast_mutex_lock(&sla.lock);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, trunk_ref, entry) {
-		if (trunk_ref->trunk == trunk) {
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
+		if (ringing_trunk->trunk == trunk) {
 			AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
 			break;
 		}
 	}
 	AST_LIST_TRAVERSE_SAFE_END
 	ast_mutex_unlock(&sla.lock);
-	if (trunk_ref) {
-		free(trunk_ref);
+	if (ringing_trunk) {
+		free(ringing_trunk);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
+		sla_queue_event(SLA_EVENT_RINGING_TRUNK);
 	}
 
 	return 0;
@@ -3638,7 +3979,7 @@ static void destroy_station(struct sla_station *station)
 	free(station);
 }
 
-static void destroy_sla(void)
+static void sla_destroy(void)
 {
 	struct sla_trunk *trunk;
 	struct sla_station *station;
@@ -3665,7 +4006,7 @@ static void destroy_sla(void)
 	ast_cond_destroy(&sla.cond);
 }
 
-static int check_device(const char *device)
+static int sla_check_device(const char *device)
 {
 	char *tech, *tech_data;
 
@@ -3678,7 +4019,7 @@ static int check_device(const char *device)
 	return 0;
 }
 
-static int build_trunk(struct ast_config *cfg, const char *cat)
+static int sla_build_trunk(struct ast_config *cfg, const char *cat)
 {
 	struct sla_trunk *trunk;
 	struct ast_variable *var;
@@ -3689,7 +4030,7 @@ static int build_trunk(struct ast_config *cfg, const char *cat)
 		return -1;
 	}
 
-	if (check_device(dev)) {
+	if (sla_check_device(dev)) {
 		ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
 			cat, dev);
 		return -1;
@@ -3708,7 +4049,13 @@ static int build_trunk(struct ast_config *cfg, const char *cat)
 	for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
 		if (!strcasecmp(var->name, "autocontext"))
 			ast_string_field_set(trunk, autocontext, var->value);
-		else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
+		else if (!strcasecmp(var->name, "ringtimeout")) {
+			if (sscanf(var->value, "%u", &trunk->ring_timeout) != 1) {
+				ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
+					var->value, trunk->name);
+				trunk->ring_timeout = 0;
+			}
+		} else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
 			ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
 				var->name, var->lineno, SLA_CONFIG_FILE);
 		}
@@ -3733,13 +4080,64 @@ static int build_trunk(struct ast_config *cfg, const char *cat)
 	}
 
 	AST_RWLIST_WRLOCK(&sla_trunks);
-	AST_RWLIST_INSERT_HEAD(&sla_trunks, trunk, entry);
+	AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
 	AST_RWLIST_UNLOCK(&sla_trunks);
 
 	return 0;
 }
 
-static int build_station(struct ast_config *cfg, const char *cat)
+static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
+{
+	struct sla_trunk *trunk;
+	struct sla_trunk_ref *trunk_ref;
+	struct sla_station_ref *station_ref;
+	char *trunk_name, *options, *cur;
+
+	options = ast_strdupa(var->value);
+	trunk_name = strsep(&options, ",");
+	
+	AST_RWLIST_RDLOCK(&sla_trunks);
+	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
+		if (!strcasecmp(trunk->name, trunk_name))
+			break;
+	}
+
+	AST_RWLIST_UNLOCK(&sla_trunks);
+	if (!trunk) {
+		ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
+		return;
+	}
+	if (!(trunk_ref = create_trunk_ref(trunk)))
+		return;
+	trunk_ref->state = SLA_TRUNK_STATE_IDLE;
+
+	while ((cur = strsep(&options, ","))) {
+		char *name, *value = cur;
+		name = strsep(&value, "=");
+		if (!strcasecmp(name, "ringtimeout")) {
+			if (sscanf(value, "%u", &trunk_ref->ring_timeout) != 1) {
+				ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
+					"trunk '%s' on station '%s'\n", value, trunk->name, station->name);
+				trunk_ref->ring_timeout = 0;
+			}
+		} else {
+			ast_log(LOG_WARNING, "Invalid option '%s' for "
+				"trunk '%s' on station '%s'\n", name, trunk->name, station->name);
+		}
+	}
+
+	if (!(station_ref = sla_create_station_ref(station))) {
+		free(trunk_ref);
+		return;
+	}
+	ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
+	AST_RWLIST_WRLOCK(&sla_trunks);
+	AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
+	AST_RWLIST_UNLOCK(&sla_trunks);
+	AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
+}
+
+static int sla_build_station(struct ast_config *cfg, const char *cat)
 {
 	struct sla_station *station;
 	struct ast_variable *var;
@@ -3761,35 +4159,16 @@ static int build_station(struct ast_config *cfg, const char *cat)
 	ast_string_field_set(station, device, dev);
 
 	for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
-		if (!strcasecmp(var->name, "trunk")) {
-			struct sla_trunk *trunk;
-			struct sla_trunk_ref *trunk_ref;
-			struct sla_station_ref *station_ref;
-			AST_RWLIST_RDLOCK(&sla_trunks);
-			AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
-				if (!strcasecmp(trunk->name, var->value))
-					break;
-			}
-			AST_RWLIST_UNLOCK(&sla_trunks);
-			if (!trunk) {
-				ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
-				continue;
-			}
-			if (!(trunk_ref = create_trunk_ref(trunk)))
-				continue;
-			trunk_ref->state = SLA_TRUNK_STATE_IDLE;
-			if (!(station_ref = ast_calloc(1, sizeof(*station_ref)))) {
-				free(trunk_ref);
-				continue;
-			}
-			station_ref->station = station;
-			ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
-			AST_RWLIST_WRLOCK(&sla_trunks);
-			AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
-			AST_RWLIST_UNLOCK(&sla_trunks);
-			AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
-		} else if (!strcasecmp(var->name, "autocontext")) {
+		if (!strcasecmp(var->name, "trunk"))
+			sla_add_trunk_to_station(station, var);
+		else if (!strcasecmp(var->name, "autocontext"))
 			ast_string_field_set(station, autocontext, var->value);
+		else if (!strcasecmp(var->name, "ringtimeout")) {
+			if (sscanf(var->value, "%u", &station->ring_timeout) != 1) {
+				ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
+					var->value, station->name);
+				station->ring_timeout = 0;
+			}
 		} else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
 			ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
 				var->name, var->lineno, SLA_CONFIG_FILE);
@@ -3844,13 +4223,13 @@ static int build_station(struct ast_config *cfg, const char *cat)
 	}
 
 	AST_RWLIST_WRLOCK(&sla_stations);
-	AST_RWLIST_INSERT_HEAD(&sla_stations, station, entry);
+	AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
 	AST_RWLIST_UNLOCK(&sla_stations);
 
 	return 0;
 }
 
-static int load_config_sla(void)
+static int sla_load_config(void)
 {
 	struct ast_config *cfg;
 	const char *cat = NULL;
@@ -3870,9 +4249,9 @@ static int load_config_sla(void)
 			continue;
 		}
 		if (!strcasecmp(type, "trunk"))
-			res = build_trunk(cfg, cat);
+			res = sla_build_trunk(cfg, cat);
 		else if (!strcasecmp(type, "station"))
-			res = build_station(cfg, cat);
+			res = sla_build_station(cfg, cat);
 		else {
 			ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
 				SLA_CONFIG_FILE, type);
@@ -3892,7 +4271,7 @@ static int load_config(int reload)
 
 	load_config_meetme();
 	if (!reload)
-		res = load_config_sla();
+		res = sla_load_config();
 
 	return res;
 }
@@ -3915,7 +4294,7 @@ static int unload_module(void)
 
 	ast_module_user_hangup_all();
 	
-	destroy_sla();
+	sla_destroy();
 
 	return res;
 }
diff --git a/configs/sla.conf.sample b/configs/sla.conf.sample
index a8ff93a90cdd4f1d69a9968d1e1a5bf4123da6e5..839d6d936f20c33e3c8d6d73e636b4ccb2753580 100644
--- a/configs/sla.conf.sample
+++ b/configs/sla.conf.sample
@@ -22,6 +22,9 @@
                           ; a unique context name.  Then, in zapata.conf, this device 
                           ; should be configured to have incoming calls go to this context.
 
+;ringtimeout=30           ; Set how long to allow this trunk to ring on an inbound call before hanging 
+                          ; it up as an unanswered call.  The value is in seconds.
+
 ;[line2]
 ;type=trunk
 ;device=Zap/4
@@ -41,10 +44,6 @@
 
 ; ---- Station Declarations ------------
 
-;[station](!)                       ; In this example, all stations have the same trunks, so this 
-                                    ; configuration template is used to simplify the declaration 
-                                    ; of each station.
-
 ;type=station                       ; This line indicates that this entry is a station.
 
 ;autocontext=sla_stations           ; This supports automatic generation of the dialplan entries if 
@@ -52,13 +51,21 @@
                                     ; context without conflict.  The device for this station should 
                                     ; have its context configured to the same one listed here.
 
+;ringtimeout=10                     ; Set a timeout for how long to allow the station to ring for an 
+;                                   ; incoming call, in seconds.
+
+
 ;trunk=line1                        ; Individually list all of the trunks that will appear on this station.  This
                                     ; order is significant.  It should be the same order as they appear on the
                                     ; phone.  The order here defines the order of preference that the trunks will
                                     ; be used.
 ;trunk=line2
 ;trunk=line3
-;trunk=line4
+;trunk=line4,ringtimeout=5          ; A ring timeout for the station can also be specified for a specific trunk.
+                                    ; If a ring timeout is specified both for the whole station and for a specific
+                                    ; trunk on a station, the setting for the specific trunk will take priority.
+                                    ; This value is in seconds.
+
 
 ;[station1](station)                ; Define a station that uses the configuration from the template "station".
 ;device=SIP/station1                ; Each station must be mapped to a device.
diff --git a/doc/sla.txt b/doc/sla.txt
index 8a3eb71daed145a5e015982f6b284e74a2a4e76a..7b78001a90957528eba3f6980ba27d812f1ca6e1 100644
--- a/doc/sla.txt
+++ b/doc/sla.txt
@@ -1,17 +1,17 @@
--------------------------------------------------------------
---- Shared Line Appearances ---------------------------------
--------------------------------------------------------------
+-------------------------------------------------------------------------------
+--- Shared Line Appearances ---------------------------------------------------
+-------------------------------------------------------------------------------
 
--------------------------------------------------------------
+-------------------------------------------------------------------------------
 INTRODUCTION
 
 The "SLA" functionality in Asterisk is intended to allow a setup that emulates
 a simple key system.  It uses the various abstraction layers already built into
 Asterisk to emulate key system functionality across various devices, including
 IP channels.
--------------------------------------------------------------
+-------------------------------------------------------------------------------
 
--------------------------------------------------------------
+-------------------------------------------------------------------------------
 DIALPLAN CONFIGURATION
 
 The SLA implementation can automatically generate the dialplan necessary for
@@ -44,9 +44,9 @@ exten => station3_line1,hint,SLA:station3_line1
 exten => station3_line1,1,SLAStation(station3_line1)
 exten => station3_line2,hint,SLA:station3_line2
 exten => station3_line2,1,SLAStation(station3_line2)
--------------------------------------------------------------
+-------------------------------------------------------------------------------
 
--------------------------------------------------------------
+-------------------------------------------------------------------------------
 TRUNKS
 
 For the trunk side of SLA, the only channels that are currently supported are
@@ -57,10 +57,10 @@ Be sure to configure the trunk's context to be the same one that is set for the
 
 If the dialplan is being built manually, ensure that calls coming in on a trunk
 execute the SLATrunk() application with an argument of the trunk name.
--------------------------------------------------------------
+-------------------------------------------------------------------------------
 
 
--------------------------------------------------------------
+-------------------------------------------------------------------------------
 STATIONS
 
 Currently, the only channel driver that has all of the features necessary to
@@ -90,4 +90,4 @@ a SIP phone for use with SLA:
    c) If you would like the phone to automatically connect to a trunk when it
       is taken off hook, then the phone should be automatically configured to
       dial "station1" when it is taken off hook.
--------------------------------------------------------------
+-------------------------------------------------------------------------------
diff --git a/main/dial.c b/main/dial.c
index af3c5e3541bc0fef995a2e8bf82aeb3b86092775..9536629e93b11a8978bf13c59f5e738c3961d70b 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -559,7 +559,7 @@ enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *cha
 
 	/* If we are running async spawn a thread and send it away... otherwise block here */
 	if (async) {
-		set_state(dial, AST_DIAL_RESULT_TRYING);
+		dial->state = AST_DIAL_RESULT_TRYING;
 		/* Try to create a thread */
 		if (ast_pthread_create(&dial->thread, NULL, async_dial, dial)) {
 			/* Failed to create the thread - hangup all dialed channels and return failed */