aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b>2010-08-20 16:46:22 +0000
committerrmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b>2010-08-20 16:46:22 +0000
commit66bd24a0507255b9575b74ae12acf7bf575bba9d (patch)
tree8c21c17634f92b3a5d073d07e3bb02ea16881c70
parent994debde3c3d78011509a53fc68dd6ae27a6024e (diff)
Merged revision 278274 from
https://origsvn.digium.com/svn/asterisk/trunk .......... r278274 | rmudgett | 2010-07-20 17:38:13 -0500 (Tue, 20 Jul 2010) | 1 line Reference correct struct member for unlikely event PRI_EVENT_CONFIG_ERR. .......... git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@283123 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--apps/app_dial.c3
-rw-r--r--channels/chan_dahdi.c4
-rw-r--r--channels/chan_local.c20
-rw-r--r--channels/chan_sip.c140
-rw-r--r--configs/say.conf.sample96
-rw-r--r--configs/sip.conf.sample13
-rwxr-xr-xcontrib/scripts/astcli167
-rw-r--r--main/channel.c14
-rw-r--r--main/pbx.c14
-rw-r--r--pbx/pbx_config.c7
10 files changed, 439 insertions, 39 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 3a942ffc2..f1dd6ef3d 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -1856,8 +1856,9 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
sentringing = 0;
ast_indicate(chan, -1);
}
- /* Be sure no generators are left on it */
+ /* Be sure no generators are left on it and reset the visible indication */
ast_deactivate_generator(chan);
+ chan->visible_indication = 0;
/* Make sure channels are compatible */
res = ast_channel_make_compatible(chan, peer);
if (res < 0) {
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index a4e549a6f..667ee0313 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -5636,7 +5636,7 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d
ast_log(LOG_DEBUG,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
#ifdef HAVE_PRI
p->digital = 0; /* Digital-only calls isn't allows any inband progress messages */
- if (!p->progress && p->sig==SIG_PRI && p->pri && !p->outgoing) {
+ if (!p->progress && !p->alerting && p->sig==SIG_PRI && p->pri && !p->outgoing) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
@@ -10066,7 +10066,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_CONFIG_ERR:
- ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err);
+ ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->span, e->err.err);
break;
case PRI_EVENT_RESTART_ACK:
chanpos = pri_find_principle(pri, e->restartack.channel);
diff --git a/channels/chan_local.c b/channels/chan_local.c
index 81f16eadf..7fa6968cc 100644
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -294,6 +294,26 @@ static void check_bridge(struct local_pvt *p)
p->chan->audiohooks = p->owner->audiohooks;
p->owner->audiohooks = audiohooks_swapper;
}
+
+ /* If any Caller ID was set, preserve it after masquerade like above. We must check
+ * to see if Caller ID was set because otherwise we'll mistakingly copy info not
+ * set from the dialplan and will overwrite the real channel Caller ID. The reason
+ * for this whole preswapping action is because the Caller ID is set on the channel
+ * thread (which is the to be masqueraded away local channel) before both local
+ * channels are optimized away.
+ */
+ if (p->owner->cid.cid_dnid || p->owner->cid.cid_num ||
+ p->owner->cid.cid_name || p->owner->cid.cid_ani ||
+ p->owner->cid.cid_rdnis || p->owner->cid.cid_pres ||
+ p->owner->cid.cid_ani2 || p->owner->cid.cid_ton ||
+ p->owner->cid.cid_tns) {
+
+ struct ast_callerid tmpcid;
+ tmpcid = p->owner->cid;
+ p->owner->cid = p->chan->_bridge->cid;
+ p->chan->_bridge->cid = tmpcid;
+ }
+
ast_app_group_update(p->chan, p->owner);
ast_channel_masquerade(p->owner, p->chan->_bridge);
ast_set_flag(p, LOCAL_ALREADY_MASQED);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 631da359d..a7edd8a25 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -149,6 +149,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/compiler.h"
#include "asterisk/threadstorage.h"
#include "asterisk/translate.h"
+#include "asterisk/astobj2.h"
#ifndef FALSE
#define FALSE 0
@@ -855,6 +856,12 @@ static int global_t38_capability = T38FAX_VERSION_0 | T38FAX_RATE_2400 | T38FAX_
#define sipdebug_config ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG)
#define sipdebug_console ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE)
+/*! \brief provisional keep alive scheduler item data */
+struct provisional_keepalive_data {
+ struct sip_pvt *pvt;
+ int sched_id;
+};
+
/*! \brief T38 States for a call */
enum t38state {
T38_DISABLED = 0, /*!< Not enabled */
@@ -1044,7 +1051,7 @@ static struct sip_pvt {
struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */
int request_queue_sched_id; /*!< Scheduler ID of any scheduled action to process queued requests */
- int provisional_keepalive_sched_id; /*!< Scheduler ID for provisional responses that need to be sent out to avoid cancellation */
+ struct provisional_keepalive_data *provisional_keepalive_data; /*!< Scheduler data for provisional responses that need to be sent out to avoid cancellation */
const char *last_provisional; /*!< The last successfully transmitted provisonal response message */
struct sip_pvt *next; /*!< Next dialog in chain */
struct sip_invite_param *options; /*!< Options for INVITE */
@@ -2335,44 +2342,124 @@ static void add_blank(struct sip_request *req)
}
}
-static int send_provisional_keepalive_full(struct sip_pvt *pvt, int with_sdp)
+/*! \brief This is called by the scheduler to resend the last provisional message in a dialog */
+static int send_provisional_keepalive_full(struct provisional_keepalive_data *data, int with_sdp)
{
const char *msg = NULL;
+ int res = 0;
+ struct sip_pvt *pvt = data->pvt;
- if (!pvt->last_provisional || !strncasecmp(pvt->last_provisional, "100", 3)) {
- msg = "183 Session Progress";
+ if (!pvt) {
+ ao2_ref(data, -1); /* not rescheduling so drop ref. in this case the dialog has already dropped this ref */
+ return res;
}
- if (pvt->invitestate < INV_COMPLETED) {
- if (with_sdp) {
- transmit_response_with_sdp(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq, XMIT_UNRELIABLE);
+ ast_mutex_lock(&pvt->lock);
+ while (pvt->owner && ast_channel_trylock(pvt->owner)) {
+ ast_mutex_unlock(&pvt->lock);
+ sched_yield();
+ if ((pvt = data->pvt)) {
+ ast_mutex_lock(&pvt->lock);
} else {
- transmit_response(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq);
+ ao2_ref(data, -1);
+ return res;
}
- return PROVIS_KEEPALIVE_TIMEOUT;
}
- return 0;
+ if (data->sched_id == -1 || pvt->invitestate >= INV_COMPLETED) {
+ goto provisional_keepalive_cleanup;
+ }
+
+ if (!pvt->last_provisional || !strncasecmp(pvt->last_provisional, "100", 3)) {
+ msg = "183 Session Progress";
+ }
+
+ if (with_sdp) {
+ transmit_response_with_sdp(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq, XMIT_UNRELIABLE);
+ } else {
+ transmit_response(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq);
+ }
+
+ res = PROVIS_KEEPALIVE_TIMEOUT; /* reschedule the keepalive event */
+
+provisional_keepalive_cleanup:
+ if (!res) { /* not rescheduling, so drop ref */
+ data->sched_id = -1; /* if we don't re-schedule, make sure to remove the sched id */
+ ao2_ref(data, -1); /* release the scheduler's reference to this data */
+ }
+
+ if (pvt->owner) {
+ ast_channel_unlock(pvt->owner);
+ }
+ ast_mutex_unlock(&pvt->lock);
+
+ return res;
}
-static int send_provisional_keepalive(const void *data) {
- struct sip_pvt *pvt = (struct sip_pvt *) data;
+static int send_provisional_keepalive(const void *data)
+{
+ struct provisional_keepalive_data *d = (struct provisional_keepalive_data *) data;
- return send_provisional_keepalive_full(pvt, 0);
+ return send_provisional_keepalive_full(d, 0);
}
-static int send_provisional_keepalive_with_sdp(const void *data) {
- struct sip_pvt *pvt = (void *)data;
+static int send_provisional_keepalive_with_sdp(const void *data)
+{
+ struct provisional_keepalive_data *d = (struct provisional_keepalive_data *) data;
+
+ return send_provisional_keepalive_full(d, 1);
+}
+
+static void *unref_provisional_keepalive(struct provisional_keepalive_data *data)
+{
+ if (data) {
+ data->sched_id = -1;
+ data->pvt = NULL;
+ ao2_ref(data, -1);
+ }
+ return NULL;
+}
- return send_provisional_keepalive_full(pvt, 1);
+static void remove_provisional_keepalive_sched(struct sip_pvt *pvt)
+{
+ int res;
+ if (!pvt->provisional_keepalive_data) {
+ return;
+ }
+ res = AST_SCHED_DEL(sched, pvt->provisional_keepalive_data->sched_id);
+ /* If we could not remove this item. remove pvt's reference this data and mark it for removal
+ * for the next time the scheduler uses it. The scheduler has it's own ref to this data
+ * and will detect it should not reschedule the event since the sched_id is -1 and pvt == NULL */
+ if (res == -1) {
+ pvt->provisional_keepalive_data = unref_provisional_keepalive(pvt->provisional_keepalive_data);
+ }
}
static void update_provisional_keepalive(struct sip_pvt *pvt, int with_sdp)
{
- AST_SCHED_DEL(sched, pvt->provisional_keepalive_sched_id);
+ remove_provisional_keepalive_sched(pvt);
+
+ if (!pvt->provisional_keepalive_data) {
+ if (!(pvt->provisional_keepalive_data = ao2_alloc(sizeof(*pvt->provisional_keepalive_data), NULL))) {
+ return; /* alloc error, can not recover */
+ }
+ pvt->provisional_keepalive_data->sched_id = -1;
+ pvt->provisional_keepalive_data->pvt = pvt;
+ }
+
+ /* give the scheduler a ref */
+ ao2_ref(pvt->provisional_keepalive_data, +1);
- pvt->provisional_keepalive_sched_id = ast_sched_add(sched, PROVIS_KEEPALIVE_TIMEOUT,
- with_sdp ? send_provisional_keepalive_with_sdp : send_provisional_keepalive, pvt);
+ /* schedule the provisional keepalive */
+ pvt->provisional_keepalive_data->sched_id = ast_sched_add(sched,
+ PROVIS_KEEPALIVE_TIMEOUT,
+ with_sdp ? send_provisional_keepalive_with_sdp : send_provisional_keepalive,
+ pvt->provisional_keepalive_data);
+
+ /* if schedule was unsuccessful, remove the scheduler's ref */
+ if (pvt->provisional_keepalive_data->sched_id == -1) {
+ ao2_ref(pvt->provisional_keepalive_data, -1);
+ }
}
/*! \brief Transmit response on SIP request*/
@@ -2399,7 +2486,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty
/* If we are sending a final response to an INVITE, stop retransmitting provisional responses */
if (p->initreq.method == SIP_INVITE && reliable == XMIT_CRITICAL) {
- AST_SCHED_DEL(sched, p->provisional_keepalive_sched_id);
+ remove_provisional_keepalive_sched(p);
}
res = (reliable) ?
@@ -3297,7 +3384,13 @@ static int __sip_destroy(struct sip_pvt *p, int lockowner)
AST_SCHED_DEL(sched, p->waitid);
AST_SCHED_DEL(sched, p->autokillid);
AST_SCHED_DEL(sched, p->request_queue_sched_id);
- AST_SCHED_DEL(sched, p->provisional_keepalive_sched_id);
+
+ remove_provisional_keepalive_sched(p);
+ if (p->provisional_keepalive_data) {
+ ast_mutex_lock(&p->lock);
+ p->provisional_keepalive_data = unref_provisional_keepalive(p->provisional_keepalive_data);
+ ast_mutex_unlock(&p->lock);
+ }
if (p->rtp) {
ast_rtp_destroy(p->rtp);
@@ -3783,7 +3876,7 @@ static int sip_hangup(struct ast_channel *ast)
}
} else { /* Incoming call, not up */
const char *res;
- AST_SCHED_DEL(sched, p->provisional_keepalive_sched_id);
+ remove_provisional_keepalive_sched(p);
if (p->hangupcause && (res = hangup_cause2sip(p->hangupcause)))
transmit_response_reliable(p, res, &p->initreq);
else
@@ -4681,7 +4774,6 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
p->waitid = -1;
p->autokillid = -1;
p->request_queue_sched_id = -1;
- p->provisional_keepalive_sched_id = -1;
p->subscribed = NONE;
p->stateid = -1;
p->prefs = default_prefs; /* Set default codecs for this call */
@@ -18824,6 +18916,8 @@ static int reload_config(enum channelreloadreason reason)
ast_log(LOG_WARNING, "Unable to set SIP TOS to %s\n", ast_tos2str(global_tos_sip));
}
}
+ } else if (setsockopt(sipsock, IPPROTO_IP, IP_TOS, &global_tos_sip, sizeof(global_tos_sip))) {
+ ast_log(LOG_WARNING, "Unable to set SIP TOS to %s\n", ast_tos2str(global_tos_sip));
}
ast_mutex_unlock(&netlock);
diff --git a/configs/say.conf.sample b/configs/say.conf.sample
index 5971d756c..25c369862 100644
--- a/configs/say.conf.sample
+++ b/configs/say.conf.sample
@@ -101,16 +101,25 @@
_[n]um:X00 => num:${SAY:0:1}, digits/hundred
_[n]um:XXX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:X000 => num:${SAY:0:1}, digits/thousand
_[n]um:XXXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
_[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}
+ _[n]um:X000000 => num:${SAY:0:1}, digits/million
_[n]um:XXXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/million
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/million, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/million
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/million, num:${SAY:3}
+ _[n]um:X000000000 => num:${SAY:0:1}, digits/billion
_[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}
+ _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion
_[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}
+ _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion
_[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}
; enumeration
@@ -118,7 +127,8 @@
_e[n]um:1X => digits/h-${SAY}
_e[n]um:[2-9]0 => digits/h-${SAY}
_e[n]um:[2-9][1-9] => num:${SAY:0:1}0, digits/h-${SAY:1}
- _e[n]um:[1-9]XX => num:${SAY:0:1}, digits/hundred, enum:${SAY:1}
+ _e[n]um:[1-9]00 => num:${SAY:0:1}, digits/h-hundred
+ _e[n]um:[1-9]XX => num:${SAY:0:1}, digits/h-hundred, enum:${SAY:1}
[en_GB](date-base,digit-base,en-base)
_[n]um:XXX => num:${SAY:0:1}, digits/hundred, vm-and, num:${SAY:1}
@@ -134,16 +144,31 @@
_[n]um:[2-9]00 => num:${SAY:0:1}, digits/hundred
_[n]um:[2-9]XX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:1000 => digits/thousand
_[n]um:1XXX => digits/thousand, num:${SAY:1}
+ _[n]um:[2-9]000 => num:${SAY:0:1}, digits/thousands
_[n]um:[2-9]XXX => num:${SAY:0:1}, digits/thousands, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousands
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousands, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousands
_[n]um:XXXXXX => num:${SAY:0:3}, digits/thousands, num:${SAY:3}
+ _[n]um:1000000 => num:${SAY:0:1}, digits/million
_[n]um:1XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:[2-9]000000 => num:${SAY:0:1}, digits/millions
_[n]um:[2-9]XXXXXX => num:${SAY:0:1}, digits/millions, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/millions
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}
+ _[n]um:X000000000 => num:${SAY:0:1}, digits/billion
+ _[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}
+ _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion
+ _[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}
+ _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion
+ _[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}
+
_datetime::. => date:AdBY 'digits/at' IMp:${SAY}
_date::. => date:AdBY:${SAY}
_time::. => date:IMp:${SAY}
@@ -163,14 +188,23 @@
_[n]um:1XX => digits/ein, digits/hundred, num:${SAY:1}
_[n]um:[2-9]00 => digits/${SAY:0:1}, digits/hundred
_[n]um:[2-9]XX => digits/${SAY:0:1}, digits/hundred, num:${SAY:1}
+
+ _[n]um:1000 => digits/ein, digits/thousand
_[n]um:1XXX => digits/ein, digits/thousand, num:${SAY:1}
+ _[n]um:[2-9]000 => digits/${SAY:0:1}, digits/thousand
_[n]um:[2-9]XXX => digits/${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
- _[n]um:X00XXX => digits/${SAY:0:1}, digits/hundred, digits/thousand, num:${SAY:3}
- _[n]um:XXXXXX => digits/${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
+ _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:1}
+
+ _[n]um:1000000 => digits/eine, digits/million
_[n]um:1XXXXXX => digits/eine, digits/million, num:${SAY:1}
+ _[n]um:[2-9]000000 => digits/${SAY:0:1}, digits/millions
_[n]um:[2-9]XXXXXX => digits/${SAY:0:1}, digits/millions, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/millions
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}
_datetime::. => date:AdBY 'digits/at' IMp:${SAY}
@@ -192,14 +226,22 @@
_[n]um:[2-9]00 => num:${SAY:0:1}, digits/hundred
_[n]um:[2-9]XX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:1000 => digits/thousand
_[n]um:1XXX => digits/thousand, num:${SAY:1}
+ _[n]um:[2-9]000 => num:${SAY:0:1}, digits/thousand
_[n]um:[2-9]XXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
_[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}
+ _[n]um:1000000 => num:${SAY:0:1}, digits/million
_[n]um:1XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:[2-9]000000 => num:${SAY:0:1}, digits/million
_[n]um:[2-9]XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/million
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/million, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/million
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/million, num:${SAY:3}
_datetime::. => date:AdBY 'digits/at' H 'hours' M 'perc':${SAY}
@@ -209,3 +251,51 @@
_pho[n]e:XXXX => num:${SAY:0:2}, num:${SAY:2:2}
_pho[n]e:0[1-9]XXXXXXXX => num:${SAY:0:1}, num:${SAY:1:1}, num:${SAY:2:2}, num:${SAY:4:2}, num:${SAY:6:2}, num:${SAY:8:2}
_pho[n]e:. => digit:${SAY}
+
+[da](date-base,digit-base)
+ _[n]um:0. => num:${SAY:1}
+ _[n]um:X => digits/${SAY}
+ _[n]um:1X => digits/${SAY}
+ _[n]um:[2-9]0 => digits/${SAY}
+ _[n]um:[2-9][1-9] => digits/${SAY:1}-and, digits/${SAY:0:1}0
+ _[n]um:100 => digits/1N, digits/hundred
+ _[n]um:1XX => digits/1N, digits/hundred, num:${SAY:1}
+ _[n]um:[2-9]00 => digits/${SAY:0:1}, digits/hundred
+ _[n]um:[2-9]XX => digits/${SAY:0:1}, digits/hundred, num:${SAY:1}
+
+ _[n]um:1000 => digits/1N, digits/thousand
+ _[n]um:1XXX => digits/1N, digits/thousand, num:${SAY:1}
+ _[n]um:[2-9]000 => digits/${SAY:0:1}, digits/thousand
+ _[n]um:[2-9]XXX => digits/${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
+ _[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
+ _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}
+
+ _[n]um:X000000 => digits/${SAY:0:1}, digits/million
+ _[n]um:XXXXXXX => digits/${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/millions
+ _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions
+ _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}
+
+ _[n]um:X000000000 => num:${SAY:0:1}, digits/billion
+ _[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}
+ _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion
+ _[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}
+ _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion
+ _[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}
+
+ _datetime::. => date:AdBY 'digits/at' kM:${SAY}
+ _date::. => date:AdBY:${SAY}
+ _time::. => date:HM:${SAY}
+
+ ; enumeration
+ _e[n]um:X => digits/h-${SAY}
+ _e[n]um:1X => digits/h-${SAY}
+ _e[n]um:[2-9]0 => digits/h-${SAY}
+ _e[n]um:[2-9][1-9] => digits/${SAY:1}-and, digits/h-${SAY:0:1}0
+ _e[n]um:100 => digits/1N, digits/h-hundred
+ _e[n]um:1XX => digits/1N, digits/h-hundred, enum:${SAY:1}
+ _e[n]um:[2-9]00 => num:${SAY:0:1}, digits/h-hundred
+ _e[n]um:[2-9]XX => num:${SAY:0:1}, digits/h-hundred, enum:${SAY:1}
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index 9a420f768..deb40781e 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -91,6 +91,19 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;vmexten=voicemail ; dialplan extension to reach mailbox sets the
; Message-Account in the MWI notify message
; defaults to "asterisk"
+
+; Codec negotiation
+;
+; When Asterisk is receiving a call, the codec will initially be set to the
+; first codec in the allowed codecs defined for the user receiving the call
+; that the caller also indicates that it supports. But, after the caller
+; starts sending RTP, Asterisk will switch to using whatever codec the caller
+; is sending.
+;
+; When Asterisk is placing a call, the codec used will be the first codec in
+; the allowed codecs that the callee indicates that it supports. Asterisk will
+; *not* switch to whatever codec the callee is sending.
+;
;disallow=all ; First disallow all codecs
;allow=ulaw ; Allow codecs in order of preference
;allow=ilbc ; see doc/rtp-packetization for framing options
diff --git a/contrib/scripts/astcli b/contrib/scripts/astcli
new file mode 100755
index 000000000..0ea245f14
--- /dev/null
+++ b/contrib/scripts/astcli
@@ -0,0 +1,167 @@
+#!/usr/bin/perl -w
+
+use strict;
+use IO::Socket;
+use Getopt::Long;
+
+# Created by: David Van Ginneken
+# Bird's the Word Technologies
+# davevg@btwtech.com
+#
+# And distributed under the terms of the GPL
+#
+my ($user, $pw, $host, $port, $interactive, $save) = (undef, undef, 'localhost', 5038, 0, 0);
+my $EOL = "\r\n"; # Standard End of Line
+my @commands;
+process_credentials('/etc/astcli.conf');
+process_credentials("$ENV{HOME}/.astcli") if defined $ENV{HOME};
+GetOptions("username=s" => \$user, "secret=s" => \$pw, "host=s" => \$host, "port=s" => \$port, "readline" => \$interactive, "write" => \$save);
+
+$|++; # Auto Flush Output
+my $action = join(" ", @ARGV);
+
+&usage if (!defined $user || !defined $pw);
+my $tc = new IO::Socket::INET(
+ PeerAddr => $host,
+ PeerPort => $port,
+ Timeout => 30,
+ Proto => 'tcp'
+) or die "Could not connect to Host: $host on port $port\n";
+if (my $error = login()) {
+ print STDERR $error;
+ exit 1;
+};
+
+if ($save) {
+ if (-d $ENV{HOME}) {
+ open DEFAULT, ">$ENV{HOME}/.astcli";
+ print DEFAULT "username=$user\n" if $user;
+ print DEFAULT "password=$pw\n" if $pw;
+ print DEFAULT "hostname=$host\n" if $host;
+ print DEFAULT "portno=$port\n" if $port;
+ close DEFAULT;
+ }
+}
+
+# Send a single command to the manager connection handle (global $tc).
+# Assumes things always work well :-)
+sub send_command($) {
+ my $command = shift;
+ $tc->send('Action: Command' . $EOL);
+ $tc->send("Command: $command" . $EOL);
+ $tc->send($EOL);
+ my $response = '';
+ while (<$tc>) {
+ if ($_ =~ /--END COMMAND--/) {
+ $_ =~ s/--END COMMAND--\s*//;
+ $response .= $_;
+ last;
+ }
+ $response .= $_;
+ }
+ $response =~ s/Privilege: Command$EOL//;
+ $response =~ s/Response: Follows$EOL//;
+ return $response;
+}
+
+sub login {
+ my ($response, $message);
+ $tc->send("Action: Login" . $EOL);
+ $tc->send("Username: $user" . $EOL);
+ $tc->send("Secret: $pw" . $EOL);
+ $tc->send("Events: off" . $EOL);
+ $tc->send($EOL);
+ while (<$tc>) {
+ last if $_ eq $EOL;
+ $_ =~ s/$EOL//g;
+ ($response) = $_ =~ /^Response: (.*?)$/ if $_ =~ /^Response:/;
+ ($message) = $_ =~ /^Message: (.*?)$/ if $_ =~ /^Message:/;
+ }
+ return 0 if $response eq 'Success';
+ return $message;
+}
+
+sub logoff {
+ my ($response, $message);
+ $tc->send("Action: Logoff" . $EOL . $EOL);
+ return 1;
+}
+
+# If the user asked to send commands from standard input:
+if ($action eq '-' || !defined $action || $action eq '') {
+ if ($interactive) {
+ eval { require Term::ReadLine;};
+ $interactive = scalar($@) ? 0 : 1;
+ print STDERR "Falling back to standard mode, Unable to load Term::Readline for readline mode\n" unless $interactive;
+ }
+ if ($interactive) {
+ my $term = new Term::ReadLine 'Command Line Interface';
+ my $prompt = "$host*CLI> ";
+ my $attribs = $term->Attribs;
+ $attribs->{completion_function} = \&tab_completion;
+ while (defined($_ = $term->readline($prompt))) {
+ (logoff() and exit) if $_ =~ /exit|quit/; # Give them a way to exit the "terminal"
+ print send_command($_) if $_ !~ m/^\s*$/;
+ }
+ } else {
+ while (<>) {
+ chomp;
+ (logoff() and exit) if $_ =~ /exit|quit/; # If someone accidentally ends up here, let them exit
+ print send_command($_);
+ }
+ }
+ exit 0;
+}
+
+# Otherwise just send the command:
+print send_command($action);
+
+# parses a configuration file into the global $user and $pw.
+sub process_credentials {
+ # Process the credentials found..
+ my $file = shift;
+ # silently fail if we can't read the file:
+ return unless (-r $file);
+ open (my $fh, "<$file") or return;
+ while (<$fh>) {
+ chomp;
+ (undef,$user) = split(/[,=]/, $_) if $_ =~ /user(name)?[,=]/i;
+ (undef,$pw) = split(/[,=]/, $_) if $_ =~ /(secret|passw(or)?d|pwd?)[,=]/i;
+ (undef,$host) = split(/[,=]/, $_) if $_ =~ /host(name)?[,=]/i;
+ (undef,$port) = split(/[,=]/, $_) if $_ =~ /port(num|no)?[,=]/i;
+ }
+ close ($fh);
+}
+
+sub usage {
+ print STDERR "astcli [<options>] [<cli-command>|-]\n";
+ print STDERR " -u <name> - Connect as username <name>\n";
+ print STDERR " -s <pw> - Connect with secret <pw>\n";
+ print STDERR " -h <host> - Connect to host <host> [localhost]\n";
+ print STDERR " -p <port> - Connect on TCP port <port> [5038]\n";
+ print STDERR " -r - Start a readline session for interactivity\n";
+ print STDERR " -w - Save connection options in a configuration file\n";
+ print STDERR " You may specify the command as '-' to take commands from stdin.\n";
+ exit;
+}
+
+sub tab_completion {
+ my ($word, $buffer, $offset) = @_;
+ my %items;
+ my $lastword = '';
+ if ($word eq '') {
+ $buffer =~ m/(\S+)\s?$/;
+ $lastword = $1;
+ #print STDERR "\n\nlastword=\"$lastword\"\n";
+ }
+
+ my $res = send_command("_command matchesarray \"$buffer\" \"$word\"");
+ foreach my $item (split /\s+/, $res) {
+ $items{$item}++ unless ($item eq '_EOF_' or $item eq '' or $item eq $lastword);
+ }
+
+ #print STDERR "\nword=\"$word\" buffer=\"$buffer\" offset=\"$offset\" res=\"$res\"\n";
+
+ return sort keys %items;
+}
+
diff --git a/main/channel.c b/main/channel.c
index 1d28515c6..bd64c50fa 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -4032,6 +4032,7 @@ int ast_do_masquerade(struct ast_channel *original)
void *t_pvt;
struct ast_callerid tmpcid;
struct ast_channel *clone = original->masq;
+ struct ast_channel *bridged;
struct ast_cdr *cdr;
int rformat = original->readformat;
int wformat = original->writeformat;
@@ -4298,6 +4299,15 @@ int ast_do_masquerade(struct ast_channel *original)
pthread_kill(original->blocker, SIGURG);
if (option_debug)
ast_log(LOG_DEBUG, "Done Masquerading %s (%d)\n", original->name, original->_state);
+
+ if ((bridged = ast_bridged_channel(original))) {
+ ast_channel_lock(bridged);
+ ast_indicate(bridged, AST_CONTROL_SRCCHANGE);
+ ast_channel_unlock(bridged);
+ }
+
+ ast_indicate(original, AST_CONTROL_SRCCHANGE);
+
return 0;
}
@@ -4679,8 +4689,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
ast_set_flag(c0, AST_FLAG_END_DTMF_ONLY);
/* Before we enter in and bridge these two together tell them both the source of audio has changed */
- ast_indicate(c0, AST_CONTROL_SRCUPDATE);
- ast_indicate(c1, AST_CONTROL_SRCUPDATE);
+ ast_indicate(c0, AST_CONTROL_SRCCHANGE);
+ ast_indicate(c1, AST_CONTROL_SRCCHANGE);
for (/* ever */;;) {
struct timeval now = { 0, };
diff --git a/main/pbx.c b/main/pbx.c
index 1ad2d2e1d..e88bdb879 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -492,7 +492,11 @@ static struct pbx_builtin {
};
static struct ast_context *contexts;
-AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
+/*!\brief Lock for the ast_context list
+ * This lock MUST be recursive, or a deadlock on reload may result. See
+ * https://issues.asterisk.org/view.php?id=17643
+ */
+AST_MUTEX_DEFINE_STATIC(conlock);
static AST_LIST_HEAD_STATIC(apps, ast_app);
@@ -6193,22 +6197,22 @@ int load_pbx(void)
*/
int ast_lock_contexts()
{
- return ast_rwlock_wrlock(&conlock);
+ return ast_mutex_lock(&conlock);
}
int ast_rdlock_contexts(void)
{
- return ast_rwlock_rdlock(&conlock);
+ return ast_mutex_lock(&conlock);
}
int ast_wrlock_contexts(void)
{
- return ast_rwlock_wrlock(&conlock);
+ return ast_mutex_lock(&conlock);
}
int ast_unlock_contexts()
{
- return ast_rwlock_unlock(&conlock);
+ return ast_mutex_unlock(&conlock);
}
/*
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index 9c51b130c..0bcdf7811 100644
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -2475,13 +2475,14 @@ static int pbx_load_module(void)
static int load_module(void)
{
- if (pbx_load_module())
- return AST_MODULE_LOAD_DECLINE;
-
+
if (static_config && !write_protect_config)
ast_cli_register(&cli_dialplan_save);
ast_cli_register_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
+ if (pbx_load_module())
+ return AST_MODULE_LOAD_DECLINE;
+
return 0;
}