aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2003-03-30 22:55:42 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2003-03-30 22:55:42 +0000
commite0c466aa42beff5788490914ece124091e8a7da7 (patch)
treec5e39cc2f65741736cc4c1676854ba25af9b4142
parent4a1c073adb76e17e72b257c86c847f6028392707 (diff)
Merge hint patch, add new variables, and misc. PBX cleanups
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@722 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xREADME.variables1
-rwxr-xr-xcdr.c1
-rwxr-xr-xchannel.c78
-rwxr-xr-xchannels/chan_modem_bestdata.c1
-rwxr-xr-xchannels/chan_sip.c11
-rwxr-xr-xcodecs/codec_speex.c8
-rwxr-xr-xdoc/README.variables1
-rwxr-xr-xformats/format_pcm_alaw.c2
-rwxr-xr-xinclude/asterisk/channel.h39
-rwxr-xr-xinclude/asterisk/pbx.h66
-rwxr-xr-xpbx.c350
-rwxr-xr-xpbx/pbx_config.c45
12 files changed, 569 insertions, 34 deletions
diff --git a/README.variables b/README.variables
index 957ab633c..bb44ff1fe 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 32999fd0e..a06c88f99 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 f1ea7f780..ed9bd2511 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;
@@ -144,6 +145,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)) {
ast_log(LOG_WARNING, "Unable to lock channel list\n");
@@ -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 027cba074..3faad53e8 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 f86f38279..2d6ddcd98 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 98a2aaab2..3c2e4f519 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 957ab633c..bb44ff1fe 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 c7e1ef749..129e292b3 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 6979515da..09cd2a6cf 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 f6034b61e..a616414e3 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 0c01820d5..655f9bd7d 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 f7b143daf..b957f29e4 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);