diff --git a/README.variables b/README.variables
index 957ab633cb3011333cf168dbd1988f6aea40f2f5..bb44ff1fec3e652e30eb6e3ffc381a08d5ced7ae 100755
--- a/README.variables
+++ b/README.variables
@@ -35,6 +35,7 @@ ${CALLERIDNUM}	Caller ID Number only
 ${EXTEN}	Current extension
 ${CONTEXT}      Current context
 ${PRIORITY}	Current priority
+${CHANNEL}	Current channel name
 
 There are two reference modes - reference by value and reference by name. 
 To refer to a variable with its name (as an argument to a function that 
diff --git a/cdr.c b/cdr.c
index 32999fd0eefbb7c874fdb93881d0a4982d557b0d..a06c88f99b8c4626d2c548facd721e308f6b03e2 100755
--- a/cdr.c
+++ b/cdr.c
@@ -21,6 +21,7 @@
 #include <asterisk/callerid.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
 #include <pthread.h>
 
 int ast_default_amaflags = AST_CDR_DOCUMENTATION;
diff --git a/channel.c b/channel.c
index f1ea7f780d0163ec7d4a0f9c42bcf8316077a6a2..ed9bd25113f1f204ab227d44f92641c1e0ef8a20 100755
--- a/channel.c
+++ b/channel.c
@@ -64,6 +64,7 @@ struct chanlist {
 	char description[80];
 	int capabilities;
 	struct ast_channel * (*requester)(char *type, int format, void *data);
+	int (*devicestate)(void *data);
 	struct chanlist *next;
 } *backends = NULL;
 struct ast_channel *channels = NULL;
@@ -143,6 +144,13 @@ time_t	myt;
 
 int ast_channel_register(char *type, char *description, int capabilities,
 		struct ast_channel *(*requester)(char *type, int format, void *data))
+{
+    return ast_channel_register_ex(type, description, capabilities, requester, NULL);
+}
+
+int ast_channel_register_ex(char *type, char *description, int capabilities,
+		struct ast_channel *(*requester)(char *type, int format, void *data),
+		int (*devicestate)(void *data))
 {
 	struct chanlist *chan, *last=NULL;
 	if (PTHREAD_MUTEX_LOCK(&chlock)) {
@@ -169,6 +177,7 @@ int ast_channel_register(char *type, char *description, int capabilities,
 	strncpy(chan->description, description, sizeof(chan->description)-1);
 	chan->capabilities = capabilities;
 	chan->requester = requester;
+	chan->devicestate = devicestate;
 	chan->next = NULL;
 	if (last)
 		last->next = chan;
@@ -469,6 +478,7 @@ void ast_channel_free(struct ast_channel *chan)
 	struct ast_var_t *vardata;
 	struct ast_frame *f, *fp;
 	struct varshead *headp;
+	char name[AST_CHANNEL_NAME];
 	
 	headp=&chan->varshead;
 	
@@ -489,10 +499,14 @@ void ast_channel_free(struct ast_channel *chan)
 		ast_log(LOG_WARNING, "Unable to find channel in list\n");
 	if (chan->pvt->pvt)
 		ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
+
+	strncpy(name, chan->name, sizeof(name)-1);
+	
 	/* Stop monitoring */
 	if (chan->monitor) {
 		chan->monitor->stop( chan, 0 );
 	}
+
 	/* Free translatosr */
 	if (chan->pvt->readtrans)
 		ast_translator_free_path(chan->pvt->readtrans);
@@ -537,6 +551,8 @@ void ast_channel_free(struct ast_channel *chan)
 	chan->pvt = NULL;
 	free(chan);
 	PTHREAD_MUTEX_UNLOCK(&chlock);
+
+	ast_device_state_changed(name);
 }
 
 int ast_softhangup_nolock(struct ast_channel *chan, int cause)
@@ -1409,6 +1425,7 @@ struct ast_channel *ast_request(char *type, int format, void *data)
 			if (chan->requester)
 				c = chan->requester(type, capabilities, data);
 			if (c) {
+//				ast_device_state_changed(c->name);
 				manager_event(EVENT_FLAG_CALL, "Newchannel",
 				"Channel: %s\r\n"
 				"State: %s\r\n"
@@ -1425,6 +1442,66 @@ struct ast_channel *ast_request(char *type, int format, void *data)
 	return c;
 }
 
+int ast_parse_device_state(char *device)
+{
+	char name[AST_CHANNEL_NAME] = "";
+	char *cut;
+	struct ast_channel *chan;
+
+	chan = ast_channel_walk(NULL);
+	while (chan) {
+		strncpy(name, chan->name, sizeof(name)-1);
+		cut = strchr(name,'-');
+		if (cut)
+		        *cut = 0;
+		if (!strcmp(name, device))
+		        return AST_DEVICE_INUSE;
+		chan = ast_channel_walk(chan);
+	}
+	return AST_DEVICE_UNKNOWN;
+}
+
+int ast_device_state(char *device)
+{
+	char tech[AST_MAX_EXTENSION] = "";
+	char *number;
+	struct chanlist *chanls;
+	int res = 0;
+	
+	strncpy(tech, device, sizeof(tech)-1);
+	number = strchr(tech, '/');
+	if (!number) {
+	    return AST_DEVICE_INVALID;
+	}
+	*number = 0;
+	number++;
+		
+	if (PTHREAD_MUTEX_LOCK(&chlock)) {
+		ast_log(LOG_WARNING, "Unable to lock channel list\n");
+		return -1;
+	}
+	chanls = backends;
+	while(chanls) {
+		if (!strcasecmp(tech, chanls->type)) {
+			PTHREAD_MUTEX_UNLOCK(&chlock);
+			if (!chanls->devicestate) 
+				return ast_parse_device_state(device);
+			else {
+				res = chanls->devicestate(number);
+				if (res == AST_DEVICE_UNKNOWN)
+					return ast_parse_device_state(device);
+				else
+					return res;
+			}
+		}
+		chanls = chanls->next;
+	}
+	if (!chanls)
+		ast_log(LOG_WARNING, "No channel type registered for '%s'\n", tech);
+	PTHREAD_MUTEX_UNLOCK(&chlock);
+	return AST_DEVICE_INVALID;
+}
+
 int ast_call(struct ast_channel *chan, char *addr, int timeout) 
 {
 	/* Place an outgoing call, but don't wait any longer than timeout ms before returning. 
@@ -1813,6 +1890,7 @@ int ast_setstate(struct ast_channel *chan, int state)
 		int oldstate = chan->_state;
 		chan->_state = state;
 		if (oldstate == AST_STATE_DOWN) {
+			ast_device_state_changed(chan->name);
 			manager_event(EVENT_FLAG_CALL, "Newchannel",
 			"Channel: %s\r\n"
 			"State: %s\r\n"
diff --git a/channels/chan_modem_bestdata.c b/channels/chan_modem_bestdata.c
index 027cba07464667f91c305d433c2a185f99a9bf49..3faad53e8e27d0df6a33adb33de87b49e44c9b6d 100755
--- a/channels/chan_modem_bestdata.c
+++ b/channels/chan_modem_bestdata.c
@@ -17,6 +17,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <unistd.h>
 #include <asterisk/lock.h>
 #include <asterisk/vmodem.h>
 #include <asterisk/module.h>
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index f86f38279e52b84b6d9d8c94e78b51e66a643eac..2d6ddcd98b75d1dae529120b0013427ef55bd2b6 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1740,10 +1740,10 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
 		char contact[256];
 		char *c;
 		if ((c=getsipuri(ot))) {
-			snprintf(contact, sizeof(contact), "<%s@%s>", c, inet_ntoa(p->ourip));
+			snprintf(contact, sizeof(contact), "<%s@%s:%d>", c, inet_ntoa(p->ourip), ourport);
 			free(c);
 		} else {
-			snprintf(contact, sizeof(contact), "<%s>", inet_ntoa(p->ourip));
+			snprintf(contact, sizeof(contact), "<%s:%d>", inet_ntoa(p->ourip), ourport);
 		}
 		snprintf(tmp, sizeof(tmp), "%d", p->expirey);
 		add_header(resp, "Expires", tmp);
@@ -1754,10 +1754,10 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
 		       very stupidly *sigh* XXX */
 		char *c;
 		if ((c=getsipuri(ot))) {
-			snprintf(contact, sizeof(contact), "<%s@%s>", c, inet_ntoa(p->ourip));
+			snprintf(contact, sizeof(contact), "<%s@%s:%d>", c, inet_ntoa(p->ourip), ourport);
 			free(c);
 		} else {
-			snprintf(contact, sizeof(contact), "<%s>", inet_ntoa(p->ourip));
+			snprintf(contact, sizeof(contact), "<%s:%d>", inet_ntoa(p->ourip), ourport);
 		}
 		add_header(resp, "Contact", contact);
 	}
@@ -2048,7 +2048,8 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
 	}
 	if (!n)
 		n = l;
-	snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%08x", n, l, inet_ntoa(p->ourip), p->tag);
+	snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%08x", n, l, inet_ntoa(p->ourip), ourport, p->tag);
+
 	if (strlen(p->username)) {
 		if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) {
 			snprintf(invite, sizeof(invite), "sip:%s@%s:%d",p->username, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port));
diff --git a/codecs/codec_speex.c b/codecs/codec_speex.c
index 98a2aaab2922d3c4b4dbd77bc5cc6b94382a341b..3c2e4f51995d2064052c780ceb0f44a64522c908 100755
--- a/codecs/codec_speex.c
+++ b/codecs/codec_speex.c
@@ -58,7 +58,7 @@ struct ast_translator_pvt {
 
 #define speex_coder_pvt ast_translator_pvt
 
-static struct ast_translator_pvt *lintospeex_new()
+static struct ast_translator_pvt *lintospeex_new(void)
 {
 	struct speex_coder_pvt *tmp;
 	tmp = malloc(sizeof(struct speex_coder_pvt));
@@ -77,7 +77,7 @@ static struct ast_translator_pvt *lintospeex_new()
 	return tmp;
 }
 
-static struct ast_translator_pvt *speextolin_new()
+static struct ast_translator_pvt *speextolin_new(void)
 {
 	struct speex_coder_pvt *tmp;
 	tmp = malloc(sizeof(struct speex_coder_pvt));
@@ -95,7 +95,7 @@ static struct ast_translator_pvt *speextolin_new()
 	return tmp;
 }
 
-static struct ast_frame *lintospeex_sample()
+static struct ast_frame *lintospeex_sample(void)
 {
 	static struct ast_frame f;
 	f.frametype = AST_FRAME_VOICE;
@@ -110,7 +110,7 @@ static struct ast_frame *lintospeex_sample()
 	return &f;
 }
 
-static struct ast_frame *speextolin_sample()
+static struct ast_frame *speextolin_sample(void)
 {
 	static struct ast_frame f;
 	f.frametype = AST_FRAME_VOICE;
diff --git a/doc/README.variables b/doc/README.variables
index 957ab633cb3011333cf168dbd1988f6aea40f2f5..bb44ff1fec3e652e30eb6e3ffc381a08d5ced7ae 100755
--- a/doc/README.variables
+++ b/doc/README.variables
@@ -35,6 +35,7 @@ ${CALLERIDNUM}	Caller ID Number only
 ${EXTEN}	Current extension
 ${CONTEXT}      Current context
 ${PRIORITY}	Current priority
+${CHANNEL}	Current channel name
 
 There are two reference modes - reference by value and reference by name. 
 To refer to a variable with its name (as an argument to a function that 
diff --git a/formats/format_pcm_alaw.c b/formats/format_pcm_alaw.c
index c7e1ef74967db5d03c8117f2c9d1aff6d8773154..129e292b3e0084d3985e711b390e29409533f6bf 100755
--- a/formats/format_pcm_alaw.c
+++ b/formats/format_pcm_alaw.c
@@ -64,7 +64,7 @@ static char *exts = "alaw|al";
 
 
 /* Returns time in msec since system boot. */
-static unsigned long get_time()
+static unsigned long get_time(void)
 {
 	struct tms buf;
 	clock_t cur;
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 6979515da5a9f9a6bf8a264256585875df13bf2c..09cd2a6cfb6aa6d534df5d6c84c72339feab949d 100755
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -233,6 +233,19 @@ struct chanmon;
 /*! Do not transmit voice data */
 #define AST_STATE_MUTE		(1 << 16)	
 
+/*! Device is valid but channel didn't know state */
+#define AST_DEVICE_UNKNOWN	0
+/*! Device is not used */
+#define AST_DEVICE_NOT_INUSE	1
+/*! Device is in use */
+#define AST_DEVICE_INUSE	2
+/*! Device is busy */
+#define AST_DEVICE_BUSY		3
+/*! Device is invalid */
+#define AST_DEVICE_INVALID	4
+/*! Device is unavailable */
+#define AST_DEVICE_UNAVAILABLE	5
+
 //! Requests a channel
 /*! 
  * \param type type of channel to request
@@ -244,6 +257,27 @@ struct chanmon;
  */
 struct ast_channel *ast_request(char *type, int format, void *data);
 
+//! Search the Channels by Name
+/*!
+ * \param device like a dialstring
+ * Search the Device in active channels by compare the channelname against 
+ * the devicename. Compared are only the first chars to the first '-' char.
+ * Returns an AST_DEVICE_UNKNOWN if no channel found or
+ * AST_DEVICE_INUSE if a channel is found
+ */
+int ast_parse_device_state(char *device);
+
+//! Asks a channel for device state
+/*!
+ * \param device like a dialstring
+ * Asks a channel for device state, data is  normaly a number from dialstring
+ * used by the low level module
+ * Trys the channel devicestate callback if not supported search in the
+ * active channels list for the device.
+ * Returns an AST_DEVICE_??? state -1 on failure
+ */
+int ast_device_state(char *device);
+
 /*!
  * \param type type of channel to request
  * \param format requested channel format
@@ -271,6 +305,11 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int
 int ast_channel_register(char *type, char *description, int capabilities, 
 			struct ast_channel* (*requester)(char *type, int format, void *data));
 
+/* Same like the upper function but with support for devicestate */
+int ast_channel_register_ex(char *type, char *description, int capabilities,
+		struct ast_channel *(*requester)(char *type, int format, void *data),
+		int (*devicestate)(void *data));
+
 //! Unregister a channel class
 /*
  * \param type the character string that corresponds to the channel you wish to unregister
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index f6034b61e6129d8a69f47d2ec64d4c005c3401cd..a616414e33f6d91935d96f9c450c7f1be64ef31d 100755
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -29,12 +29,27 @@ extern "C" {
 //! Special return values from applications to the PBX
 #define AST_PBX_KEEPALIVE	10		/* Destroy the thread, but don't hang up the channel */
 
+//! Special Priority for an hint
+#define PRIORITY_HINT	-1
+
+//! Extension states
+//! No device INUSE or BUSY 
+#define AST_EXTENSION_NOT_INUSE		0
+//! One or more devices INUSE
+#define AST_EXTENSION_INUSE		1
+//! All devices BUSY
+#define AST_EXTENSION_BUSY		2
+//! All devices UNAVAILABLE/UNREGISTERED
+#define AST_EXTENSION_UNAVAILABLE 	3
+
 struct ast_context;
 struct ast_exten;     
 struct ast_include;
 struct ast_ignorepat;
 struct ast_sw;
 
+typedef int (*ast_notify_cb_type)(char *context, char* id, int state, void *data);
+
 //! Data structure associated with an asterisk switch
 struct ast_switch {
 	/*! NULL */
@@ -189,6 +204,57 @@ int ast_register_application(char *app, int (*execute)(struct ast_channel *, voi
  */
 int ast_unregister_application(char *app);
 
+//! Uses hint and devicestate callback to get the state of an extension
+/*!
+ * \param c this is not important
+ * \param context which context to look in
+ * \param exten which extension to get state
+ * Returns extension state !! = AST_EXTENSION_???
+ */
+int ast_extension_state(struct ast_channel *c, char *context, char *exten);
+
+//! Tells Asterisk the State for Device is changed
+/*!
+ * \param device devicename like a dialstring
+ * Asterisk polls the new extensionstates and calls the registered
+ * callbacks for the changed extensions
+ * Returns 0 on success, -1 on failure
+ */
+int ast_device_state_changed(char *device);
+
+//! Registers a state change callback
+/*!
+ * \param context which context to look in
+ * \param exten which extension to get state
+ * \param callback callback to call if state changed
+ * \param data to pass to callback
+ * The callback is called if the state for extension is changed
+ * Return -1 on failure, ID on success
+ */ 
+int ast_extension_state_add(char *context, char *exten, 
+			    ast_notify_cb_type callback, void *data);
+
+//! Deletes a registered state change callback by ID
+/*!
+ * \param id of the callback to delete
+ * Removes the callback from list of callbacks
+ * Return 0 on success, -1 on failure
+ */
+int ast_extension_state_del(int id);
+
+//! If an extension exists, return non-zero
+/*!
+ * \param hint buffer for hint
+ * \param maxlen size of hint buffer
+ * \param c this is not important
+ * \param context which context to look in
+ * \param exten which extension to search for
+ * If an extension within the given context with the priority PRIORITY_HINT
+ * is found a non zero value will be returned.
+ * Otherwise, 0 is returned.
+ */
+int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten);
+
 //! If an extension exists, return non-zero
 // work
 /*!
diff --git a/pbx.c b/pbx.c
index 0c01820d5827dce3f5a078d500137ea1d1cd3334..655f9bd7d44711844fc49e68c3549479d8f71034 100755
--- a/pbx.c
+++ b/pbx.c
@@ -132,6 +132,22 @@ struct ast_app {
 	struct ast_app *next;
 };
 
+/* An extension state notify */
+struct ast_notify_cb {
+    int id;
+    void *data;
+    ast_notify_cb_type callback;
+    struct ast_notify_cb *next;
+};
+	    
+struct ast_notify {
+    struct ast_exten *exten;
+    int laststate; 
+    struct ast_notify_cb *callbacks;
+    struct ast_notify *next;
+};
+
+
 static int pbx_builtin_prefix(struct ast_channel *, void *);
 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
 static int pbx_builtin_answer(struct ast_channel *, void *);
@@ -294,6 +310,11 @@ static struct ast_app *apps = NULL;
 static pthread_mutex_t switchlock = AST_MUTEX_INITIALIZER;
 struct ast_switch *switches = NULL;
 
+/* Lock for extension state notifys */
+static pthread_mutex_t notifylock = AST_MUTEX_INITIALIZER;
+static int notifycnt = 0;
+struct ast_notify *notifys = NULL;
+
 int pbx_exec(struct ast_channel *c, /* Channel */
 					struct ast_app *app,
 					void *data,				/* Data for execution */
@@ -676,20 +697,19 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *cont
 	return NULL;
 }
 
-static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char **cp4)
+static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char **cp4, char *workspace, int workspacelen)
 {
 	char *first,*second;
 	int offset,offset2;
 	struct ast_var_t *variables;
 	char *name, *num; /* for callerid name + num variables */
 	struct varshead *headp;
-	char pri[80];
         headp=&c->varshead;
         *cp4=NULL;
         /* Now we have the variable name on cp3 */
 	if ((first=strchr(cp3,':'))) {
 		*first='\0';
-		pbx_substitute_variables_temp(c,cp3,cp4);
+		pbx_substitute_variables_temp(c,cp3,cp4,workspace,workspacelen);
 		if (!(*cp4)) return;
 		offset=atoi(first+1);
 	 	if ((second=strchr(first+1,':'))) {
@@ -711,20 +731,18 @@ static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char *
 			*cp4+=strlen(*cp4)+offset;
 		(*cp4)[offset2] = '\0';
 	} else if (!strcmp(cp3, "CALLERIDNUM")) {
-		char cid[256] = "";
 		if (c->callerid)
-			strncpy(cid, c->callerid, sizeof(cid) - 1);
-		ast_callerid_parse(cid, &name, &num);
+			strncpy(workspace, c->callerid, workspacelen - 1);
+		ast_callerid_parse(workspace, &name, &num);
 		if (num) {
 			ast_shrink_phone_number(num);
 			*cp4 = num;
 		} else
 			*cp4 = "";
 	} else if (!strcmp(cp3, "CALLERIDNAME")) {
-		char cid[256] = "";
 		if (c->callerid)
-			strncpy(cid, c->callerid, sizeof(cid) - 1);
-		ast_callerid_parse(cid, &name, &num);
+			strncpy(workspace, c->callerid, workspacelen - 1);
+		ast_callerid_parse(workspace, &name, &num);
 		if (name)
 			*cp4 = name;
 		else
@@ -733,6 +751,11 @@ static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char *
 		*cp4 = c->callerid;
 		if (!(*cp4))
 			*cp4 = "";
+	} else if (!strcmp(cp3, "HINT")) {
+		if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten))
+			*cp4 = "";
+		else
+			*cp4 = workspace;
 	} else if (!strcmp(cp3, "EXTEN")) {
 		*cp4 = c->exten;
 	} else if (!strncmp(cp3, "EXTEN-", strlen("EXTEN-")) && 
@@ -760,8 +783,10 @@ static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char *
 	} else if (!strcmp(cp3, "CONTEXT")) {
 		*cp4 = c->context;
 	} else if (!strcmp(cp3, "PRIORITY")) {
-		snprintf(pri, sizeof(pri), "%d", c->priority);
-		*cp4 = pri;
+		snprintf(workspace, workspacelen, "%d", c->priority);
+		*cp4 = workspace;
+	} else if (!strcmp(cp3, "CHANNEL")) {
+		*cp4 = c->name;
 	} else {
 		AST_LIST_TRAVERSE(headp,variables,entries) {
 #if 0
@@ -796,6 +821,7 @@ static void pbx_substitute_variables_helper(struct ast_channel *c,char *cp1,char
 	char *cp4,*cp2;
 	char *tmp,*wherearewe,*finish=NULL,*ltmp,*lval,*nextvar;
 	int length,variables=0;
+	char workspace[256];
 
 	wherearewe=tmp=cp1;
 	cp2=*ecp2;
@@ -854,7 +880,7 @@ static void pbx_substitute_variables_helper(struct ast_channel *c,char *cp1,char
 				cp1=cp2;
 			}
 			if (count) {			
-				pbx_substitute_variables_temp(c,cp1,&cp4);
+				pbx_substitute_variables_temp(c,cp1,&cp4, workspace, sizeof(workspace));
 				if (cp4) {
 					/* reset output variable so we could store the result */
 					*cp2='\0';
@@ -1080,6 +1106,300 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
 
 }
 
+static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
+{
+	struct ast_exten *e;
+	struct ast_switch *sw;
+	char *data;
+	int status = 0;
+	char *incstack[AST_PBX_MAX_STACK];
+	int stacklen = 0;
+
+	if (ast_pthread_mutex_lock(&conlock)) {
+		ast_log(LOG_WARNING, "Unable to obtain lock\n");
+		return NULL;
+	}
+	e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
+	ast_pthread_mutex_unlock(&conlock);	
+	return e;
+}
+
+static int ast_extension_state2(struct ast_exten *e)
+{
+    char hint[AST_MAX_EXTENSION] = "";    
+    char *cur, *rest;
+    int res = -1;
+    int allunavailable = 1, allbusy = 1, allfree = 1;
+    int busy = 0;
+
+    strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
+    
+    cur = hint;    
+    do {
+	rest = strchr(cur, '&');
+	if (rest) {
+	    *rest = 0;
+	    rest++;
+	}
+	
+	res = ast_device_state(cur);
+	switch (res) {
+	    case AST_DEVICE_NOT_INUSE:
+		allunavailable = 0;
+		allbusy = 0;
+		break;
+	    case AST_DEVICE_INUSE:
+		return AST_EXTENSION_INUSE;
+	    case AST_DEVICE_BUSY:
+		allunavailable = 0;
+		allfree = 0;
+		busy = 1;
+		break;
+	    case AST_DEVICE_UNAVAILABLE:
+	    case AST_DEVICE_INVALID:
+		allbusy = 0;
+		allfree = 0;
+		break;
+	    default:
+		allunavailable = 0;
+		allbusy = 0;
+		allfree = 0;
+	}
+        cur = rest;
+    } while (cur);
+
+    if (allfree)
+	return AST_EXTENSION_NOT_INUSE;
+    if (allbusy)
+	return AST_EXTENSION_BUSY;
+    if (allunavailable)
+	return AST_EXTENSION_UNAVAILABLE;
+    if (busy) 
+	return AST_EXTENSION_INUSE;
+
+    return AST_EXTENSION_NOT_INUSE;
+}
+
+
+int ast_extension_state(struct ast_channel *c, char *context, char *exten)
+{
+    struct ast_exten *e;
+
+    e = ast_hint_extension(c, context, exten);    
+    if (!e) 
+	return -1;
+
+    return ast_extension_state2(e);    
+}
+
+int ast_device_state_changed(char *device) 
+{
+    struct ast_notify *list;
+    struct ast_notify_cb *cblist;
+    char hint[AST_MAX_EXTENSION];
+    char *cur, *rest;
+    int state;
+        
+    pthread_mutex_lock(&notifylock);
+
+    list = notifys;
+    
+    while (list) {
+	
+	strcpy(hint, ast_get_extension_app(list->exten));
+	cur = hint;
+	do {
+	    rest = strchr(cur, '&');
+	    if (rest) {
+		*rest = 0;
+		rest++;
+	    }
+	    
+	    if (!strncmp(cur, device, strlen(cur))) {
+	    // Found extension execute callbacks 
+		state = ast_extension_state2(list->exten);
+		if ((state != -1) && (state != list->laststate)) {
+    		    cblist = list->callbacks;
+		    while (cblist) {
+			cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
+			cblist = cblist->next;
+		    }
+		    list->laststate = state;
+		}
+		break;
+	    }
+	    cur = rest;
+	} while (cur);
+	
+	list = list->next;
+    }
+
+    pthread_mutex_unlock(&notifylock);
+    return 1;
+}
+			
+int ast_extension_state_add(char *context, char *exten, 
+			    ast_notify_cb_type callback, void *data)
+{
+    struct ast_notify *list;
+    struct ast_notify_cb *cblist;
+    struct ast_exten *e;
+
+    pthread_mutex_lock(&notifylock);
+    list = notifys;        
+    
+    while (list) {
+	if (!strcmp(list->exten->parent->name, context) && 
+	    !strcmp(list->exten->exten, exten))
+	    break;	    
+	list = list->next;    
+    }
+
+    if (!list) {
+	e = ast_hint_extension(NULL, context, exten);    
+	if (!e) {
+	    pthread_mutex_unlock(&notifylock);
+	    return -1;
+	}
+	list = malloc(sizeof(struct ast_notify));
+	if (!list) {
+	    pthread_mutex_unlock(&notifylock);
+	    return -1;
+	}
+	/* Initialize and insert new item */
+	memset(list, 0, sizeof(struct ast_notify));	    
+	list->exten = e;
+	list->laststate = -1;
+	list->next = notifys;
+	notifys = list;
+    }
+    
+    /* Now inserts the callback */
+    cblist = malloc(sizeof(struct ast_notify_cb));
+    if (!cblist) {
+	pthread_mutex_unlock(&notifylock);
+	return -1;
+    }
+    memset(cblist, 0, sizeof(struct ast_notify_cb));
+    cblist->id = notifycnt++;
+    cblist->callback = callback;
+    cblist->data = data;
+
+    cblist->next = list->callbacks;
+    list->callbacks = cblist;
+
+    pthread_mutex_unlock(&notifylock);
+    return cblist->id;
+}
+
+static int ast_extension_state_clean(struct ast_exten *e)
+{
+    /* Cleanup the Notifys if hint is removed */
+    struct ast_notify *list, *prev = NULL;
+    struct ast_notify_cb *cblist, *cbprev;
+
+    pthread_mutex_lock(&notifylock);
+
+    list = notifys;    
+    while(list) {
+	if (list->exten==e) {
+	    cbprev = NULL;
+	    cblist = list->callbacks;
+	    while (cblist) {	    
+		cbprev = cblist;	    
+		cblist = cblist->next;
+		cblist->callback(list->exten->parent->name, list->exten->exten, -1, cblist->data);
+		free(cbprev);
+	    }
+	    list->callbacks = NULL;
+
+	    if (!prev) {
+		notifys = list->next;
+		free(list);
+		list = notifys;
+	    } else {
+		prev->next = list->next;
+		free(list);
+		list = prev->next;
+	    }
+	} else {
+	    prev = list;
+    	    list = list->next;    
+	}
+    }
+
+    pthread_mutex_unlock(&notifylock);
+    return 1;
+}
+
+int ast_extension_state_del(int id)
+{
+    struct ast_notify *list, *prev = NULL;
+    struct ast_notify_cb *cblist, *cbprev;
+            
+    pthread_mutex_lock(&notifylock);
+
+    list = notifys;
+    while (list) {
+	cblist = list->callbacks;
+	cbprev = NULL;
+	while (cblist) {
+	    if (cblist->id==id) {
+		if (!cbprev) {
+		    list->callbacks = cblist->next;		
+		    free(cblist);
+		    cblist = list->callbacks;
+		} else {
+		    cbprev->next = cblist->next;
+		    free(cblist);
+		    cblist = cbprev->next;
+		}
+		
+		if (!list->callbacks) {
+		    if (!prev) {
+			notifys = list->next;
+			free(list);
+			list = notifys;
+		    } else {
+			prev->next = list->next;
+			free(list);
+			list = prev->next;
+		    }
+		}
+		break;
+	    } else {
+    		cbprev = cblist;				
+		cblist = cblist->next;
+	    }
+	}
+
+	// we can have only one item
+	if (cblist)
+	    break;	    
+	    
+	prev = list;
+	list = list->next;
+    }
+    
+    pthread_mutex_unlock(&notifylock);
+    if (list) 
+	return 0;
+    else
+	return -1;
+	
+}
+
+int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
+{
+	struct ast_exten *e;
+	e = ast_hint_extension(c, context, exten);
+	if (e) {	
+	    strncpy(hint, ast_get_extension_app(e), maxlen);
+	    return -1;
+	}
+	return 0;	
+}
+
 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
 {
 	return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
@@ -1544,6 +1864,9 @@ int ast_context_remove_extension2(struct ast_context *con, char *extension, int
 				peer = exten; 
 				while (peer) {
 					exten = peer->peer;
+					
+					if (!peer->priority==PRIORITY_HINT) 
+					    ast_extension_state_clean(peer);
 
 					peer->datad(peer->data);
 					free(peer);
@@ -1589,6 +1912,8 @@ int ast_context_remove_extension2(struct ast_context *con, char *extension, int
 						}
 
 						/* now, free whole priority extension */
+						if (peer->priority==PRIORITY_HINT)
+						    ast_extension_state_clean(peer);
 						peer->datad(peer->data);
 						free(peer);
 
@@ -2956,6 +3281,7 @@ int ast_add_extension2(struct ast_context *con,
 			tmp->matchcid = 0;
 		}
 		strncpy(tmp->app, application, sizeof(tmp->app)-1);
+		tmp->parent = con;
 		tmp->data = data;
 		tmp->datad = datad;
 		tmp->registrar = registrar;
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index f7b143dafb06def00e0252cbfd8cbb5040d09001..b957f29e4248c67e07c7765b78b5c31ea06ec2b0 100755
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -344,14 +344,16 @@ static int handle_context_remove_extension(int fd, int argc, char *argv[])
 		 * why? because atoi (strtol) returns 0 if any characters in
 		 * string and whole extension will be removed, it's not good
 		 */
-		while (*c != '\0') {
+		if (strcmp("hint", c)) {
+    		    while (*c != '\0') {
 			if (!isdigit(*c++)) {
 				ast_cli(fd, "Invalid priority '%s'\n", argv[3]);
 				return RESULT_FAILURE;
 			}
-		}
-
-		removing_priority = atoi(argv[3]);
+		    }
+		    removing_priority = atoi(argv[3]);
+		} else
+		    removing_priority = PRIORITY_HINT;
 
 		if (removing_priority == 0) {
 			ast_cli(fd, "If you want to remove whole extension, please " \
@@ -983,11 +985,17 @@ static int handle_save_dialplan(int fd, int argc, char *argv[])
 							context_header_written = 1;
 						}
 
-						fprintf(output, "exten => %s,%d,%s,%s\n",
-							ast_get_extension_name(p),
-							ast_get_extension_priority(p),
-							ast_get_extension_app(p),
-							(char *)ast_get_extension_app_data(p));
+						if (!ast_get_extension_priority(p)==PRIORITY_HINT)
+							fprintf(output, "exten => %s,%d,%s,%s\n",
+							    ast_get_extension_name(p),
+							    ast_get_extension_priority(p),
+							    ast_get_extension_app(p),
+							    (char *)ast_get_extension_app_data(p));
+						else
+							fprintf(output, "exten => %s,hint,%s\n",
+							    ast_get_extension_name(p),
+							    ast_get_extension_app(p));
+						
 					}
 					p = ast_walk_extension_priorities(e, p);
 				}
@@ -1058,6 +1066,7 @@ static int handle_context_add_extension(int fd, int argc, char *argv[])
 {
 	char *whole_exten;
 	char *exten, *prior;
+	int iprior = -2;
 	char *cidmatch, *app, *app_data;
 	char *start, *end;
 
@@ -1075,6 +1084,11 @@ static int handle_context_add_extension(int fd, int argc, char *argv[])
 		cidmatch = NULL;
 	}
 	prior       = strsep(&whole_exten,",");
+	if (!strcmp(prior, "hint")) {
+	    iprior = PRIORITY_HINT;
+	} else {
+	    iprior = atoi(prior);
+	}
 	app         = strsep(&whole_exten,",");
 	if ((start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
 		*start = *end = '\0';
@@ -1085,9 +1099,11 @@ static int handle_context_add_extension(int fd, int argc, char *argv[])
 	} else
 		app_data    = whole_exten;
 
-	if (!exten || !prior || !app || !app_data) return RESULT_SHOWUSAGE;
+	if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) return RESULT_SHOWUSAGE;
 
-	if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, atoi(prior), cidmatch, app,
+	if (!app_data)
+	    app_data="";
+	if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, cidmatch, app,
 		(void *)strdup(app_data), free, registrar)) {
 		switch (errno) {
 			case ENOMEM:
@@ -1500,6 +1516,7 @@ static int pbx_load_module(void)
 				while(v) {
 					if (!strcasecmp(v->name, "exten")) {
 						char *stringp=NULL;
+						int ipri = -2;
 						tc = strdup(v->value);
 						if(tc!=NULL){
 							stringp=tc;
@@ -1509,6 +1526,10 @@ static int pbx_load_module(void)
 							pri = strsep(&stringp, ",");
 							if (!pri)
 								pri="";
+							if (!strcmp(pri,"hint"))
+								ipri=PRIORITY_HINT;
+							else
+								ipri=atoi(pri);
 							appl = stringp;
 							if (!appl)
 								appl="";
@@ -1544,7 +1565,7 @@ static int pbx_load_module(void)
 
 							if (!data)
 								data="";
-							if (ast_add_extension2(con, 0, ext, atoi(pri), cidmatch, appl, strdup(data), free, registrar)) {
+							if (ast_add_extension2(con, 0, ext, ipri, cidmatch, appl, strdup(data), free, registrar)) {
 								ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
 							}
 							free(tc);