aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2009-04-03 22:41:46 +0000
committermmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2009-04-03 22:41:46 +0000
commitf00656db9ebcc7db98c0e3a3abf9a83791d8bcdb (patch)
tree2e466f746a2e29094d6dcc3c6f2577f4dd85f4c0
parent531f260b1278edd05dcabd04422b6a072e75f821 (diff)
This commit introduces COLP/CONP and Redirecting party information into Asterisk.
The channel drivers which have been most heavily tested with these enhancements are chan_sip and chan_misdn. Further work is being done to add Q.SIG support and will be introduced in a later commit. chan_skinny has code added to it here, but according to user pj, the support on chan_skinny is not working as of now. This will be fixed in a later commit. A special thanks goes out to bugtracker user gareth for getting the ball rolling and providing the initial support for this work. Without his initial work on this, this would not have been nearly as painless as it was. This functionality has been tested by Digium's product quality department, as well as a customer site running thousands of calls every day. In addition, many many many many bugtracker users have tested this, too. (closes issue #8824) Reported by: gareth Review: http://reviewboard.digium.com/r/201 git-svn-id: http://svn.digium.com/svn/asterisk/trunk@186525 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--CHANGES42
-rw-r--r--apps/app_dial.c190
-rw-r--r--apps/app_directed_pickup.c13
-rw-r--r--apps/app_queue.c186
-rw-r--r--channels/chan_agent.c3
-rw-r--r--channels/chan_dahdi.c32
-rw-r--r--channels/chan_h323.c12
-rw-r--r--channels/chan_iax2.c108
-rw-r--r--channels/chan_local.c75
-rw-r--r--channels/chan_mgcp.c2
-rw-r--r--channels/chan_misdn.c1553
-rw-r--r--channels/chan_phone.c8
-rw-r--r--channels/chan_sip.c1111
-rw-r--r--channels/chan_skinny.c54
-rw-r--r--channels/chan_unistim.c12
-rw-r--r--channels/misdn/chan_misdn_config.h10
-rw-r--r--channels/misdn/isdn_lib.c196
-rw-r--r--channels/misdn/isdn_lib.h202
-rw-r--r--channels/misdn/isdn_lib_intern.h1
-rw-r--r--channels/misdn/isdn_msg_parser.c395
-rw-r--r--channels/misdn_config.c113
-rw-r--r--configs/misdn.conf.sample194
-rw-r--r--configs/sip.conf.sample8
-rw-r--r--include/asterisk/callerid.h237
-rw-r--r--include/asterisk/channel.h1021
-rw-r--r--include/asterisk/frame.h98
-rw-r--r--main/callerid.c235
-rw-r--r--main/channel.c936
-rw-r--r--main/dial.c19
-rw-r--r--main/features.c61
-rw-r--r--main/stun.c2
-rw-r--r--res/res_rtp_asterisk.c2
32 files changed, 5462 insertions, 1669 deletions
diff --git a/CHANGES b/CHANGES
index 88ae3f515..a9205024f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,7 +7,6 @@
=== and the other UPGRADE files for older releases.
===
======================================================================
-
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 1.6.2 to Asterisk 1.6.3 -------------
------------------------------------------------------------------------------
@@ -23,10 +22,47 @@ Applications
present, those values are sent immediatly upon receiving a PROGRESS message
regardless if the call has been answered or not.
-Functions
----------
+Dialplan Functions
+------------------
+ * Added new dialplan functions CONNECTEDLINE and REDIRECTING which permits
+ setting various connected line and redirecting party information.
* The CHANNEL() function now supports the "name" option.
+Queue changes
+-------------
+ * A new option, 'I' has been added to both app_queue and app_dial.
+ By setting this option, Asterisk will not update the caller with
+ connected line changes or redirecting party changes when they occur.
+
+mISDN channel driver (chan_misdn) changes
+----------------------------------------
+ * Added display_connected parameter to misdn.conf to put a display string
+ in the CONNECT message containing the connected name and/or number if
+ the presentation setting permits it.
+ * Added display_setup parameter to misdn.conf to put a display string
+ in the SETUP message containing the caller name and/or number if the
+ presentation setting permits it.
+ * Made misdn.conf parameters localdialplan and cpndialplan take a -1 to
+ indicate the dialplan settings are to be obtained from the asterisk
+ channel.
+ * Made misdn.conf parameter callerid accept the "name" <number> format
+ used by the rest of the system.
+ * Made use the nationalprefix and internationalprefix misdn.conf
+ parameters to prefix any received number from the ISDN link if that
+ number has the corresponding Type-Of-Number.
+ * Added the following new parameters: unknownprefix, netspecificprefix,
+ subscriberprefix, and abbreviatedprefix in misdn.conf to prefix any
+ received number from the ISDN link if that number has the corresponding
+ Type-Of-Number.
+
+
+SIP channel driver (chan_sip) changes
+-------------------------------------------
+ * The sendrpid parameter has been expanded to include the options
+ 'rpid' and 'pai'. Setting sendrpid to 'rpid' will cause Remote-Party-ID
+ header to be sent (equivalent to setting sendrpid=yes) and setting
+ sendrpid to 'pai' will cause P-Asserted-Identity header to be sent.
+
Asterisk Manager Interface
--------------------------
* The Hangup action now accepts a Cause header which may be used to
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 96bb57081..ee3953fcc 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -157,6 +157,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<option name="i">
<para>Asterisk will ignore any forwarding requests it may receive on this dial attempt.</para>
</option>
+ <option name="I">
+ <para>Asterisk will ignore any connected line update requests or redirecting party update
+ requests it may receiveon this dial attempt.</para>
+ </option>
<option name="k">
<para>Allow the called party to enable parking of the call by sending
the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
@@ -382,7 +386,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
This application will report normal termination if the originating channel
hangs up, or if the call is bridged and either of the parties in the bridge
ends the call.</para>
-
<para>If the <variable>OUTBOUND_GROUP</variable> variable is set, all peer channels created by this
application will be put into that group (as in Set(GROUP()=...).
If the <variable>OUTBOUND_GROUP_ONCE</variable> variable is set, all peer channels created by this
@@ -464,12 +467,13 @@ enum {
OPT_GO_ON = (1 << 5),
OPT_CALLEE_HANGUP = (1 << 6),
OPT_CALLER_HANGUP = (1 << 7),
+ OPT_ORIGINAL_CLID = (1 << 8),
OPT_DURATION_LIMIT = (1 << 9),
OPT_MUSICBACK = (1 << 10),
OPT_CALLEE_MACRO = (1 << 11),
OPT_SCREEN_NOINTRO = (1 << 12),
- OPT_SCREEN_NOCLID = (1 << 13),
- OPT_ORIGINAL_CLID = (1 << 14),
+ OPT_SCREEN_NOCALLERID = (1 << 13),
+ OPT_IGNORE_CONNECTEDLINE = (1 << 14),
OPT_SCREENING = (1 << 15),
OPT_PRIVACY = (1 << 16),
OPT_RINGBACK = (1 << 17),
@@ -490,9 +494,10 @@ enum {
#define DIAL_STILLGOING (1 << 31)
#define DIAL_NOFORWARDHTML ((uint64_t)1 << 32) /* flags are now 64 bits, so keep it up! */
-#define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 33)
-#define OPT_PEER_H ((uint64_t)1 << 34)
-#define OPT_CALLEE_GO_ON ((uint64_t)1 << 35)
+#define DIAL_NOCONNECTEDLINE ((uint64_t)1 << 33)
+#define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 34)
+#define OPT_PEER_H ((uint64_t)1 << 35)
+#define OPT_CALLEE_GO_ON ((uint64_t)1 << 36)
enum {
OPT_ARG_ANNOUNCE = 0,
@@ -524,13 +529,14 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
AST_APP_OPTION('H', OPT_CALLER_HANGUP),
AST_APP_OPTION('i', OPT_IGNORE_FORWARDING),
+ AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
AST_APP_OPTION('k', OPT_CALLEE_PARK),
AST_APP_OPTION('K', OPT_CALLER_PARK),
AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
AST_APP_OPTION('n', OPT_SCREEN_NOINTRO),
- AST_APP_OPTION('N', OPT_SCREEN_NOCLID),
+ AST_APP_OPTION('N', OPT_SCREEN_NOCALLERID),
AST_APP_OPTION('o', OPT_ORIGINAL_CLID),
AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE),
AST_APP_OPTION('p', OPT_SCREENING),
@@ -558,6 +564,7 @@ struct chanlist {
struct chanlist *next;
struct ast_channel *chan;
uint64_t flags;
+ struct ast_party_connected_line connected;
};
static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode);
@@ -654,7 +661,6 @@ static int onedigit_goto(struct ast_channel *chan, const char *context, char ext
return 0;
}
-
static const char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
{
const char *context = S_OR(chan->macrocontext, chan->context);
@@ -702,6 +708,8 @@ static void do_forward(struct chanlist *o,
struct ast_channel *original = o->chan;
struct ast_channel *c = o->chan; /* the winner */
struct ast_channel *in = num->chan; /* the input channel */
+ struct ast_party_redirecting *apr = &o->chan->redirecting;
+ struct ast_party_connected_line *apc = &o->chan->connected;
char *stuff;
char *tech;
int cause;
@@ -742,30 +750,38 @@ static void do_forward(struct chanlist *o,
handle_cause(cause, num);
ast_hangup(original);
} else {
- char *new_cid_num, *new_cid_name;
- struct ast_channel *src;
-
if (single) {
ast_rtp_instance_early_bridge_make_compatible(c, in);
}
+
+ c->cdrflags = in->cdrflags;
+
+ ast_channel_set_redirecting(c, apr);
+ ast_channel_lock(c);
+ while (ast_channel_trylock(in)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(c);
+ }
+ S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(original->cid.cid_rdnis, S_OR(in->macroexten, in->exten))));
+
+ c->cid.cid_tns = in->cid.cid_tns;
+
if (ast_test_flag64(o, OPT_FORCECLID)) {
- new_cid_num = ast_strdup(S_OR(in->macroexten, in->exten));
- new_cid_name = NULL; /* XXX no name ? */
- src = c; /* XXX possible bug in previous code, which used 'winner' ? it may have changed */
+ S_REPLACE(c->cid.cid_num, ast_strdupa(S_OR(in->macroexten, in->exten)));
+ S_REPLACE(c->cid.cid_name, NULL);
+ ast_string_field_set(c, accountcode, c->accountcode);
} else {
- new_cid_num = ast_strdup(in->cid.cid_num);
- new_cid_name = ast_strdup(in->cid.cid_name);
- src = in;
+ ast_party_caller_copy(&c->cid, &in->cid);
+ ast_string_field_set(c, accountcode, in->accountcode);
}
- ast_string_field_set(c, accountcode, src->accountcode);
- c->cdrflags = src->cdrflags;
- S_REPLACE(c->cid.cid_num, new_cid_num);
- S_REPLACE(c->cid.cid_name, new_cid_name);
+ ast_party_connected_line_copy(&c->connected, apc);
+
+ S_REPLACE(in->cid.cid_rdnis, ast_strdup(c->cid.cid_rdnis));
+ ast_channel_unlock(in);
+ ast_channel_unlock(c);
+ ast_channel_update_redirecting(in, apr);
+
+ ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
- if (in->cid.cid_ani) { /* XXX or maybe unconditional ? */
- S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani));
- }
- S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten)));
if (ast_call(c, tmpchan, 0)) {
ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
ast_clear_flag64(o, DIAL_STILLGOING);
@@ -775,7 +791,6 @@ static void do_forward(struct chanlist *o,
num->nochan++;
} else {
senddialevent(in, c, stuff);
- /* After calling, set callerid to extension */
if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
char cidname[AST_MAX_EXTENSION] = "";
ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL);
@@ -808,16 +823,28 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
int orig = *to;
struct ast_channel *peer = NULL;
/* single is set if only one destination is enabled */
- int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
+ int single = outgoing && !outgoing->next;
#ifdef HAVE_EPOLL
struct chanlist *epollo;
#endif
+ struct ast_party_connected_line connected_caller;
struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1);
if (single) {
/* Turn off hold music, etc */
- ast_deactivate_generator(in);
+ if (!ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK))
+ ast_deactivate_generator(in);
+
/* If we are calling a single channel, make them compatible for in-band tone purpose */
ast_channel_make_compatible(outgoing->chan, in);
+
+ if (!ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE) && !ast_test_flag64(outgoing, DIAL_NOCONNECTEDLINE)) {
+ ast_channel_lock(outgoing->chan);
+ ast_connected_line_copy_from_caller(&connected_caller, &outgoing->chan->cid);
+ ast_channel_unlock(outgoing->chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
}
#ifdef HAVE_EPOLL
@@ -864,6 +891,18 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
if (!peer) {
ast_verb(3, "%s answered %s\n", c->name, in->name);
+ if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ if (o->connected.id.number) {
+ ast_channel_update_connected_line(in, &o->connected);
+ } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) {
+ ast_channel_lock(c);
+ ast_connected_line_copy_from_caller(&connected_caller, &c->cid);
+ ast_channel_unlock(c);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ }
peer = c;
ast_copy_flags64(peerflags, o,
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
@@ -902,6 +941,18 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
/* This is our guy if someone answered. */
if (!peer) {
ast_verb(3, "%s answered %s\n", c->name, in->name);
+ if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ if (o->connected.id.number) {
+ ast_channel_update_connected_line(in, &o->connected);
+ } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) {
+ ast_channel_lock(c);
+ ast_connected_line_copy_from_caller(&connected_caller, &c->cid);
+ ast_channel_unlock(c);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ }
peer = c;
if (peer->cdr) {
peer->cdr->answer = ast_tvnow();
@@ -970,6 +1021,29 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
ast_verb(3, "%s requested a source update, passing it to %s\n", c->name, in->name);
ast_indicate(in, AST_CONTROL_SRCUPDATE);
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ ast_verb(3, "Connected line update to %s prevented.\n", in->name);
+ } else if (!single) {
+ struct ast_party_connected_line connected;
+ ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", c->name, in->name);
+ ast_party_connected_line_set_init(&connected, &o->connected);
+ ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
+ ast_party_connected_line_set(&o->connected, &connected);
+ ast_party_connected_line_free(&connected);
+ } else {
+ ast_verb(3, "%s connected line has changed, passing it to %s\n", c->name, in->name);
+ ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+ }
+ break;
+ case AST_CONTROL_REDIRECTING:
+ if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+ ast_verb(3, "Redirecting update to %s prevented.\n", in->name);
+ } else {
+ ast_verb(3, "%s redirecting info has changed, passing it to %s\n", c->name, in->name);
+ ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+ }
+ break;
case AST_CONTROL_PROCEEDING:
ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name);
if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
@@ -1084,7 +1158,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
((f->subclass == AST_CONTROL_HOLD) ||
(f->subclass == AST_CONTROL_UNHOLD) ||
(f->subclass == AST_CONTROL_VIDUPDATE) ||
- (f->subclass == AST_CONTROL_SRCUPDATE))) {
+ (f->subclass == AST_CONTROL_SRCUPDATE) ||
+ (f->subclass == AST_CONTROL_CONNECTED_LINE) ||
+ (f->subclass == AST_CONTROL_REDIRECTING))) {
ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen);
}
@@ -1423,11 +1499,11 @@ static int setup_privacy_args(struct privacy_args *pa,
ast_copy_string(pa->privcid, l, sizeof(pa->privcid));
- if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCLID)) {
- /* if callerid is set and OPT_SCREEN_NOCLID is set also */
+ if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCALLERID)) {
+ /* if callerid is set and OPT_SCREEN_NOCALLERID is set also */
ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid);
pa->privdb_val = AST_PRIVACY_ALLOW;
- } else if (ast_test_flag64(opts, OPT_SCREEN_NOCLID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
+ } else if (ast_test_flag64(opts, OPT_SCREEN_NOCALLERID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val);
}
@@ -1637,7 +1713,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
outbound_group = ast_strdupa(outbound_group);
}
ast_channel_unlock(chan);
- ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING);
+ ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE);
/* loop through the list of dial destinations */
rest = args.peers;
@@ -1674,6 +1750,14 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
ast_channel_lock(chan);
datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
+ /* If the incoming channel has previously had connected line information
+ * set on it (perhaps through the CONNECTED_LINE dialplan function) then
+ * seed the calllist's connected line information with this previously
+ * acquired info
+ */
+ if (chan->connected.id.number) {
+ ast_party_connected_line_copy(&tmp->connected, &chan->connected);
+ }
ast_channel_unlock(chan);
if (datastore)
@@ -1746,6 +1830,10 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
}
pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
+ ast_channel_lock(tc);
+ while (ast_channel_trylock(chan)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(tc);
+ }
/* Setup outgoing SDP to match incoming one */
if (!outgoing && !rest) {
ast_rtp_instance_early_bridge_make_compatible(tc, chan);
@@ -1759,20 +1847,31 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
tc->data = "(Outgoing Line)";
memset(&tc->whentohangup, 0, sizeof(tc->whentohangup));
- S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num));
- S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name));
- S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
- S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+ /* If the new channel has no callerid, try to guess what it should be */
+ if (ast_strlen_zero(tc->cid.cid_num)) {
+ if (!ast_strlen_zero(chan->connected.id.number)) {
+ ast_set_callerid(tc, chan->connected.id.number, chan->connected.id.name, chan->connected.ani);
+ } else if (!ast_strlen_zero(chan->cid.cid_dnid)) {
+ ast_set_callerid(tc, chan->cid.cid_dnid, NULL, NULL);
+ } else if (!ast_strlen_zero(S_OR(chan->macroexten, chan->exten))) {
+ ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), NULL, NULL);
+ }
+ ast_set_flag64(tmp, DIAL_NOCONNECTEDLINE);
+ }
+ ast_connected_line_copy_from_caller(&tc->connected, &chan->cid);
+
+ S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+ ast_party_redirecting_copy(&tc->redirecting, &chan->redirecting);
+
+ tc->cid.cid_tns = chan->cid.cid_tns;
+
ast_string_field_set(tc, accountcode, chan->accountcode);
tc->cdrflags = chan->cdrflags;
if (ast_strlen_zero(tc->musicclass))
ast_string_field_set(tc, musicclass, chan->musicclass);
- /* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */
- tc->cid.cid_pres = chan->cid.cid_pres;
- tc->cid.cid_ton = chan->cid.cid_ton;
- tc->cid.cid_tns = chan->cid.cid_tns;
- tc->cid.cid_ani2 = chan->cid.cid_ani2;
+
+ /* Pass ADSI CPE and transfer capability */
tc->adsicpe = chan->adsicpe;
tc->transfercapability = chan->transfercapability;
@@ -1809,6 +1908,8 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
if (tc->hangupcause) {
chan->hangupcause = tc->hangupcause;
}
+ ast_channel_unlock(chan);
+ ast_channel_unlock(tc);
ast_hangup(tc);
tc = NULL;
ast_free(tmp);
@@ -1816,8 +1917,11 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
} else {
senddialevent(chan, tc, numsubst);
ast_verb(3, "Called %s\n", numsubst);
- if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID))
+ if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL);
+ }
+ ast_channel_unlock(chan);
+ ast_channel_unlock(tc);
}
/* Put them in the list of outgoing thingies... We're ready now.
XXX If we're forcibly removed, these outgoing calls won't get
diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c
index 605d11faf..cfba99fce 100644
--- a/apps/app_directed_pickup.c
+++ b/apps/app_directed_pickup.c
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/features.h"
+#include "asterisk/callerid.h"
#define PICKUPMARK "PICKUPMARK"
@@ -91,9 +92,21 @@ static const char *app2 = "PickupChan";
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
{
int res = 0;
+ struct ast_party_connected_line connected_caller;
ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
+ connected_caller = target->connected;
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(chan, &connected_caller);
+
+ ast_channel_lock(chan);
+ ast_connected_line_copy_from_caller(&connected_caller, &chan->cid);
+ ast_channel_unlock(chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(chan, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+
if ((res = ast_answer(chan))) {
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
return -1;
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 5726d4c5c..58b1c09ba 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -94,6 +94,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/strings.h"
#include "asterisk/global_datastores.h"
#include "asterisk/taskprocessor.h"
+#include "asterisk/callerid.h"
/*!
* \par Please read before modifying this file.
@@ -141,6 +142,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Ignore call forward requests from queue members and do nothing
when they are requested.</para>
</option>
+ <option name="I">
+ <para>Asterisk will ignore any connected line update requests or any redirecting party
+ update requests it may receive on this dial attempt.</para>
+ </option>
<option name="r">
<para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
</option>
@@ -625,6 +630,8 @@ struct callattempt {
time_t lastcall;
struct call_queue *lastqueue;
struct member *member;
+ unsigned int update_connectedline:1;
+ struct ast_party_connected_line connected;
};
@@ -2479,22 +2486,40 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
(*busies)++;
return 0;
}
-
+
+ ast_channel_lock(tmp->chan);
+ while (ast_channel_trylock(qe->chan)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
+ }
+
if (qe->cancel_answered_elsewhere) {
ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
}
tmp->chan->appl = "AppQueue";
tmp->chan->data = "(Outgoing Line)";
memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
- if (tmp->chan->cid.cid_num)
- ast_free(tmp->chan->cid.cid_num);
- tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
- if (tmp->chan->cid.cid_name)
- ast_free(tmp->chan->cid.cid_name);
- tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
- if (tmp->chan->cid.cid_ani)
- ast_free(tmp->chan->cid.cid_ani);
- tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
+
+ /* If the new channel has no callerid, try to guess what it should be */
+ if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
+ if (!ast_strlen_zero(qe->chan->connected.id.number)) {
+ ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
+ tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
+ } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
+ ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
+ } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
+ ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
+ }
+ tmp->update_connectedline = 0;
+ }
+
+ if (tmp->chan->cid.cid_rdnis)
+ ast_free(tmp->chan->cid.cid_rdnis);
+ tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis);
+ ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
+
+ tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
+
+ ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid);
/* Inherit specially named variables from parent channel */
ast_channel_inherit_variables(qe->chan, tmp->chan);
@@ -2503,7 +2528,6 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
tmp->chan->adsicpe = qe->chan->adsicpe;
/* Inherit context and extension */
- ast_channel_lock(qe->chan);
macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
@@ -2511,13 +2535,14 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
else
ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
- ast_channel_unlock(qe->chan);
/* Place the call, but don't wait on the answer */
if ((res = ast_call(tmp->chan, location, 0))) {
/* Again, keep going even if there's an error */
ast_debug(1, "ast call on peer returned %d\n", res);
ast_verb(3, "Couldn't call %s\n", tmp->interface);
+ ast_channel_unlock(tmp->chan);
+ ast_channel_unlock(qe->chan);
do_hang(tmp);
(*busies)++;
update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
@@ -2545,6 +2570,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
ast_verb(3, "Called %s\n", tmp->interface);
}
+ ast_channel_unlock(tmp->chan);
+ ast_channel_unlock(qe->chan);
update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
return 1;
@@ -2775,7 +2802,7 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member
* \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
* \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
*/
-static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
+static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline)
{
const char *queue = qe->parent->name;
struct callattempt *o, *start = NULL, *prev = NULL;
@@ -2795,6 +2822,12 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
#ifdef HAVE_EPOLL
struct callattempt *epollo;
#endif
+ struct ast_party_connected_line connected_caller;
+ char *inchan_name;
+
+ ast_channel_lock(qe->chan);
+ inchan_name = ast_strdupa(qe->chan->name);
+ ast_channel_unlock(qe->chan);
starttime = (long) time(NULL);
#ifdef HAVE_EPOLL
@@ -2845,9 +2878,28 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
}
winner = ast_waitfor_n(watchers, pos, to);
for (o = start; o; o = o->call_next) {
+ /* We go with a static buffer here instead of using ast_strdupa. Using
+ * ast_strdupa in a loop like this one can cause a stack overflow
+ */
+ char ochan_name[AST_CHANNEL_NAME];
+ ast_channel_lock(o->chan);
+ ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
+ ast_channel_unlock(o->chan);
if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
if (!peer) {
- ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
+ ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
+ if (update_connectedline) {
+ if (o->connected.id.number) {
+ ast_channel_update_connected_line(in, &o->connected);
+ } else if (o->update_connectedline) {
+ ast_channel_lock(o->chan);
+ ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
+ ast_channel_unlock(o->chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ }
peer = o;
}
} else if (o->chan && (o->chan == winner)) {
@@ -2856,12 +2908,15 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
ast_copy_string(membername, o->member->membername, sizeof(membername));
if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
- ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
+ ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
numnochan++;
do_hang(o);
winner = NULL;
continue;
} else if (!ast_strlen_zero(o->chan->call_forward)) {
+ struct ast_party_redirecting *apr = &o->chan->redirecting;
+ struct ast_party_connected_line *apc = &o->chan->connected;
+ struct ast_channel *original = o->chan;
char tmpchan[256];
char *stuff;
char *tech;
@@ -2876,7 +2931,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
tech = "Local";
}
/* Before processing channel, go ahead and check for forwarding */
- ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
+ ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
/* Setup parameters */
o->chan = ast_request(tech, in->nativeformats, stuff, &status);
if (!o->chan) {
@@ -2884,32 +2939,42 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
o->stillgoing = 0;
numnochan++;
} else {
+ ast_channel_lock(o->chan);
+ while (ast_channel_trylock(in)) {
+ CHANNEL_DEADLOCK_AVOIDANCE(o->chan);
+ }
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
- if (o->chan->cid.cid_num)
- ast_free(o->chan->cid.cid_num);
- o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
-
- if (o->chan->cid.cid_name)
- ast_free(o->chan->cid.cid_name);
- o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
ast_string_field_set(o->chan, accountcode, in->accountcode);
o->chan->cdrflags = in->cdrflags;
- if (in->cid.cid_ani) {
- if (o->chan->cid.cid_ani)
- ast_free(o->chan->cid.cid_ani);
- o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
- }
+ ast_channel_set_redirecting(o->chan, apr);
+
if (o->chan->cid.cid_rdnis)
ast_free(o->chan->cid.cid_rdnis);
- o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
+ o->chan->cid.cid_rdnis = ast_strdup(S_OR(original->cid.cid_rdnis,S_OR(in->macroexten, in->exten)));
+
+ o->chan->cid.cid_tns = in->cid.cid_tns;
+
+ ast_party_caller_copy(&o->chan->cid, &in->cid);
+ ast_party_connected_line_copy(&o->chan->connected, apc);
+
+ ast_channel_update_redirecting(in, apr);
+ if (in->cid.cid_rdnis) {
+ ast_free(in->cid.cid_rdnis);
+ }
+ in->cid.cid_rdnis = ast_strdup(o->chan->cid.cid_rdnis);
+
+ update_connectedline = 1;
+
if (ast_call(o->chan, tmpchan, 0)) {
ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
do_hang(o);
numnochan++;
}
+ ast_channel_unlock(in);
+ ast_channel_unlock(o->chan);
}
/* Hangup the original channel now, in case we needed it */
ast_hangup(winner);
@@ -2922,12 +2987,24 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
case AST_CONTROL_ANSWER:
/* This is our guy if someone answered. */
if (!peer) {
- ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
+ ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
+ if (update_connectedline) {
+ if (o->connected.id.number) {
+ ast_channel_update_connected_line(in, &o->connected);
+ } else if (o->update_connectedline) {
+ ast_channel_lock(o->chan);
+ ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
+ ast_channel_unlock(o->chan);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(in, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ }
peer = o;
}
break;
case AST_CONTROL_BUSY:
- ast_verb(3, "%s is busy\n", o->chan->name);
+ ast_verb(3, "%s is busy\n", ochan_name);
if (in->cdr)
ast_cdr_busy(in->cdr);
do_hang(o);
@@ -2942,7 +3019,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
numbusies++;
break;
case AST_CONTROL_CONGESTION:
- ast_verb(3, "%s is circuit-busy\n", o->chan->name);
+ ast_verb(3, "%s is circuit-busy\n", ochan_name);
if (in->cdr)
ast_cdr_busy(in->cdr);
endtime = (long) time(NULL);
@@ -2957,13 +3034,37 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
numbusies++;
break;
case AST_CONTROL_RINGING:
- ast_verb(3, "%s is ringing\n", o->chan->name);
+ ast_verb(3, "%s is ringing\n", ochan_name);
break;
case AST_CONTROL_OFFHOOK:
/* Ignore going off hook */
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ if (!update_connectedline) {
+ ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
+ } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
+ struct ast_party_connected_line connected;
+ ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
+ ast_party_connected_line_set_init(&connected, &o->connected);
+ ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
+ ast_party_connected_line_set(&o->connected, &connected);
+ ast_party_connected_line_free(&connected);
+ } else {
+ ast_verb(3, "%s connected line has changed, passing it to %s\n", ochan_name, inchan_name);
+ ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+ }
+ break;
+ case AST_CONTROL_REDIRECTING:
+ if (!update_connectedline) {
+ ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
+ } else {
+ ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
+ ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+ }
+ break;
default:
ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
+ break;
}
}
ast_frfree(f);
@@ -3517,6 +3618,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
char *p;
char vars[2048];
int forwardsallowed = 1;
+ int update_connectedline = 1;
int callcompletedinsl;
struct ao2_iterator memi;
struct ast_datastore *datastore, *transfer_ds;
@@ -3582,6 +3684,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
case 'i':
forwardsallowed = 0;
break;
+ case 'I':
+ update_connectedline = 0;
+ break;
case 'x':
ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
break;
@@ -3591,7 +3696,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
case 'C':
qe->cancel_answered_elsewhere = 1;
break;
-
}
/* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited.
@@ -3661,6 +3765,17 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
}
}
AST_LIST_UNLOCK(dialed_interfaces);
+
+ ast_channel_lock(qe->chan);
+ /* If any pre-existing connected line information exists on this
+ * channel, like from the CONNECTED_LINE dialplan function, use this
+ * to seed the connected line information. It may, of course, be updated
+ * during the call
+ */
+ if (qe->chan->connected.id.number) {
+ ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
+ }
+ ast_channel_unlock(qe->chan);
if (di) {
free(tmp);
@@ -3692,6 +3807,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
tmp->oldstatus = cur->status;
tmp->lastcall = cur->lastcall;
tmp->lastqueue = cur->lastqueue;
+ tmp->update_connectedline = 1;
ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
/* Special case: If we ring everyone, go ahead and ring them, otherwise
just calculate their metric for the appropriate strategy */
@@ -3732,7 +3848,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
ring_one(qe, outgoing, &numbusies);
if (use_weight)
ao2_unlock(queues);
- lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
+ lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
/* The ast_channel_datastore_remove() function could fail here if the
* datastore was moved to another channel during a masquerade. If this is
* the case, don't free the datastore here because later, when the channel
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index b15f7a04e..818f61935 100644
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -757,8 +757,7 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout)
time(&p->start);
/* Call on this agent */
ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
- ast_set_callerid(p->chan,
- ast->cid.cid_num, ast->cid.cid_name, NULL);
+ ast_channel_set_connected_line(p->chan, &ast->connected);
ast_channel_inherit_variables(ast, p->chan);
res = ast_call(p->chan, p->loginchan, 0);
CLEANUP(ast,p);
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index f520e32f7..f6d3fb9ad 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -3156,7 +3156,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
}
p->callwaitcas = 0;
if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
- p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p));
+ p->cidlen = ast_callerid_generate(p->cidspill, ast->connected.id.name, ast->connected.id.number, AST_LAW(p));
p->cidpos = 0;
send_callerid(p);
}
@@ -3197,12 +3197,12 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
} else {
/* Call waiting call */
p->callwaitrings = 0;
- if (ast->cid.cid_num)
- ast_copy_string(p->callwait_num, ast->cid.cid_num, sizeof(p->callwait_num));
+ if (ast->connected.id.number)
+ ast_copy_string(p->callwait_num, ast->connected.id.number, sizeof(p->callwait_num));
else
p->callwait_num[0] = '\0';
- if (ast->cid.cid_name)
- ast_copy_string(p->callwait_name, ast->cid.cid_name, sizeof(p->callwait_name));
+ if (ast->connected.id.name)
+ ast_copy_string(p->callwait_name, ast->connected.id.name, sizeof(p->callwait_name));
else
p->callwait_name[0] = '\0';
/* Call waiting tone instead */
@@ -3214,8 +3214,8 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
if (tone_zone_play_tone(p->subs[SUB_CALLWAIT].dfd, DAHDI_TONE_RINGTONE))
ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name);
}
- n = ast->cid.cid_name;
- l = ast->cid.cid_num;
+ n = ast->connected.id.name;
+ l = ast->connected.id.number;
if (l)
ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num));
else
@@ -3281,14 +3281,14 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
switch (mysig) {
case SIG_FEATD:
- l = ast->cid.cid_num;
+ l = ast->connected.id.number;
if (l)
snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c);
else
snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c);
break;
case SIG_FEATDMF:
- l = ast->cid.cid_num;
+ l = ast->connected.id.number;
if (l)
snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c);
else
@@ -3423,7 +3423,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
}
if (!p->hidecallerid) {
- l = ast->cid.cid_num;
+ l = ast->connected.id.number;
} else {
l = NULL;
}
@@ -3472,10 +3472,10 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
}
}
isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
- p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
- p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED );
+ p->use_callingpres ? cid_pres2ss7pres(ast->connected.id.number_presentation) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
+ p->use_callingpres ? cid_pres2ss7screen(ast->connected.id.number_presentation) : SS7_SCREENING_USER_PROVIDED );
- isup_set_oli(p->ss7call, ast->cid.cid_ani2);
+ isup_set_oli(p->ss7call, ast->connected.ani2);
isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
ast_channel_lock(ast);
@@ -3587,9 +3587,9 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
l = NULL;
n = NULL;
if (!p->hidecallerid) {
- l = ast->cid.cid_num;
+ l = ast->connected.id.number;
if (!p->hidecalleridname) {
- n = ast->cid.cid_name;
+ n = ast->connected.id.name;
}
}
@@ -3803,7 +3803,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
}
}
pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
- p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
+ p->use_callingpres ? ast->connected.id.number_presentation : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) {
if (!strcasecmp(rr_str, "UNKNOWN"))
redirect_reason = 0;
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index c3e074d14..0445497b4 100644
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -606,18 +606,18 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
/* make sure null terminated */
called_addr[sizeof(called_addr) - 1] = '\0';
- if (c->cid.cid_num)
- ast_copy_string(pvt->options.cid_num, c->cid.cid_num, sizeof(pvt->options.cid_num));
+ if (c->connected.id.number)
+ ast_copy_string(pvt->options.cid_num, c->connected.id.number, sizeof(pvt->options.cid_num));
- if (c->cid.cid_name)
- ast_copy_string(pvt->options.cid_name, c->cid.cid_name, sizeof(pvt->options.cid_name));
+ if (c->connected.id.name)
+ ast_copy_string(pvt->options.cid_name, c->connected.id.name, sizeof(pvt->options.cid_name));
if (c->cid.cid_rdnis) {
ast_copy_string(pvt->options.cid_rdnis, c->cid.cid_rdnis, sizeof(pvt->options.cid_rdnis));
}
- pvt->options.presentation = c->cid.cid_pres;
- pvt->options.type_of_number = c->cid.cid_ton;
+ pvt->options.presentation = c->connected.id.number_presentation;
+ pvt->options.type_of_number = c->connected.id.number_type;
if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) {
if (!strcasecmp(addr, "UNKNOWN"))
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 860e1d614..d594498f6 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -380,7 +380,9 @@ enum iax2_flags {
them before sending voice or anything else*/
IAX_ALLOWFWDOWNLOAD = (1 << 26), /*!< Allow the FWDOWNL command? */
IAX_IMMEDIATE = (1 << 27), /*!< Allow immediate off-hook to extension s */
- IAX_FORCE_ENCRYPT = (1 << 28), /*!< Forces call encryption, if encryption not possible hangup */
+ IAX_SENDCONNECTEDLINE = (1 << 28), /*!< Allow sending of connected line updates */
+ IAX_RECVCONNECTEDLINE = (1 << 29), /*!< Allow receiving of connected line updates */
+ IAX_FORCE_ENCRYPT = (1 << 30), /*!< Forces call encryption, if encryption not possible hangup */
};
static int global_rtautoclear = 120;
@@ -1976,7 +1978,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
iaxs[x]->amaflags = amaflags;
- ast_copy_flags(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT);
+ ast_copy_flags(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
ast_string_field_set(iaxs[x], accountcode, accountcode);
ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);
ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);
@@ -3601,6 +3603,8 @@ struct create_addr_info {
char outkey[80];
char timezone[80];
char prefs[32];
+ char cid_num[80];
+ char cid_name[80];
char context[AST_MAX_CONTEXT];
char peercontext[AST_MAX_CONTEXT];
char mohinterpret[MAX_MUSICCLASS];
@@ -3644,7 +3648,7 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka
if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0)))
goto return_unref;
- ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT);
+ ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
cai->maxtime = peer->maxms;
cai->capability = peer->capability;
cai->encmethods = peer->encmethods;
@@ -3662,6 +3666,8 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka
ast_copy_string(cai->username, peer->username, sizeof(cai->username));
ast_copy_string(cai->timezone, peer->zonetag, sizeof(cai->timezone));
ast_copy_string(cai->outkey, peer->outkey, sizeof(cai->outkey));
+ ast_copy_string(cai->cid_num, peer->cid_num, sizeof(cai->cid_num));
+ ast_copy_string(cai->cid_name, peer->cid_name, sizeof(cai->cid_name));
ast_copy_string(cai->mohinterpret, peer->mohinterpret, sizeof(cai->mohinterpret));
ast_copy_string(cai->mohsuggest, peer->mohsuggest, sizeof(cai->mohsuggest));
if (ast_strlen_zero(peer->dbsecret)) {
@@ -3870,8 +3876,8 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
if (pds.port)
sin.sin_port = htons(atoi(pds.port));
- l = c->cid.cid_num;
- n = c->cid.cid_name;
+ l = c->connected.id.number;
+ n = c->connected.id.name;
/* Now build request */
memset(&ied, 0, sizeof(ied));
@@ -3888,21 +3894,21 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
if (l) {
iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
- iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
+ iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->connected.id.number_presentation);
} else {
if (n)
- iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
+ iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->connected.id.number_presentation);
else
iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, AST_PRES_NUMBER_NOT_AVAILABLE);
}
- iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->cid.cid_ton);
+ iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->connected.id.number_type);
iax_ie_append_short(&ied, IAX_IE_CALLINGTNS, c->cid.cid_tns);
if (n)
iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, n);
- if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->cid.cid_ani)
- iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->cid.cid_ani);
+ if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->connected.ani)
+ iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->connected.ani);
if (!ast_strlen_zero(c->language))
iax_ie_append_str(&ied, IAX_IE_LANGUAGE, c->language);
@@ -4398,6 +4404,11 @@ static int iax2_indicate(struct ast_channel *c, int condition, const void *data,
ast_moh_stop(c);
goto done;
}
+ break;
+ case AST_CONTROL_CONNECTED_LINE:
+ if (!ast_test_flag(pvt, IAX_SENDCONNECTEDLINE))
+ goto done;
+ break;
}
res = send_command(pvt, AST_FRAME_CONTROL, condition, 0, data, datalen, -1);
@@ -6381,7 +6392,7 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
iaxs[callno]->amaflags = user->amaflags;
if (!ast_strlen_zero(user->language))
ast_string_field_set(iaxs[callno], language, user->language);
- ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
+ ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
/* Keep this check last */
if (!ast_strlen_zero(user->dbsecret)) {
char *family, *key=NULL;
@@ -9954,6 +9965,31 @@ immediatedial:
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
+ /* Don't allow connected line updates unless we are configured to */
+ if (f.frametype == AST_FRAME_CONTROL && f.subclass == AST_CONTROL_CONNECTED_LINE) {
+ struct ast_party_connected_line connected;
+
+ if (!ast_test_flag(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) {
+ ast_mutex_unlock(&iaxsl[fr->callno]);
+ return 1;
+ }
+
+ /* Initialize defaults */
+ ast_party_connected_line_init(&connected);
+ connected.id.number_presentation = iaxs[fr->callno]->calling_pres;
+
+ if (!ast_connected_line_parse_data(f.data.ptr, f.datalen, &connected)) {
+ ast_string_field_set(iaxs[fr->callno], cid_num, connected.id.number);
+ ast_string_field_set(iaxs[fr->callno], cid_name, connected.id.name);
+ iaxs[fr->callno]->calling_pres = connected.id.number_presentation;
+
+ if (iaxs[fr->callno]->owner) {
+ ast_set_callerid(iaxs[fr->callno]->owner, S_OR(connected.id.number, ""), S_OR(connected.id.name, ""), NULL);
+ iaxs[fr->callno]->owner->cid.cid_pres = connected.id.number_presentation;
+ }
+ }
+ ast_party_connected_line_free(&connected);
+ }
/* Common things */
f.src = "IAX2";
f.mallocd = 0;
@@ -10449,7 +10485,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data
memset(&cai, 0, sizeof(cai));
cai.capability = iax2_capability;
- ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
+ ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
/* Populate our address from the given */
if (create_addr(pds.peer, NULL, &sin, &cai)) {
@@ -10468,7 +10504,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data
}
/* If this is a trunk, update it now */
- ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
+ ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
if (ast_test_flag(&cai, IAX_TRUNK)) {
int new_callno;
if ((new_callno = make_trunk(callno, 1)) != -1)
@@ -10731,7 +10767,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
if (peer) {
if (firstpass) {
- ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT);
+ ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
peer->encmethods = iax2_encryption;
peer->adsi = adsi;
ast_string_field_set(peer,secret,"");
@@ -10904,6 +10940,18 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
ast_string_field_set(peer, zonetag, v->value);
} else if (!strcasecmp(v->name, "adsi")) {
peer->adsi = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "connectedline")) {
+ if (ast_true(v->value)) {
+ ast_set_flag(peer, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+ } else if (!strcasecmp(v->value, "send")) {
+ ast_clear_flag(peer, IAX_RECVCONNECTEDLINE);
+ ast_set_flag(peer, IAX_SENDCONNECTEDLINE);
+ } else if (!strcasecmp(v->value, "receive")) {
+ ast_clear_flag(peer, IAX_SENDCONNECTEDLINE);
+ ast_set_flag(peer, IAX_RECVCONNECTEDLINE);
+ } else {
+ ast_clear_flag(peer, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+ }
}/* else if (strcasecmp(v->name,"type")) */
/* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
v = v->next;
@@ -11002,7 +11050,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
user->adsi = adsi;
ast_string_field_set(user, name, name);
ast_string_field_set(user, language, language);
- ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_FORCE_ENCRYPT);
+ ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
ast_clear_flag(user, IAX_HASCALLERID);
ast_string_field_set(user, cid_name, "");
ast_string_field_set(user, cid_num, "");
@@ -11147,6 +11195,18 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
user->maxauthreq = 0;
} else if (!strcasecmp(v->name, "adsi")) {
user->adsi = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "connectedline")) {
+ if (ast_true(v->value)) {
+ ast_set_flag(user, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+ } else if (!strcasecmp(v->value, "send")) {
+ ast_clear_flag(user, IAX_RECVCONNECTEDLINE);
+ ast_set_flag(user, IAX_SENDCONNECTEDLINE);
+ } else if (!strcasecmp(v->value, "receive")) {
+ ast_clear_flag(user, IAX_SENDCONNECTEDLINE);
+ ast_set_flag(user, IAX_RECVCONNECTEDLINE);
+ } else {
+ ast_clear_flag(user, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+ }
}/* else if (strcasecmp(v->name,"type")) */
/* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
v = v->next;
@@ -11262,10 +11322,8 @@ static void set_config_destroy(void)
trunkmaxsize = MAX_TRUNKDATA;
amaflags = 0;
delayreject = 0;
- ast_clear_flag((&globalflags), IAX_NOTRANSFER);
- ast_clear_flag((&globalflags), IAX_TRANSFERMEDIA);
- ast_clear_flag((&globalflags), IAX_USEJITTERBUF);
- ast_clear_flag((&globalflags), IAX_FORCEJITTERBUF);
+ ast_clear_flag((&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF |
+ IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
delete_users();
}
@@ -11569,6 +11627,18 @@ static int set_config(char *config_file, int reload)
adsi = ast_true(v->value);
} else if (!strcasecmp(v->name, "srvlookup")) {
srvlookup = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "connectedline")) {
+ if (ast_true(v->value)) {
+ ast_set_flag((&globalflags), IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+ } else if (!strcasecmp(v->value, "send")) {
+ ast_clear_flag((&globalflags), IAX_RECVCONNECTEDLINE);
+ ast_set_flag((&globalflags), IAX_SENDCONNECTEDLINE);
+ } else if (!strcasecmp(v->value, "receive")) {
+ ast_clear_flag((&globalflags), IAX_SENDCONNECTEDLINE);
+ ast_set_flag((&globalflags), IAX_RECVCONNECTEDLINE);
+ } else {
+ ast_clear_flag((&globalflags), IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+ }
} /*else if (strcasecmp(v->name,"type")) */
/* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
v = v->next;
diff --git a/channels/chan_local.c b/channels/chan_local.c
index e426e10fa..509e69b10 100644
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -406,6 +406,37 @@ static int local_indicate(struct ast_channel *ast, int condition, const void *da
ast_moh_start(ast, data, NULL);
} else if (condition == AST_CONTROL_UNHOLD) {
ast_moh_stop(ast);
+ } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
+ struct ast_channel *this_channel;
+ struct ast_channel *the_other_channel;
+ /* A connected line update frame may only contain a partial amount of data, such
+ * as just a source, or just a ton, and not the full amount of information. However,
+ * the collected information is all stored in the outgoing channel's connectedline
+ * structure, so when receiving a connected line update on an outgoing local channel,
+ * we need to transmit the collected connected line information instead of whatever
+ * happens to be in this control frame. The same applies for redirecting information, which
+ * is why it is handled here as well.*/
+ isoutbound = IS_OUTBOUND(ast, p);
+ if (isoutbound) {
+ this_channel = p->chan;
+ the_other_channel = p->owner;
+ } else {
+ this_channel = p->owner;
+ the_other_channel = p->chan;
+ }
+ if (the_other_channel) {
+ unsigned char frame_data[1024];
+ if (condition == AST_CONTROL_CONNECTED_LINE) {
+ f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected);
+ } else {
+ f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting);
+ }
+ f.subclass = condition;
+ f.data.ptr = frame_data;
+ if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) {
+ ast_mutex_unlock(&p->lock);
+ }
+ }
} else {
/* Queue up a frame representing the indication as a control frame */
ast_mutex_lock(&p->lock);
@@ -509,22 +540,45 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
if (!p)
return -1;
-
- ast_mutex_lock(&p->lock);
+
+ /* If you value your sanity, please don't look at this code */
+start_over:
+ while (ast_channel_trylock(p->chan)) {
+ ast_channel_unlock(p->owner);
+ usleep(1);
+ ast_channel_lock(p->owner);
+ }
+
+ /* p->owner and p->chan are locked now. Let's get p locked */
+ if (ast_mutex_trylock(&p->lock)) {
+ /* @#$&$@ */
+ ast_channel_unlock(p->chan);
+ ast_channel_unlock(p->owner);
+ usleep(1);
+ ast_channel_lock(p->owner);
+ goto start_over;
+ }
/*
* Note that cid_num and cid_name aren't passed in the ast_channel_alloc
* call, so it's done here instead.
+ *
+ * All these failure points just return -1. The individual strings will
+ * be cleared when we destroy the channel.
*/
- p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
- p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
- p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
- p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
- p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
- p->chan->cid.cid_pres = p->owner->cid.cid_pres;
- p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
- p->chan->cid.cid_ton = p->owner->cid.cid_ton;
+ if (!(p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis))) {
+ return -1;
+ }
+ ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting);
+
+ if (!(p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid))) {
+ return -1;
+ }
p->chan->cid.cid_tns = p->owner->cid.cid_tns;
+
+ ast_connected_line_copy_to_caller(&p->chan->cid, &p->owner->connected);
+ ast_connected_line_copy_from_caller(&p->chan->connected, &p->owner->cid);
+
ast_string_field_set(p->chan, language, p->owner->language);
ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
@@ -560,6 +614,7 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
ast_set_flag(p, LOCAL_LAUNCHED_PBX);
ast_mutex_unlock(&p->lock);
+ ast_channel_unlock(p->chan);
return res;
}
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index cad9d9497..83a2e61b4 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -915,7 +915,7 @@ static int mgcp_call(struct ast_channel *ast, char *dest, int timeout)
transmit_modify_request(sub->next);
}
- transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name);
+ transmit_notify_request_with_callerid(sub, tone, ast->connected.id.number, ast->connected.id.name);
ast_setstate(ast, AST_STATE_RINGING);
if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 599bcef82..52b8f1d9f 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <signal.h>
#include <sys/file.h>
#include <semaphore.h>
+#include <ctype.h>
#include "asterisk/channel.h"
#include "asterisk/config.h"
@@ -88,8 +89,6 @@ struct misdn_jb{
ast_mutex_t mutexjb;
};
-
-
/*! \brief allocates the jb-structure and initialize the elements */
struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
@@ -340,10 +339,6 @@ struct chan_list {
*/
char mohinterpret[MAX_MUSICCLASS];
-#if 0
- int zero_read_cnt; /* Not used */
-#endif
-
/*!
* \brief Number of outgoing audio frames dropped since last debug gripe message.
*/
@@ -401,18 +396,10 @@ struct chan_list {
*/
struct timeval overlap_tv;
-#if 0
- struct chan_list *peer; /* Not used */
-#endif
-
/*!
* \brief Next channel call record in the list.
*/
struct chan_list *next;
-#if 0
- struct chan_list *prev; /* Not used */
- struct chan_list *first; /* Not used */
-#endif
};
@@ -423,13 +410,14 @@ void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_
void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
-static struct robin_list {
+struct robin_list {
char *group;
int port;
int channel;
struct robin_list *next;
struct robin_list *prev;
-} *robin = NULL;
+};
+static struct robin_list *robin = NULL;
static inline void free_robin_list_r(struct robin_list *r)
@@ -538,7 +526,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data);
int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
-void debug_numplan(int port, int numplan, char *type);
+void debug_numtype(int port, int numtype, char *type);
int add_out_calls(int port);
int add_in_calls(int port);
@@ -580,6 +568,534 @@ static struct chan_list * get_chan_by_ast_name(char *name)
return NULL;
}
+/*!
+ * \internal
+ * \brief Convert the mISDN type of number code to a string
+ *
+ * \param number_type mISDN type of number code.
+ *
+ * \return The mISDN type of number code as a string
+ */
+static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type)
+{
+ const char *str;
+
+ switch (number_type) {
+ default:
+ case NUMTYPE_UNKNOWN:
+ str = "Unknown";
+ break;
+
+ case NUMTYPE_INTERNATIONAL:
+ str = "International";
+ break;
+
+ case NUMTYPE_NATIONAL:
+ str = "National";
+ break;
+
+ case NUMTYPE_NETWORK_SPECIFIC:
+ str = "Network Specific";
+ break;
+
+ case NUMTYPE_SUBSCRIBER:
+ str = "Subscriber";
+ break;
+
+ case NUMTYPE_ABBREVIATED:
+ str = "Abbreviated";
+ break;
+ }
+
+ return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN type of number code to Asterisk type of number code
+ *
+ * \param number_type mISDN type of number code.
+ *
+ * \return Asterisk type of number code
+ */
+static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type)
+{
+ int ast_number_type;
+
+ switch (number_type) {
+ default:
+ case NUMTYPE_UNKNOWN:
+ ast_number_type = NUMTYPE_UNKNOWN << 4;
+ break;
+
+ case NUMTYPE_INTERNATIONAL:
+ ast_number_type = NUMTYPE_INTERNATIONAL << 4;
+ break;
+
+ case NUMTYPE_NATIONAL:
+ ast_number_type = NUMTYPE_NATIONAL << 4;
+ break;
+
+ case NUMTYPE_NETWORK_SPECIFIC:
+ ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4;
+ break;
+
+ case NUMTYPE_SUBSCRIBER:
+ ast_number_type = NUMTYPE_SUBSCRIBER << 4;
+ break;
+
+ case NUMTYPE_ABBREVIATED:
+ ast_number_type = NUMTYPE_ABBREVIATED << 4;
+ break;
+ }
+
+ return ast_number_type;
+}
+
+/*!
+ * \internal
+ * \brief Convert the Asterisk type of number code to mISDN type of number code
+ *
+ * \param ast_number_type Asterisk type of number code.
+ *
+ * \return mISDN type of number code
+ */
+static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type)
+{
+ enum mISDN_NUMBER_TYPE number_type;
+
+ switch ((ast_number_type >> 4) & 0x07) {
+ default:
+ case NUMTYPE_UNKNOWN:
+ number_type = NUMTYPE_UNKNOWN;
+ break;
+
+ case NUMTYPE_INTERNATIONAL:
+ number_type = NUMTYPE_INTERNATIONAL;
+ break;
+
+ case NUMTYPE_NATIONAL:
+ number_type = NUMTYPE_NATIONAL;
+ break;
+
+ case NUMTYPE_NETWORK_SPECIFIC:
+ number_type = NUMTYPE_NETWORK_SPECIFIC;
+ break;
+
+ case NUMTYPE_SUBSCRIBER:
+ number_type = NUMTYPE_SUBSCRIBER;
+ break;
+
+ case NUMTYPE_ABBREVIATED:
+ number_type = NUMTYPE_ABBREVIATED;
+ break;
+ }
+
+ return number_type;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN numbering plan code to a string
+ *
+ * \param number_plan mISDN numbering plan code.
+ *
+ * \return The mISDN numbering plan code as a string
+ */
+static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan)
+{
+ const char *str;
+
+ switch (number_plan) {
+ default:
+ case NUMPLAN_UNKNOWN:
+ str = "Unknown";
+ break;
+
+ case NUMPLAN_ISDN:
+ str = "ISDN";
+ break;
+
+ case NUMPLAN_DATA:
+ str = "Data";
+ break;
+
+ case NUMPLAN_TELEX:
+ str = "Telex";
+ break;
+
+ case NUMPLAN_NATIONAL:
+ str = "National";
+ break;
+
+ case NUMPLAN_PRIVATE:
+ str = "Private";
+ break;
+ }
+
+ return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN numbering plan code to Asterisk numbering plan code
+ *
+ * \param number_plan mISDN numbering plan code.
+ *
+ * \return Asterisk numbering plan code
+ */
+static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan)
+{
+ int ast_number_plan;
+
+ switch (number_plan) {
+ default:
+ case NUMPLAN_UNKNOWN:
+ ast_number_plan = NUMPLAN_UNKNOWN;
+ break;
+
+ case NUMPLAN_ISDN:
+ ast_number_plan = NUMPLAN_ISDN;
+ break;
+
+ case NUMPLAN_DATA:
+ ast_number_plan = NUMPLAN_DATA;
+ break;
+
+ case NUMPLAN_TELEX:
+ ast_number_plan = NUMPLAN_TELEX;
+ break;
+
+ case NUMPLAN_NATIONAL:
+ ast_number_plan = NUMPLAN_NATIONAL;
+ break;
+
+ case NUMPLAN_PRIVATE:
+ ast_number_plan = NUMPLAN_PRIVATE;
+ break;
+ }
+
+ return ast_number_plan;
+}
+
+/*!
+ * \internal
+ * \brief Convert the Asterisk numbering plan code to mISDN numbering plan code
+ *
+ * \param ast_number_plan Asterisk numbering plan code.
+ *
+ * \return mISDN numbering plan code
+ */
+static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan)
+{
+ enum mISDN_NUMBER_PLAN number_plan;
+
+ switch (ast_number_plan & 0x0F) {
+ default:
+ case NUMPLAN_UNKNOWN:
+ number_plan = NUMPLAN_UNKNOWN;
+ break;
+
+ case NUMPLAN_ISDN:
+ number_plan = NUMPLAN_ISDN;
+ break;
+
+ case NUMPLAN_DATA:
+ number_plan = NUMPLAN_DATA;
+ break;
+
+ case NUMPLAN_TELEX:
+ number_plan = NUMPLAN_TELEX;
+ break;
+
+ case NUMPLAN_NATIONAL:
+ number_plan = NUMPLAN_NATIONAL;
+ break;
+
+ case NUMPLAN_PRIVATE:
+ number_plan = NUMPLAN_PRIVATE;
+ break;
+ }
+
+ return number_plan;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN presentation code to a string
+ *
+ * \param presentation mISDN number presentation restriction code.
+ *
+ * \return The mISDN presentation code as a string
+ */
+static const char *misdn_to_str_pres(int presentation)
+{
+ const char *str;
+
+ switch (presentation) {
+ case 0:
+ str = "Allowed";
+ break;
+
+ case 1:
+ str = "Restricted";
+ break;
+
+ case 2:
+ str = "Unavailable";
+ break;
+
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN presentation code to Asterisk presentation code
+ *
+ * \param presentation mISDN number presentation restriction code.
+ *
+ * \return Asterisk presentation code
+ */
+static int misdn_to_ast_pres(int presentation)
+{
+ switch (presentation) {
+ default:
+ case 0:
+ presentation = AST_PRES_ALLOWED;
+ break;
+
+ case 1:
+ presentation = AST_PRES_RESTRICTED;
+ break;
+
+ case 2:
+ presentation = AST_PRES_UNAVAILABLE;
+ break;
+ }
+
+ return presentation;
+}
+
+/*!
+ * \internal
+ * \brief Convert the Asterisk presentation code to mISDN presentation code
+ *
+ * \param presentation Asterisk number presentation restriction code.
+ *
+ * \return mISDN presentation code
+ */
+static int ast_to_misdn_pres(int presentation)
+{
+ switch (presentation & AST_PRES_RESTRICTION) {
+ default:
+ case AST_PRES_ALLOWED:
+ presentation = 0;
+ break;
+
+ case AST_PRES_RESTRICTED:
+ presentation = 1;
+ break;
+
+ case AST_PRES_UNAVAILABLE:
+ presentation = 2;
+ break;
+ }
+
+ return presentation;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN screening code to a string
+ *
+ * \param screening mISDN number screening code.
+ *
+ * \return The mISDN screening code as a string
+ */
+static const char *misdn_to_str_screen(int screening)
+{
+ const char *str;
+
+ switch (screening) {
+ case 0:
+ str = "Unscreened";
+ break;
+
+ case 1:
+ str = "Passed Screen";
+ break;
+
+ case 2:
+ str = "Failed Screen";
+ break;
+
+ case 3:
+ str = "Network Number";
+ break;
+
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN screening code to Asterisk screening code
+ *
+ * \param screening mISDN number screening code.
+ *
+ * \return Asterisk screening code
+ */
+static int misdn_to_ast_screen(int screening)
+{
+ switch (screening) {
+ default:
+ case 0:
+ screening = AST_PRES_USER_NUMBER_UNSCREENED;
+ break;
+
+ case 1:
+ screening = AST_PRES_USER_NUMBER_PASSED_SCREEN;
+ break;
+
+ case 2:
+ screening = AST_PRES_USER_NUMBER_FAILED_SCREEN;
+ break;
+
+ case 3:
+ screening = AST_PRES_NETWORK_NUMBER;
+ break;
+ }
+
+ return screening;
+}
+
+/*!
+ * \internal
+ * \brief Convert the Asterisk screening code to mISDN screening code
+ *
+ * \param screening Asterisk number screening code.
+ *
+ * \return mISDN screening code
+ */
+static int ast_to_misdn_screen(int screening)
+{
+ switch (screening & AST_PRES_NUMBER_TYPE) {
+ default:
+ case AST_PRES_USER_NUMBER_UNSCREENED:
+ screening = 0;
+ break;
+
+ case AST_PRES_USER_NUMBER_PASSED_SCREEN:
+ screening = 1;
+ break;
+
+ case AST_PRES_USER_NUMBER_FAILED_SCREEN:
+ screening = 2;
+ break;
+
+ case AST_PRES_NETWORK_NUMBER:
+ screening = 3;
+ break;
+ }
+
+ return screening;
+}
+
+/*!
+ * \internal
+ * \brief Convert Asterisk redirecting reason to mISDN redirecting reason code.
+ *
+ * \param ast Asterisk redirecting reason code.
+ *
+ * \return mISDN reason code
+ */
+static enum mISDN_REDIRECTING_REASON ast_to_misdn_reason(const enum AST_REDIRECTING_REASON ast)
+{
+ unsigned index;
+
+ static const struct misdn_reasons {
+ enum AST_REDIRECTING_REASON ast;
+ enum mISDN_REDIRECTING_REASON q931;
+ } misdn_reason_table[] = {
+ /* *INDENT-OFF* */
+ { AST_REDIRECTING_REASON_UNKNOWN, mISDN_REDIRECTING_REASON_UNKNOWN },
+ { AST_REDIRECTING_REASON_USER_BUSY, mISDN_REDIRECTING_REASON_CALL_FWD_BUSY },
+ { AST_REDIRECTING_REASON_NO_ANSWER, mISDN_REDIRECTING_REASON_NO_REPLY },
+ { AST_REDIRECTING_REASON_UNAVAILABLE, mISDN_REDIRECTING_REASON_NO_REPLY },
+ { AST_REDIRECTING_REASON_UNCONDITIONAL, mISDN_REDIRECTING_REASON_CALL_FWD },
+ { AST_REDIRECTING_REASON_TIME_OF_DAY, mISDN_REDIRECTING_REASON_UNKNOWN },
+ { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN },
+ { AST_REDIRECTING_REASON_DEFLECTION, mISDN_REDIRECTING_REASON_DEFLECTION },
+ { AST_REDIRECTING_REASON_FOLLOW_ME, mISDN_REDIRECTING_REASON_UNKNOWN },
+ { AST_REDIRECTING_REASON_OUT_OF_ORDER, mISDN_REDIRECTING_REASON_OUT_OF_ORDER },
+ { AST_REDIRECTING_REASON_AWAY, mISDN_REDIRECTING_REASON_UNKNOWN },
+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, mISDN_REDIRECTING_REASON_CALL_FWD_DTE }
+ /* *INDENT-ON* */
+ };
+
+ for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) {
+ if (misdn_reason_table[index].ast == ast) {
+ return misdn_reason_table[index].q931;
+ }
+ }
+ return mISDN_REDIRECTING_REASON_UNKNOWN;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN redirecting reason to Asterisk redirecting reason code
+ *
+ * \param q931 mISDN redirecting reason code.
+ *
+ * \return Asterisk redirecting reason code
+ */
+static enum AST_REDIRECTING_REASON misdn_to_ast_reason(const enum mISDN_REDIRECTING_REASON q931)
+{
+ enum AST_REDIRECTING_REASON ast;
+
+ switch (q931) {
+ default:
+ case mISDN_REDIRECTING_REASON_UNKNOWN:
+ ast = AST_REDIRECTING_REASON_UNKNOWN;
+ break;
+
+ case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
+ ast = AST_REDIRECTING_REASON_USER_BUSY;
+ break;
+
+ case mISDN_REDIRECTING_REASON_NO_REPLY:
+ ast = AST_REDIRECTING_REASON_NO_ANSWER;
+ break;
+
+ case mISDN_REDIRECTING_REASON_DEFLECTION:
+ ast = AST_REDIRECTING_REASON_DEFLECTION;
+ break;
+
+ case mISDN_REDIRECTING_REASON_OUT_OF_ORDER:
+ ast = AST_REDIRECTING_REASON_OUT_OF_ORDER;
+ break;
+
+ case mISDN_REDIRECTING_REASON_CALL_FWD_DTE:
+ ast = AST_REDIRECTING_REASON_CALL_FWD_DTE;
+ break;
+
+ case mISDN_REDIRECTING_REASON_CALL_FWD:
+ ast = AST_REDIRECTING_REASON_UNCONDITIONAL;
+ break;
+ }
+
+ return ast;
+}
+
struct allowed_bearers {
@@ -590,7 +1106,7 @@ struct allowed_bearers {
};
/* *INDENT-OFF* */
-static const struct allowed_bearers allowed_bearers_array[]= {
+static const struct allowed_bearers allowed_bearers_array[] = {
/* Name, Displayable Name Bearer Capability, Deprecated */
{ "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 },
{ "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 },
@@ -609,7 +1125,7 @@ static const char *bearer2str(int cap)
if (allowed_bearers_array[index].cap == cap) {
return allowed_bearers_array[index].display;
}
- } /* end for */
+ }
return "Unknown Bearer";
}
@@ -682,6 +1198,95 @@ static void print_bearer(struct misdn_bchannel *bc)
}
}
+/*!
+ * \internal
+ * \brief Prefix a string to another string in place.
+ *
+ * \param str_prefix String to prefix to the main string.
+ * \param str_main String to get the prefix added to it.
+ * \param size Buffer size of the main string (Includes null terminator).
+ *
+ * \note The str_main buffer size must be greater than one.
+ *
+ * \return Nothing
+ */
+static void misdn_prefix_string(const char *str_prefix, char *str_main, size_t size)
+{
+ size_t len_over;
+ size_t len_total;
+ size_t len_main;
+ size_t len_prefix;
+
+ len_prefix = strlen(str_prefix);
+ if (!len_prefix) {
+ /* There is no prefix to prepend. */
+ return;
+ }
+ len_main = strlen(str_main);
+ len_total = len_prefix + len_main;
+ if (size <= len_total) {
+ /* We need to truncate since the buffer is too small. */
+ len_over = len_total + 1 - size;
+ if (len_over <= len_main) {
+ len_main -= len_over;
+ } else {
+ len_over -= len_main;
+ len_main = 0;
+ len_prefix -= len_over;
+ }
+ }
+ if (len_main) {
+ memmove(str_main + len_prefix, str_main, len_main);
+ }
+ memcpy(str_main, str_prefix, len_prefix);
+ str_main[len_prefix + len_main] = '\0';
+}
+
+/*!
+ * \internal
+ * \brief Add a configured prefix to the given number.
+ *
+ * \param port Logical port number
+ * \param number_type Type-of-number passed in.
+ * \param number Given number string to add prefix
+ * \param size Buffer size number string occupies.
+ *
+ * \return Nothing
+ */
+static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type, char *number, size_t size)
+{
+ enum misdn_cfg_elements type_prefix;
+ char num_prefix[MISDN_MAX_NUMBER_LEN];
+
+ /* Get prefix string. */
+ switch (number_type) {
+ case NUMTYPE_UNKNOWN:
+ type_prefix = MISDN_CFG_TON_PREFIX_UNKNOWN;
+ break;
+ case NUMTYPE_INTERNATIONAL:
+ type_prefix = MISDN_CFG_TON_PREFIX_INTERNATIONAL;
+ break;
+ case NUMTYPE_NATIONAL:
+ type_prefix = MISDN_CFG_TON_PREFIX_NATIONAL;
+ break;
+ case NUMTYPE_NETWORK_SPECIFIC:
+ type_prefix = MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC;
+ break;
+ case NUMTYPE_SUBSCRIBER:
+ type_prefix = MISDN_CFG_TON_PREFIX_SUBSCRIBER;
+ break;
+ case NUMTYPE_ABBREVIATED:
+ type_prefix = MISDN_CFG_TON_PREFIX_ABBREVIATED;
+ break;
+ default:
+ /* Type-of-number does not have a prefix that can be added. */
+ return;
+ }
+ misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix));
+
+ misdn_prefix_string(num_prefix, number, size);
+}
+
static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
{
char buf[128];
@@ -691,7 +1296,8 @@ static void export_aoc_vars(int originator, struct ast_channel *ast, struct misd
}
if (originator == ORG_AST) {
- if (!(ast = ast_bridged_channel(ast))) {
+ ast = ast_bridged_channel(ast);
+ if (!ast) {
return;
}
}
@@ -745,7 +1351,8 @@ static void export_aoc_vars(int originator, struct ast_channel *ast, struct misd
/*************** Helpers END *************/
static void sighandler(int sig)
-{}
+{
+}
static void *misdn_tasks_thread_func(void *data)
{
@@ -840,6 +1447,7 @@ static void misdn_tasks_remove(int task_id)
static int misdn_l1_task(const void *vdata)
{
const int *data = vdata;
+
misdn_lib_isdn_l1watcher(*data);
chan_misdn_log(5, *data, "L1watcher timeout\n");
return 1;
@@ -866,21 +1474,22 @@ static int misdn_overlap_dial_task(const void *data)
tv_end.tv_sec += ch->overlap_dial;
tv_now = ast_tvnow();
- if ((diff = ast_tvdiff_ms(tv_end, tv_now)) > 100) {
+ diff = ast_tvdiff_ms(tv_end, tv_now);
+ if (100 < diff) {
return diff;
}
/* if we are 100ms near the timeout, we are satisfied.. */
stop_indicate(ch);
- if (ast_strlen_zero(ch->bc->dad)) {
+ if (ast_strlen_zero(ch->bc->dialed.number)) {
dad = "s";
- ast_copy_string(ch->ast->exten, "s", sizeof(ch->ast->exten));
+ strcpy(ch->ast->exten, dad);
} else {
- dad = ch->bc->dad;
+ dad = ch->bc->dialed.number;
}
- if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) {
+ if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->caller.number)) {
ch->state = MISDN_DIALING;
if (pbx_start_chan(ch) < 0) {
chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
@@ -957,8 +1566,10 @@ static char *handle_cli_misdn_set_debug(struct ast_cli_entry *e, int cmd, struct
level = 1;
} else if (!strcasecmp(a->argv[3], "off")) {
level = 0;
- } else {
+ } else if (isdigit(a->argv[3][0])) {
level = atoi(a->argv[3]);
+ } else {
+ return CLI_SHOWUSAGE;
}
switch (a->argc) {
@@ -1293,27 +1904,29 @@ struct state_struct {
};
static struct state_struct state_array[] = {
+/* *INDENT-OFF* */
{ MISDN_NOTHING, "NOTHING" }, /* at beginning */
- { MISDN_WAITING4DIGS, "WAITING4DIGS" }, /* when waiting for infos */
- { MISDN_EXTCANTMATCH, "EXTCANTMATCH" }, /* when asterisk couldn't match our ext */
- { MISDN_INCOMING_SETUP, "INCOMING SETUP" }, /* when pbx_start */
- { MISDN_DIALING, "DIALING" }, /* when pbx_start */
- { MISDN_PROGRESS, "PROGRESS" }, /* when pbx_start */
- { MISDN_PROCEEDING, "PROCEEDING" }, /* when pbx_start */
- { MISDN_CALLING, "CALLING" }, /* when misdn_call is called */
- { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /* when misdn_call is called */
- { MISDN_ALERTING, "ALERTING" }, /* when Alerting */
- { MISDN_BUSY, "BUSY" }, /* when BUSY */
- { MISDN_CONNECTED, "CONNECTED" }, /* when connected */
- { MISDN_PRECONNECTED, "PRECONNECTED" }, /* when connected */
- { MISDN_DISCONNECTED, "DISCONNECTED" }, /* when connected */
- { MISDN_RELEASED, "RELEASED" }, /* when connected */
- { MISDN_BRIDGED, "BRIDGED" }, /* when bridged */
+ { MISDN_WAITING4DIGS, "WAITING4DIGS" }, /* when waiting for infos */
+ { MISDN_EXTCANTMATCH, "EXTCANTMATCH" }, /* when asterisk couldn't match our ext */
+ { MISDN_INCOMING_SETUP, "INCOMING SETUP" }, /* when pbx_start */
+ { MISDN_DIALING, "DIALING" }, /* when pbx_start */
+ { MISDN_PROGRESS, "PROGRESS" }, /* when pbx_start */
+ { MISDN_PROCEEDING, "PROCEEDING" }, /* when pbx_start */
+ { MISDN_CALLING, "CALLING" }, /* when misdn_call is called */
+ { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /* when misdn_call is called */
+ { MISDN_ALERTING, "ALERTING" }, /* when Alerting */
+ { MISDN_BUSY, "BUSY" }, /* when BUSY */
+ { MISDN_CONNECTED, "CONNECTED" }, /* when connected */
+ { MISDN_PRECONNECTED, "PRECONNECTED" }, /* when connected */
+ { MISDN_DISCONNECTED, "DISCONNECTED" }, /* when connected */
+ { MISDN_RELEASED, "RELEASED" }, /* when connected */
+ { MISDN_BRIDGED, "BRIDGED" }, /* when bridged */
{ MISDN_CLEANING, "CLEANING" }, /* when hangup from * but we were connected before */
- { MISDN_HUNGUP_FROM_MISDN, "HUNGUP_FROM_MISDN" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
- { MISDN_HOLDED, "HOLDED" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
- { MISDN_HOLD_DISCONNECT, "HOLD_DISCONNECT" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
+ { MISDN_HUNGUP_FROM_MISDN, "HUNGUP_FROM_MISDN" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
+ { MISDN_HOLDED, "HOLDED" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
+ { MISDN_HOLD_DISCONNECT, "HOLD_DISCONNECT" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
{ MISDN_HUNGUP_FROM_AST, "HUNGUP_FROM_AST" }, /* when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */
+/* *INDENT-ON* */
};
static const char *misdn_get_ch_state(struct chan_list *p)
@@ -1384,18 +1997,24 @@ static char *handle_cli_misdn_reload(struct ast_cli_entry *e, int cmd, struct as
static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel *bc)
{
struct ast_channel *ast = help->ast;
- ast_cli(fd,
- "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n",
- bc->pid, bc->port, bc->channel,
+ ast_cli(fd,
+ "* Pid:%d Port:%d Ch:%d Mode:%s Orig:%s dialed:%s\n"
+ " --> caller:\"%s\" <%s>\n"
+ " --> redirecting:\"%s\" <%s>\n"
+ " --> context:%s state:%s\n",
+ bc->pid,
+ bc->port,
+ bc->channel,
bc->nt ? "NT" : "TE",
help->originator == ORG_AST ? "*" : "I",
- ast ? ast->exten : NULL,
- ast ? ast->cid.cid_num : NULL,
- bc->rad,
- ast ? ast->context : NULL,
- misdn_get_ch_state(help)
- );
+ ast ? ast->exten : "",
+ (ast && ast->cid.cid_name) ? ast->cid.cid_name : "",
+ (ast && ast->cid.cid_num) ? ast->cid.cid_num : "",
+ bc->redirecting.from.name,
+ bc->redirecting.from.number,
+ ast ? ast->context : "",
+ misdn_get_ch_state(help));
if (misdn_debug[bc->port] > 0) {
ast_cli(fd,
" --> astname: %s\n"
@@ -1418,21 +2037,18 @@ static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel
help->l3id,
help->addr,
bc->addr,
- bc ? bc->l3_id : -1,
+ bc->l3_id,
bc->display,
-
bc->active,
bc_state2str(bc->bc_state),
bearer2str(bc->capability),
#ifdef MISDN_1_2
bc->pipeline,
#else
- bc->ec_enable,
+ bc->ec_enable,
#endif
-
help->norxtone, help->notxtone,
- bc->holded
- );
+ bc->holded);
}
}
@@ -1480,15 +2096,17 @@ static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, st
if (help->state == MISDN_HOLDED) {
ast_cli(a->fd, "ITS A HOLDED BC:\n");
ast_cli(a->fd, " --> l3_id: %x\n"
- " --> dad:%s oad:%s\n"
- " --> hold_port: %d\n"
- " --> hold_channel: %d\n",
- help->l3id,
- ast->exten,
- ast->cid.cid_num,
- help->hold_info.port,
- help->hold_info.channel
- );
+ " --> dialed:%s\n"
+ " --> caller:\"%s\" <%s>\n"
+ " --> hold_port: %d\n"
+ " --> hold_channel: %d\n",
+ help->l3id,
+ ast->exten,
+ ast->cid.cid_name ? ast->cid.cid_name : "",
+ ast->cid.cid_num ? ast->cid.cid_num : "",
+ help->hold_info.port,
+ help->hold_info.channel
+ );
} else {
ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num);
}
@@ -1693,7 +2311,7 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st
return 0;
}
tmp->bc->fac_out.Function = Fac_CD;
- ast_copy_string((char *)tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber));
+ ast_copy_string((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber));
misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
} else if (strstr(a->argv[3], "CFActivate")) {
if (a->argc < 7) {
@@ -1718,7 +2336,7 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st
} else if (strstr(a->argv[3], "CFDeactivate")) {
if (a->argc < 6) {
- ast_verbose("CFActivate requires 1 arg: FromNumber\n\n");
+ ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n");
return 0;
}
port = atoi(a->argv[4]);
@@ -1728,10 +2346,10 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st
ast_verbose("Sending CFDeactivate Port:(%d) FromNr. (%s)\n", port, served_nr);
bc->fac_out.Function = Fac_CFDeactivate;
- bc->fac_out.u.CFDeactivate.BasicService = 0; //All Services
- bc->fac_out.u.CFDeactivate.Procedure = 0; //Unconditional
+ bc->fac_out.u.CFDeactivate.BasicService = 0; /* All Services */
+ bc->fac_out.u.CFDeactivate.Procedure = 0; /* Unconditional */
+ ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
- ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
misdn_lib_send_event(bc, EVENT_FACILITY);
}
@@ -2009,23 +2627,25 @@ static struct ast_cli_entry chan_misdn_clis[] = {
};
/*! \brief Updates caller ID information from config */
-static int update_config(struct chan_list *ch, int orig)
+static void update_config(struct chan_list *ch)
{
struct ast_channel *ast;
struct misdn_bchannel *bc;
- int port, hdlc = 0;
- int pres, screen;
+ int port;
+ int hdlc = 0;
+ int pres;
+ int screen;
if (!ch) {
ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
- return -1;
+ return;
}
ast = ch->ast;
bc = ch->bc;
if (! ast || ! bc) {
ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
- return -1;
+ return;
}
port = bc->port;
@@ -2033,7 +2653,6 @@ static int update_config(struct chan_list *ch, int orig)
chan_misdn_log(7, port, "update_config: Getting Config\n");
misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
-
if (hdlc) {
switch (bc->capability) {
case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
@@ -2050,48 +2669,17 @@ static int update_config(struct chan_list *ch, int orig)
chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
if (pres < 0 || screen < 0) {
- chan_misdn_log(2, port, " --> pres: %x\n", ast->cid.cid_pres);
+ chan_misdn_log(2, port, " --> pres: %x\n", ast->connected.id.number_presentation);
- switch (ast->cid.cid_pres & 0x60) {
- case AST_PRES_RESTRICTED:
- bc->pres = 1;
- chan_misdn_log(2, port, " --> PRES: Restricted (1)\n");
- break;
- case AST_PRES_UNAVAILABLE:
- bc->pres = 2;
- chan_misdn_log(2, port, " --> PRES: Unavailable (2)\n");
- break;
- default:
- bc->pres = 0;
- chan_misdn_log(2, port, " --> PRES: Allowed (0)\n");
- break;
- }
+ bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation);
+ chan_misdn_log(2, port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
- switch (ast->cid.cid_pres & 0x3) {
- default:
- case AST_PRES_USER_NUMBER_UNSCREENED:
- bc->screen = 0;
- chan_misdn_log(2, port, " --> SCREEN: Unscreened (0)\n");
- break;
- case AST_PRES_USER_NUMBER_PASSED_SCREEN:
- bc->screen = 1;
- chan_misdn_log(2, port, " --> SCREEN: Passed Screen (1)\n");
- break;
- case AST_PRES_USER_NUMBER_FAILED_SCREEN:
- bc->screen = 2;
- chan_misdn_log(2, port, " --> SCREEN: Failed Screen (2)\n");
- break;
- case AST_PRES_NETWORK_NUMBER:
- bc->screen = 3;
- chan_misdn_log(2, port, " --> SCREEN: Network Nr. (3)\n");
- break;
- }
+ bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number_presentation);
+ chan_misdn_log(2, port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
} else {
- bc->screen = screen;
- bc->pres = pres;
+ bc->caller.screening = screen;
+ bc->caller.presentation = pres;
}
-
- return 0;
}
@@ -2130,20 +2718,26 @@ static void config_jitterbuffer(struct chan_list *ch)
}
-void debug_numplan(int port, int numplan, char *type)
+void debug_numtype(int port, int numtype, char *type)
{
- switch (numplan) {
- case NUMPLAN_INTERNATIONAL:
+ switch (numtype) {
+ case NUMTYPE_UNKNOWN:
+ chan_misdn_log(2, port, " --> %s: Unknown\n", type);
+ break;
+ case NUMTYPE_INTERNATIONAL:
chan_misdn_log(2, port, " --> %s: International\n", type);
break;
- case NUMPLAN_NATIONAL:
+ case NUMTYPE_NATIONAL:
chan_misdn_log(2, port, " --> %s: National\n", type);
break;
- case NUMPLAN_SUBSCRIBER:
+ case NUMTYPE_NETWORK_SPECIFIC:
+ chan_misdn_log(2, port, " --> %s: Network Specific\n", type);
+ break;
+ case NUMTYPE_SUBSCRIBER:
chan_misdn_log(2, port, " --> %s: Subscriber\n", type);
break;
- case NUMPLAN_UNKNOWN:
- chan_misdn_log(2, port, " --> %s: Unknown\n", type);
+ case NUMTYPE_ABBREVIATED:
+ chan_misdn_log(2, port, " --> %s: Abbreviated\n", type);
break;
/* Maybe we should cut off the prefix if present ? */
default:
@@ -2193,7 +2787,7 @@ static int update_ec_config(struct misdn_bchannel *bc)
#endif
-static int read_config(struct chan_list *ch, int orig)
+static int read_config(struct chan_list *ch)
{
struct ast_channel *ast;
struct misdn_bchannel *bc;
@@ -2234,7 +2828,6 @@ static int read_config(struct chan_list *ch, int orig)
misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf));
misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int));
-
if (ch->ast_dsp) {
ch->ignore_dtmf = 1;
}
@@ -2251,7 +2844,6 @@ static int read_config(struct chan_list *ch, int orig)
misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect));
misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc));
-
if (hdlc) {
switch (bc->capability) {
case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
@@ -2280,14 +2872,16 @@ static int read_config(struct chan_list *ch, int orig)
misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect));
+ misdn_cfg_get(port, MISDN_CFG_DISPLAY_CONNECTED, &bc->display_connected, sizeof(bc->display_connected));
+ misdn_cfg_get(port, MISDN_CFG_DISPLAY_SETUP, &bc->display_setup, sizeof(bc->display_setup));
+
misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));
-
chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
ast->pickupgroup = pg;
ast->callgroup = cg;
- if (orig == ORG_AST) {
+ if (ch->originator == ORG_AST) {
char callerid[BUFFERSIZE + 1];
/* ORIGINATOR Asterisk (outgoing call) */
@@ -2300,80 +2894,46 @@ static int read_config(struct chan_list *ch, int orig)
misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid));
if (!ast_strlen_zero(callerid)) {
- chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid);
- ast_copy_string(bc->oad, callerid, sizeof(bc->oad));
+ char *cid_name = NULL;
+ char *cid_num = NULL;
+
+ ast_callerid_parse(callerid, &cid_name, &cid_num);
+ if (cid_name) {
+ ast_copy_string(bc->caller.name, cid_name, sizeof(bc->caller.name));
+ } else {
+ bc->caller.name[0] = '\0';
+ }
+ if (cid_num) {
+ ast_copy_string(bc->caller.number, cid_num, sizeof(bc->caller.number));
+ } else {
+ bc->caller.number[0] = '\0';
+ }
+ chan_misdn_log(1, port, " --> * Setting caller to \"%s\" <%s>\n", bc->caller.name, bc->caller.number);
}
- misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(bc->dnumplan));
- misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(bc->onumplan));
- misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan));
- debug_numplan(port, bc->dnumplan, "TON");
- debug_numplan(port, bc->onumplan, "LTON");
- debug_numplan(port, bc->cpnnumplan, "CTON");
+ misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dialed.number_type, sizeof(bc->dialed.number_type));
+ bc->dialed.number_plan = NUMPLAN_ISDN;
+ debug_numtype(port, bc->dialed.number_type, "TON");
ch->overlap_dial = 0;
} else {
/* ORIGINATOR MISDN (incoming call) */
- char prefix[BUFFERSIZE + 1] = "";
if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
ch->faxdetect = (strstr(faxdetect, "nojump")) ? 2 : 1;
}
- misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan));
- debug_numplan(port, bc->cpnnumplan, "CTON");
-
- switch (bc->onumplan) {
- case NUMPLAN_INTERNATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix));
- break;
+ /* Add configured prefix to caller.number */
+ misdn_add_number_prefix(bc->port, bc->caller.number_type, bc->caller.number, sizeof(bc->caller.number));
- case NUMPLAN_NATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix));
- break;
- default:
- break;
- }
-
- ast_copy_string(buf, bc->oad, sizeof(buf));
- snprintf(bc->oad, sizeof(bc->oad), "%s%s", prefix, buf);
-
- if (!ast_strlen_zero(bc->dad)) {
- ast_copy_string(bc->orig_dad, bc->dad, sizeof(bc->orig_dad));
+ if (ast_strlen_zero(bc->dialed.number) && !ast_strlen_zero(bc->keypad)) {
+ ast_copy_string(bc->dialed.number, bc->keypad, sizeof(bc->dialed.number));
}
- if (ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) {
- ast_copy_string(bc->dad, bc->keypad, sizeof(bc->dad));
- }
+ /* Add configured prefix to dialed.number */
+ misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number));
- prefix[0] = 0;
-
- switch (bc->dnumplan) {
- case NUMPLAN_INTERNATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix));
- break;
- case NUMPLAN_NATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix));
- break;
- default:
- break;
- }
-
- ast_copy_string(buf, bc->dad, sizeof(buf));
- snprintf(bc->dad, sizeof(bc->dad), "%s%s", prefix, buf);
-
- if (strcmp(bc->dad, ast->exten)) {
- ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten));
- }
-
- ast_set_callerid(ast, bc->oad, NULL, bc->oad);
-
- if ( !ast_strlen_zero(bc->rad) ) {
- if (ast->cid.cid_rdnis) {
- ast_free(ast->cid.cid_rdnis);
- }
- ast->cid.cid_rdnis = ast_strdup(bc->rad);
- }
+ ast_copy_string(ast->exten, bc->dialed.number, sizeof(ast->exten));
misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
ast_mutex_init(&ch->overlap_tv_lock);
@@ -2400,6 +2960,79 @@ static int read_config(struct chan_list *ch, int orig)
return 0;
}
+/*!
+ * \internal
+ * \brief Notify peer that the connected line has changed.
+ *
+ * \param ast Current Asterisk channel
+ * \param bc Associated B channel
+ * \param originator Who originally created this channel. ORG_AST or ORG_MISDN
+ *
+ * \return Nothing
+ */
+static void misdn_update_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
+{
+ int number_type;
+
+ if (originator == ORG_MISDN) {
+ /* ORIGINATOR MISDN (incoming call) */
+
+ ast_copy_string(bc->connected.name, S_OR(ast->connected.id.name, ""), sizeof(bc->connected.name));
+ ast_copy_string(bc->connected.number, S_OR(ast->connected.id.number, ""), sizeof(bc->connected.number));
+ bc->connected.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation);
+ bc->connected.screening = ast_to_misdn_screen(ast->connected.id.number_presentation);
+
+ misdn_cfg_get(bc->port, MISDN_CFG_CPNDIALPLAN, &number_type, sizeof(number_type));
+ if (number_type < 0) {
+ bc->connected.number_type = ast_to_misdn_ton(ast->connected.id.number_type);
+ bc->connected.number_plan = ast_to_misdn_plan(ast->connected.id.number_type);
+ } else {
+ /* Force us to send in CONNECT message */
+ bc->connected.number_type = number_type;
+ bc->connected.number_plan = NUMPLAN_ISDN;
+ }
+ debug_numtype(bc->port, bc->connected.number_type, "CTON");
+ } else {
+ /* ORIGINATOR Asterisk (outgoing call) */
+
+ ast_copy_string(bc->caller.name, S_OR(ast->connected.id.name, ""), sizeof(bc->caller.name));
+ ast_copy_string(bc->caller.number, S_OR(ast->connected.id.number, ""), sizeof(bc->caller.number));
+ bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation);
+ bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number_presentation);
+
+ misdn_cfg_get(bc->port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
+ if (number_type < 0) {
+ bc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type);
+ bc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number_type);
+ } else {
+ /* Force us to send in SETUP message */
+ bc->caller.number_type = number_type;
+ bc->caller.number_plan = NUMPLAN_ISDN;
+ }
+ debug_numtype(bc->port, bc->caller.number_type, "LTON");
+ }
+}
+
+/*!
+ * \internal
+ * \brief Copy the redirecting info out of the Asterisk channel
+ *
+ * \param bc Associated B channel
+ * \param ast Current Asterisk channel
+ *
+ * \return Nothing
+ */
+static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct ast_channel *ast)
+{
+ ast_copy_string(bc->redirecting.from.name, S_OR(ast->redirecting.from.name, ""), sizeof(bc->redirecting.from.name));
+ ast_copy_string(bc->redirecting.from.number, S_OR(ast->cid.cid_rdnis, ""), sizeof(bc->redirecting.from.number));
+ bc->redirecting.from.presentation = ast_to_misdn_pres(ast->redirecting.from.number_presentation);
+ bc->redirecting.from.screening = ast_to_misdn_screen(ast->redirecting.from.number_presentation);
+ bc->redirecting.from.number_type = ast_to_misdn_ton(ast->redirecting.from.number_type);
+ bc->redirecting.from.number_plan = ast_to_misdn_plan(ast->redirecting.from.number_type);
+ bc->redirecting.reason = ast_to_misdn_reason(ast->redirecting.reason);
+}
+
/*****************************/
/*** AST Indications Start ***/
@@ -2411,22 +3044,17 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
int r;
int exceed;
int bridging;
- struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(ast);
+ int number_type;
+ struct chan_list *ch;
struct misdn_bchannel *newbc;
- char *dest_cp = ast_strdupa(dest);
+ char *dest_cp;
+
AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(type);
- AST_APP_ARG(ext);
- AST_APP_ARG(opts);
+ AST_APP_ARG(intf); /* The interface token is discarded. */
+ AST_APP_ARG(ext); /* extension token */
+ AST_APP_ARG(opts); /* options token */
);
- AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
-
- if (ast_strlen_zero(args.ext)) {
- chan_misdn_log(0, 0, "misdn_call: No Extension given!\n");
- return -1;
- }
-
if (!ast) {
ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
return -1;
@@ -2439,47 +3067,74 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
return -1;
}
+ ch = MISDN_ASTERISK_TECH_PVT(ast);
if (!ch) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
+ ast_log(LOG_WARNING, " --> ! misdn_call called on %s, chan_list *ch==NULL\n", ast->name);
ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
ast_setstate(ast, AST_STATE_DOWN);
return -1;
}
newbc = ch->bc;
-
if (!newbc) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
+ ast_log(LOG_WARNING, " --> ! misdn_call called on %s, newbc==NULL\n", ast->name);
ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
ast_setstate(ast, AST_STATE_DOWN);
return -1;
}
+ /*
+ * dest is ---v
+ * Dial(mISDN/g:group_name[/extension[/options]])
+ * Dial(mISDN/port[:preselected_channel][/extension[/options]])
+ *
+ * The dial extension could be empty if you are using MISDN_KEYPAD
+ * to control ISDN provider features.
+ */
+ dest_cp = ast_strdupa(dest);
+ AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
+ if (!args.ext) {
+ args.ext = "";
+ }
+
port = newbc->port;
- if ((exceed = add_out_calls(port))) {
+ exceed = add_out_calls(port);
+ if (exceed != 0) {
char tmp[16];
snprintf(tmp, sizeof(tmp), "%d", exceed);
pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
+ ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
+ ast_setstate(ast, AST_STATE_DOWN);
return -1;
}
chan_misdn_log(1, port, "* CALL: %s\n", dest);
- chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n", ast->exten, ast->name, ast->context);
+ chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast->name, ast->context);
- chan_misdn_log(3, port, " --> * adding2newbc ext %s\n", ast->exten);
- if (ast->exten) {
- ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
- ast_copy_string(newbc->dad, args.ext, sizeof(newbc->dad));
- }
+ ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
+ ast_copy_string(newbc->dialed.number, args.ext, sizeof(newbc->dialed.number));
- ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad));
+ if (ast_strlen_zero(newbc->caller.name) && !ast_strlen_zero(ast->connected.id.name)) {
+ ast_copy_string(newbc->caller.name, ast->connected.id.name, sizeof(newbc->caller.name));
+ chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
+ }
+ if (ast_strlen_zero(newbc->caller.number) && !ast_strlen_zero(ast->connected.id.number)) {
+ ast_copy_string(newbc->caller.number, ast->connected.id.number, sizeof(newbc->caller.number));
+ chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
+ }
- chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n", ast->cid.cid_num);
- if (ast_strlen_zero(newbc->oad) && !ast_strlen_zero(ast->cid.cid_num)) {
- ast_copy_string(newbc->oad, ast->cid.cid_num, sizeof(newbc->oad));
+ misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
+ if (number_type < 0) {
+ newbc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type);
+ newbc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number_type);
+ } else {
+ /* Force us to send in SETUP message */
+ newbc->caller.number_type = number_type;
+ newbc->caller.number_plan = NUMPLAN_ISDN;
}
+ debug_numtype(port, newbc->caller.number_type, "LTON");
newbc->capability = ast->transfercapability;
pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability));
@@ -2487,10 +3142,10 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
chan_misdn_log(2, port, " --> * Call with flag Digital\n");
}
- /* update screening and presentation */
- update_config(ch, ORG_AST);
+ /* update caller screening and presentation */
+ update_config(ch);
- /* fill in some ies from channel vary */
+ /* fill in some ies from channel dialplan variables */
import_ch(ast, newbc, ch);
/* Finally The Options Override Everything */
@@ -2499,6 +3154,11 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
} else {
chan_misdn_log(2, port, "NO OPTS GIVEN\n");
}
+ if (newbc->set_presentation) {
+ newbc->caller.presentation = newbc->presentation;
+ }
+
+ misdn_copy_redirecting_from_ast(newbc, ast);
/*check for bridging*/
misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
@@ -2519,7 +3179,7 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
/** we should have l3id after sending setup **/
ch->l3id = newbc->l3_id;
- if (r == -ENOCHAN ) {
+ if (r == -ENOCHAN) {
chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1);
ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
@@ -2585,9 +3245,19 @@ static int misdn_answer(struct ast_channel *ast)
p->state = MISDN_CONNECTED;
stop_indicate(p);
- if ( ast_strlen_zero(p->bc->cad) ) {
- chan_misdn_log(2, p->bc->port, " --> empty cad using dad\n");
- ast_copy_string(p->bc->cad, p->bc->dad, sizeof(p->bc->cad));
+ if (ast_strlen_zero(p->bc->connected.number)) {
+ chan_misdn_log(2,p->bc->port," --> empty connected number using dialed number\n");
+ ast_copy_string(p->bc->connected.number, p->bc->dialed.number, sizeof(p->bc->connected.number));
+
+ /*
+ * Use the misdn_set_opt() application to set the presentation
+ * before we answer or you can use the CONECTEDLINE() function
+ * to set everything before using the Answer() application.
+ */
+ p->bc->connected.presentation = p->bc->presentation;
+ p->bc->connected.screening = 0; /* unscreened */
+ p->bc->connected.number_type = p->bc->dialed.number_type;
+ p->bc->connected.number_plan = p->bc->dialed.number_plan;
}
misdn_lib_send_event(p->bc, EVENT_CONNECT);
@@ -2628,15 +3298,15 @@ static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int dur
break;
case MISDN_CALLING_ACKNOWLEDGE:
ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad));
- if (strlen(bc->dad) < sizeof(bc->dad) - 1) {
- strncat(bc->dad, buf, sizeof(bc->dad) - strlen(bc->dad) - 1);
+ if (strlen(bc->dialed.number) < sizeof(bc->dialed.number) - 1) {
+ strncat(bc->dialed.number, buf, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
}
- ast_copy_string(p->ast->exten, bc->dad, sizeof(p->ast->exten));
+ ast_copy_string(p->ast->exten, bc->dialed.number, sizeof(p->ast->exten));
misdn_lib_send_event(bc, EVENT_INFORMATION);
break;
default:
/* Do not send Digits in CONNECTED State, when
- * the other side is too mISDN. */
+ * the other side is also mISDN. */
if (p->other_ch) {
return 0;
}
@@ -2687,7 +3357,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
switch (cond) {
case AST_CONTROL_BUSY:
- chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc->pid);
ast_setstate(ast, AST_STATE_BUSY);
p->bc->out_cause = AST_CAUSE_USER_BUSY;
@@ -2699,20 +3369,20 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
}
return -1;
case AST_CONTROL_RING:
- chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc->pid);
return -1;
case AST_CONTROL_RINGING:
- chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc->pid);
switch (p->state) {
case MISDN_ALERTING:
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc->pid);
break;
case MISDN_CONNECTED:
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc->pid);
return -1;
default:
p->state = MISDN_ALERTING;
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc->pid);
misdn_lib_send_event( p->bc, EVENT_ALERTING);
if (p->other_ch && p->other_ch->bc) {
@@ -2727,7 +3397,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
}
}
- chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc->pid);
ast_setstate(ast, AST_STATE_RING);
if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio) {
@@ -2738,28 +3408,28 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
}
break;
case AST_CONTROL_ANSWER:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc->pid);
start_bc_tones(p);
break;
case AST_CONTROL_TAKEOFFHOOK:
- chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc->pid);
return -1;
case AST_CONTROL_OFFHOOK:
- chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc->pid);
return -1;
case AST_CONTROL_FLASH:
- chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc->pid);
break;
case AST_CONTROL_PROGRESS:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc->pid);
misdn_lib_send_event( p->bc, EVENT_PROGRESS);
break;
case AST_CONTROL_PROCEEDING:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc->pid);
misdn_lib_send_event( p->bc, EVENT_PROCEEDING);
break;
case AST_CONTROL_CONGESTION:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc->pid);
p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION;
start_bc_tones(p);
@@ -2770,7 +3440,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
}
break;
case -1 :
- chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc->pid);
stop_indicate(p);
@@ -2780,14 +3450,23 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
break;
case AST_CONTROL_HOLD:
ast_moh_start(ast, data, p->mohinterpret);
- chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc->pid);
break;
case AST_CONTROL_UNHOLD:
ast_moh_stop(ast);
- chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc->pid);
+ break;
+ case AST_CONTROL_CONNECTED_LINE:
+ chan_misdn_log(1, p->bc->port, "* IND :\tconnected line update pid:%d\n", p->bc->pid);
+ misdn_update_connected_line(ast, p->bc, p->originator);
+ break;
+ case AST_CONTROL_REDIRECTING:
+ chan_misdn_log(1, p->bc->port, "* IND :\tredirecting info update pid:%d\n", p->bc->pid);
+ misdn_copy_redirecting_from_ast(p->bc, ast);
break;
default:
- chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc ? p->bc->pid : -1);
+ chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc->pid);
+ break;
}
return 0;
@@ -2814,8 +3493,10 @@ static int misdn_hangup(struct ast_channel *ast)
if (bc) {
const char *tmp;
+
ast_channel_lock(ast);
- if ((tmp = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER"))) {
+ tmp = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER");
+ if (tmp) {
ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
strcpy(bc->uu, tmp);
bc->uulen = strlen(bc->uu);
@@ -2875,11 +3556,17 @@ static int misdn_hangup(struct ast_channel *ast)
}
ast_channel_unlock(ast);
- chan_misdn_log(1, bc->port, "* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n", p->bc ? p->bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(p));
+ chan_misdn_log(1, bc->port,
+ "* IND : HANGUP\tpid:%d context:%s dialed:%s caller:\"%s\" <%s> State:%s\n",
+ p->bc ? p->bc->pid : -1,
+ ast->context,
+ ast->exten,
+ ast->cid.cid_name ? ast->cid.cid_name : "",
+ ast->cid.cid_num ? ast->cid.cid_num : "",
+ misdn_get_ch_state(p));
chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);
- chan_misdn_log(2, bc->port, " --> state:%s\n", misdn_get_ch_state(p));
switch (p->state) {
case MISDN_INCOMING_SETUP:
@@ -3034,7 +3721,7 @@ static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame
ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
}
} else {
- ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten);
+ ast_log(LOG_NOTICE, "Fax detected but no fax extension, context:%s exten:%s\n", context, ast->exten);
}
} else {
ast_debug(1, "Already in a fax extension, not redirecting\n");
@@ -3081,7 +3768,8 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
FD_ZERO(&rrfs);
FD_SET(tmp->pipe[0], &rrfs);
- if (!(t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv))) {
+ t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv);
+ if (!t) {
chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
len = 160;
}
@@ -3249,15 +3937,11 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
return 0;
}
-
-
-
-static enum ast_bridge_result misdn_bridge (struct ast_channel *c0,
- struct ast_channel *c1, int flags,
- struct ast_frame **fo,
- struct ast_channel **rc,
- int timeoutms)
-
+static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
+ struct ast_channel *c1, int flags,
+ struct ast_frame **fo,
+ struct ast_channel **rc,
+ int timeoutms)
{
struct chan_list *ch1, *ch2;
struct ast_channel *carr[2], *who;
@@ -3293,7 +3977,11 @@ static enum ast_bridge_result misdn_bridge (struct ast_channel *c0,
ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
- chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad);
+ chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between \"%s\" <%s> and \"%s\" <%s>\n",
+ ch1->bc->caller.name,
+ ch1->bc->caller.number,
+ ch2->bc->caller.name,
+ ch2->bc->caller.number);
if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) ) {
ch1->ignore_dtmf = 1;
@@ -3342,7 +4030,7 @@ static enum ast_bridge_result misdn_bridge (struct ast_channel *c0,
}
#endif
- ast_write(who == c0 ? c1 : c0, f);
+ ast_write((who == c0) ? c1 : c0, f);
}
chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1);
@@ -3437,7 +4125,8 @@ static struct chan_list *init_chan_list(int orig)
{
struct chan_list *cl;
- if (!(cl = ast_calloc(1, sizeof(*cl)))) {
+ cl = ast_calloc(1, sizeof(*cl));
+ if (!cl) {
chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
return NULL;
}
@@ -3455,38 +4144,54 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat
{
struct ast_channel *tmp = NULL;
char group[BUFFERSIZE + 1] = "";
- char buf[128];
- char *buf2 = ast_strdupa(data), *ext = NULL, *port_str;
- char *tokb = NULL, *p = NULL;
- int channel = 0, port = 0;
+ char dial_str[128];
+ char *dest_cp;
+ char *p = NULL;
+ int channel = 0;
+ int port = 0;
struct misdn_bchannel *newbc = NULL;
int dec = 0;
+ struct chan_list *cl;
- struct chan_list *cl = init_chan_list(ORG_AST);
-
- snprintf(buf, sizeof(buf), "%s/%s", misdn_type, (char*)data);
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(intf); /* interface token */
+ AST_APP_ARG(ext); /* extension token */
+ AST_APP_ARG(opts); /* options token */
+ );
- port_str = strtok_r(buf2, "/", &tokb);
+ snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data);
- ext = strtok_r(NULL, "/", &tokb);
+ /*
+ * data is ---v
+ * Dial(mISDN/g:group_name[/extension[/options]])
+ * Dial(mISDN/port[:preselected_channel][/extension[/options]])
+ *
+ * The dial extension could be empty if you are using MISDN_KEYPAD
+ * to control ISDN provider features.
+ */
+ dest_cp = ast_strdupa(data);
+ AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
+ if (!args.ext) {
+ args.ext = "";
+ }
- if (port_str) {
- if (port_str[0] == 'g' && port_str[1] == ':' ) {
+ if (!ast_strlen_zero(args.intf)) {
+ if (args.intf[0] == 'g' && args.intf[1] == ':' ) {
/* We make a group call lets checkout which ports are in my group */
- port_str += 2;
- ast_copy_string(group, port_str, sizeof(group));
+ args.intf += 2;
+ ast_copy_string(group, args.intf, sizeof(group));
chan_misdn_log(2, 0, " --> Group Call group: %s\n", group);
- } else if ((p = strchr(port_str, ':'))) {
+ } else if ((p = strchr(args.intf, ':'))) {
/* we have a preselected channel */
- *p = 0;
- channel = atoi(++p);
- port = atoi(port_str);
+ *p++ = 0;
+ channel = atoi(p);
+ port = atoi(args.intf);
chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel);
} else {
- port = atoi(port_str);
+ port = atoi(args.intf);
}
} else {
- ast_log(LOG_WARNING, " --> ! IND : CALL dad:%s WITHOUT PORT/Group, check extensions.conf\n", ext);
+ ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str);
return NULL;
}
@@ -3579,7 +4284,8 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat
chan_misdn_log(4, port, "portup:%d\n", port_up);
if (port_up > 0) {
- if ((newbc = misdn_lib_get_free_bc(port, 0, 0, dec))) {
+ newbc = misdn_lib_get_free_bc(port, 0, 0, dec);
+ if (newbc) {
break;
}
}
@@ -3602,18 +4308,22 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat
chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel);
}
newbc = misdn_lib_get_free_bc(port, channel, 0, dec);
-
if (!newbc) {
- ast_log(LOG_WARNING, "Could not create channel on port:%d with extensions:%s\n", port, ext);
+ ast_log(LOG_WARNING, "Could not create channel on port:%d for Dial(%s)\n", port, dial_str);
return NULL;
}
}
/* create ast_channel and link all the objects together */
+ cl = init_chan_list(ORG_AST);
+ if (!cl) {
+ ast_log(LOG_WARNING, "Could not create Asterisk channel for Dial(%s)\n", dial_str);
+ return NULL;
+ }
cl->bc = newbc;
- tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel);
+ tmp = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, format, port, channel);
if (!tmp) {
ast_log(LOG_ERROR, "Could not create Asterisk object\n");
return NULL;
@@ -3625,7 +4335,7 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat
cl_queue_chan(&cl_te, cl);
/* fill in the config into the objects */
- read_config(cl, ORG_AST);
+ read_config(cl);
/* important */
cl->need_hangup = 0;
@@ -3736,7 +4446,7 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char
tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++);
if (tmp) {
- chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n", exten, callerid);
+ chan_misdn_log(2, 0, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid);
tmp->nativeformats = prefformat;
@@ -3791,7 +4501,11 @@ static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bc
}
}
- chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
+ chan_misdn_log(6, bc->port,
+ "$$$ find_chan_by_bc: No channel found for dialed:%s caller:\"%s\" <%s>\n",
+ bc->dialed.number,
+ bc->caller.name,
+ bc->caller.number);
return NULL;
}
@@ -3805,7 +4519,7 @@ static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid)
}
}
- chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n", pid);
+ chan_misdn_log(6, 0, "$$$ find_chan_by_pid: No channel found for pid:%d\n", pid);
return NULL;
}
@@ -3818,7 +4532,11 @@ static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchann
return NULL;
}
- chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad);
+ chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d dialed:%s caller:\"%s\" <%s>\n",
+ bc->channel,
+ bc->dialed.number,
+ bc->caller.name,
+ bc->caller.number);
for (; help; help = help->next) {
chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n", help->state == MISDN_HOLDED, help->hold_info.channel);
if ((help->state == MISDN_HOLDED) &&
@@ -3826,7 +4544,11 @@ static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchann
return help;
}
}
- chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
+ chan_misdn_log(6, bc->port,
+ "$$$ find_holded: No channel found for dialed:%s caller:\"%s\" <%s>\n",
+ bc->dialed.number,
+ bc->caller.name,
+ bc->caller.number);
return NULL;
}
@@ -3947,12 +4669,14 @@ static void hangup_chan(struct chan_list *ch)
}
/** Isdn asks us to release channel, pendant to misdn_hangup **/
-static void release_chan(struct misdn_bchannel *bc) {
+static void release_chan(struct misdn_bchannel *bc)
+{
struct ast_channel *ast = NULL;
struct chan_list *ch;
ast_mutex_lock(&release_lock);
- if (!(ch = find_chan_by_bc(cl_te, bc))) {
+ ch = find_chan_by_bc(cl_te, bc);
+ if (!ch) {
chan_misdn_log(1, bc->port, "release_chan: Ch not found!\n");
ast_mutex_unlock(&release_lock);
return;
@@ -3965,7 +4689,7 @@ static void release_chan(struct misdn_bchannel *bc) {
chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id);
/* releasing jitterbuffer */
- if (ch->jb ) {
+ if (ch->jb) {
misdn_jb_destroy(ch->jb);
ch->jb = NULL;
} else {
@@ -3993,7 +4717,14 @@ static void release_chan(struct misdn_bchannel *bc) {
close(ch->pipe[1]);
if (ast && MISDN_ASTERISK_TECH_PVT(ast)) {
- chan_misdn_log(1, bc->port, "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s\n", bc ? bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(ch));
+ chan_misdn_log(1, bc->port,
+ "* RELEASING CHANNEL pid:%d context:%s dialed:%s caller:\"%s\" <%s> state: %s\n",
+ bc->pid,
+ ast->context,
+ ast->exten,
+ ast->cid.cid_name ? ast->cid.cid_name : "",
+ ast->cid.cid_num ? ast->cid.cid_num : "",
+ misdn_get_ch_state(ch));
chan_misdn_log(3, bc->port, " --> * State Down\n");
MISDN_ASTERISK_TECH_PVT(ast) = NULL;
@@ -4053,9 +4784,14 @@ static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch,
ch->state = MISDN_INCOMING_SETUP;
}
- chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, ast->cid.cid_num);
+ chan_misdn_log(1, bc->port,
+ "* Starting Ast context:%s dialed:%s caller:\"%s\" <%s> with 's' extension\n",
+ ast->context,
+ ast->exten,
+ ast->cid.cid_name ? ast->cid.cid_name : "",
+ ast->cid.cid_num ? ast->cid.cid_num : "");
- strncpy(ast->exten, "s", 2);
+ strcpy(ast->exten, "s");
if (pbx_start_chan(ch) < 0) {
ast = NULL;
@@ -4183,6 +4919,7 @@ void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_
void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
{
char tmp[32];
+
chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid);
snprintf(tmp, sizeof(tmp), "%d", bc->pid);
pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp);
@@ -4237,7 +4974,8 @@ int add_out_calls(int port)
return 0;
}
-static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
+static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
+{
if (pbx_start_chan(ch) < 0) {
hangup_chan(ch);
chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
@@ -4250,10 +4988,11 @@ static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct as
}
}
-static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
+static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
+{
ch->state = MISDN_WAITING4DIGS;
misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- if (bc->nt && !bc->dad[0]) {
+ if (bc->nt && !bc->dialed.number[0]) {
dialtone_indicate(ch);
}
}
@@ -4273,7 +5012,14 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
debuglevel = 5;
}
- chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch ? misdn_get_ch_state(ch) : "none");
+ chan_misdn_log(debuglevel, bc->port,
+ "I IND :%s caller:\"%s\" <%s> dialed:%s pid:%d state:%s\n",
+ manager_isdn_get_info(event),
+ bc->caller.name,
+ bc->caller.number,
+ bc->dialed.number,
+ bc->pid,
+ ch ? misdn_get_ch_state(ch) : "none");
if (debuglevel == 1) {
misdn_lib_log_ies(bc);
chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state));
@@ -4407,25 +5153,23 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad));
}
- strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
+ strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
+ ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
/* Check for Pickup Request first */
if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
if (ast_pickup_call(ch->ast)) {
hangup_chan(ch);
} else {
- struct ast_channel *chan = ch->ast;
ch->state = MISDN_CALLING_ACKNOWLEDGE;
- ast_setstate(chan, AST_STATE_DOWN);
hangup_chan(ch);
ch->ast = NULL;
break;
}
}
- if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
+ if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
+ if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port);
strcpy(ch->ast->exten, "i");
@@ -4459,7 +5203,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
break;
}
- if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
+ if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
ch->state = MISDN_DIALING;
start_pbx(ch, bc, ch->ast);
}
@@ -4482,8 +5226,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits));
if (ch->state != MISDN_CONNECTED ) {
if (digits) {
- strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
+ strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
+ ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
ast_cdr_update(ch->ast);
}
@@ -4494,10 +5238,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
case EVENT_SETUP:
{
struct chan_list *ch = find_chan_by_bc(cl_te, bc);
- int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad);
+ int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dialed.number);
struct ast_channel *chan;
int exceed;
- int pres, screen;
int ai;
int im;
@@ -4537,10 +5280,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
ch->bc = bc;
ch->l3id = bc->l3_id;
ch->addr = bc->addr;
- ch->originator = ORG_MISDN;
-
- chan = misdn_new(ch, AST_STATE_RESERVED, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel);
+ chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, AST_FORMAT_ALAW, bc->port, bc->channel);
if (!chan) {
misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n");
@@ -4555,49 +5296,44 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp);
}
- read_config(ch, ORG_MISDN);
+ read_config(ch);
export_ch(chan, bc, ch);
ch->ast->rings = 1;
ast_setstate(ch->ast, AST_STATE_RINGING);
- switch (bc->pres) {
- case 1:
- pres = AST_PRES_RESTRICTED;
- chan_misdn_log(2, bc->port, " --> PRES: Restricted (1)\n");
- break;
- case 2:
- pres = AST_PRES_UNAVAILABLE;
- chan_misdn_log(2, bc->port, " --> PRES: Unavailable (2)\n");
- break;
- default:
- pres = AST_PRES_ALLOWED;
- chan_misdn_log(2, bc->port, " --> PRES: Allowed (%d)\n", bc->pres);
- break;
- }
+ /* Update asterisk channel caller information */
+ chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type);
+ chan_misdn_log(2, bc->port, " --> PLAN: %s(%d)\n", misdn_to_str_plan(bc->caller.number_plan), bc->caller.number_plan);
+ chan->cid.cid_ton = misdn_to_ast_ton(bc->caller.number_type)
+ | misdn_to_ast_plan(bc->caller.number_plan);
- switch (bc->screen) {
- default:
- case 0:
- screen = AST_PRES_USER_NUMBER_UNSCREENED;
- chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (%d)\n", bc->screen);
- break;
- case 1:
- screen = AST_PRES_USER_NUMBER_PASSED_SCREEN;
- chan_misdn_log(2, bc->port, " --> SCREEN: Passed screen (1)\n");
- break;
- case 2:
- screen = AST_PRES_USER_NUMBER_FAILED_SCREEN;
- chan_misdn_log(2, bc->port, " --> SCREEN: failed screen (2)\n");
- break;
- case 3:
- screen = AST_PRES_NETWORK_NUMBER;
- chan_misdn_log(2, bc->port, " --> SCREEN: Network Number (3)\n");
- break;
- }
+ chan_misdn_log(2, bc->port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
+ chan_misdn_log(2, bc->port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
+ chan->cid.cid_pres = misdn_to_ast_pres(bc->caller.presentation)
+ | misdn_to_ast_screen(bc->caller.screening);
+
+ ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number);
+
+ if (!ast_strlen_zero(bc->redirecting.from.number)) {
+ struct ast_party_redirecting redirecting;
- chan->cid.cid_pres = pres | screen;
+ /* Add configured prefix to redirecting.from.number */
+ misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type, bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
+
+ /* Update asterisk channel redirecting information */
+ ast_party_redirecting_set_init(&redirecting, &chan->redirecting);
+ redirecting.from.number = bc->redirecting.from.number;
+ redirecting.from.number_type =
+ misdn_to_ast_ton(bc->redirecting.from.number_type)
+ | misdn_to_ast_plan(bc->redirecting.from.number_plan);
+ redirecting.from.number_presentation =
+ misdn_to_ast_pres(bc->redirecting.from.presentation)
+ | misdn_to_ast_screen(bc->redirecting.from.screening);
+ redirecting.reason = misdn_to_ast_reason(bc->redirecting.reason);
+ ast_channel_set_redirecting(chan, &redirecting);
+ }
pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
chan->transfercapability = bc->capability;
@@ -4627,7 +5363,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
break;
}
}
- } /* end for */
+ }
if (i == ARRAY_LEN(allowed_bearers_array)) {
/* We did not find the bearer capability */
chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
@@ -4652,7 +5388,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
hangup_chan(ch);
} else {
ch->state = MISDN_CALLING_ACKNOWLEDGE;
- ast_setstate(chan, AST_STATE_DOWN);
hangup_chan(ch);
ch->ast = NULL;
break;
@@ -4669,16 +5404,16 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
break;
}
- /* check if we should jump into s when we have no dad */
+ /* check if we should jump into s when we have no dialed.number */
misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
- if (im && ast_strlen_zero(bc->dad)) {
+ if (im && ast_strlen_zero(bc->dialed.number)) {
do_immediate_setup(bc, ch, chan);
break;
}
chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context);
- if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
+ if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
+ if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port);
strcpy(ch->ast->exten, "i");
misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
@@ -4722,7 +5457,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
* the number is empty, we wait for the ISDN timeout
* instead of our own timer.
*/
- if (ch->overlap_dial && bc->nt && !bc->dad[0] ) {
+ if (ch->overlap_dial && bc->nt && !bc->dialed.number[0] ) {
wait_for_digits(ch, bc, chan);
break;
}
@@ -4747,7 +5482,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
/* If the extension does not exist and we're not TE_PTMP we wait for more digits
* without interdigit timeout.
* */
- if (!ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
+ if (!ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
wait_for_digits(ch, bc, chan);
break;
}
@@ -4755,29 +5490,30 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
/*
* If the extension exists let's just jump into it.
* */
- if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
+ if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
misdn_lib_send_event(bc, bc->need_more_infos ? EVENT_SETUP_ACKNOWLEDGE : EVENT_PROCEEDING);
ch->state = MISDN_DIALING;
start_pbx(ch, bc, chan);
break;
}
- }
break;
+ }
case EVENT_SETUP_ACKNOWLEDGE:
ch->state = MISDN_CALLING_ACKNOWLEDGE;
- if (bc->channel)
+ if (bc->channel) {
update_name(ch->ast,bc->port,bc->channel);
+ }
if (!ast_strlen_zero(bc->infos_pending)) {
/* TX Pending Infos */
- strncat(bc->dad, bc->infos_pending, sizeof(bc->dad) - strlen(bc->dad) - 1);
+ strncat(bc->dialed.number, bc->infos_pending, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
if (!ch->ast) {
break;
}
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
+ ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad));
ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending));
@@ -4842,29 +5578,31 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
}
break;
case EVENT_CONNECT:
- {
- struct ast_channel *bridged;
+ {
+ struct ast_party_connected_line connected;
- /*we answer when we've got our very new L3 ID from the NT stack */
- misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
+ /* we answer when we've got our very new L3 ID from the NT stack */
+ misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
- if (!ch->ast) {
- break;
- }
+ if (!ch->ast) {
+ break;
+ }
- bridged = ast_bridged_channel(ch->ast);
- stop_indicate(ch);
+ stop_indicate(ch);
- if (bridged && !strcasecmp(bridged->tech->type, "mISDN")) {
- struct chan_list *bridged_ch = MISDN_ASTERISK_TECH_PVT(bridged);
+ /* Add configured prefix to connected.number */
+ misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
+
+ /* Update the connected line information on the other channel */
+ ast_party_connected_line_init(&connected);
+ connected.id.number = bc->connected.number;
+ connected.id.number_type = misdn_to_ast_ton(bc->connected.number_type)
+ | misdn_to_ast_plan(bc->connected.number_plan);
+ connected.id.number_presentation = misdn_to_ast_pres(bc->connected.presentation)
+ | misdn_to_ast_screen(bc->connected.screening);
+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(ch->ast, &connected);
- chan_misdn_log(1, bc->port, " --> copying cpndialplan:%d and cad:%s to the A-Channel\n", bc->cpnnumplan, bc->cad);
- if (bridged_ch) {
- bridged_ch->bc->cpnnumplan = bc->cpnnumplan;
- ast_copy_string(bridged_ch->bc->cad, bc->cad, sizeof(bridged_ch->bc->cad));
- }
- }
- }
ch->l3id = bc->l3_id;
ch->addr = bc->addr;
@@ -4874,6 +5612,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
break;
+ }
case EVENT_CONNECT_ACKNOWLEDGE:
ch->l3id = bc->l3_id;
ch->addr = bc->addr;
@@ -4947,8 +5686,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
stop_bc_tones(ch);
hangup_chan(ch);
- if (ch)
+ if (ch) {
ch->state = MISDN_CLEANING;
+ }
release_chan(bc);
break;
@@ -5003,16 +5743,16 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
} else {
bc->tone_cnt = 0;
}
- }
break;
-
+ }
case EVENT_BCHAN_DATA:
if (ch->bc->AOCD_need_export) {
export_aoc_vars(ch->originator, ch->ast, ch->bc);
}
if (!misdn_cap_is_speech(ch->bc->capability)) {
struct ast_frame frame;
- /*In Data Modes we queue frames*/
+
+ /* In Data Modes we queue frames */
frame.frametype = AST_FRAME_VOICE; /* we have no data frames yet */
frame.subclass = AST_FORMAT_ALAW;
frame.datalen = bc->bframe_len;
@@ -5023,8 +5763,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
frame.src = NULL;
frame.data.ptr = bc->bframe;
- if (ch->ast)
+ if (ch->ast) {
ast_queue_frame(ch->ast, &frame);
+ }
} else {
fd_set wrfs;
struct timeval tv = { 0, 0 };
@@ -5099,6 +5840,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
break;
default:
misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+ break;
}
break;
@@ -5137,8 +5879,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
}
- }
break;
+ }
case EVENT_HOLD:
{
int hold_allowed;
@@ -5171,8 +5913,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
}
- }
break;
+ }
case EVENT_FACILITY:
print_facility(&(bc->fac_in), bc);
@@ -5189,7 +5931,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
ch_br = MISDN_ASTERISK_TECH_PVT(bridged);
/*ch->state = MISDN_FACILITY_DEFLECTED;*/
if (ch_br->bc) {
- if (ast_exists_extension(bridged, ch->context, (char *)bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->oad)) {
+ if (ast_exists_extension(bridged, ch->context, (char *) bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->caller.number)) {
ch_br->state = MISDN_DIALING;
if (pbx_start_chan(ch_br) < 0) {
chan_misdn_log(-1, ch_br->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
@@ -5461,6 +6203,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data)
{
struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
char *parse;
+
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(facility_type);
AST_APP_ARG(arg)[99];
@@ -5473,7 +6216,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data)
return -1;
}
- if (ast_strlen_zero((char *)data)) {
+ if (ast_strlen_zero((char *) data)) {
ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
return -1;
}
@@ -5492,7 +6235,9 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data)
}
if (strlen(args.arg[0]) >= sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)) {
- ast_log(LOG_WARNING, "Facility: Number argument too long (up to %d digits are allowed). Ignoring.\n", (int)sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
+ ast_log(LOG_WARNING,
+ "Facility: Number argument too long (up to %d digits are allowed). Ignoring.\n",
+ (int) sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
return 0;
}
ch->bc->fac_out.Function = Fac_CD;
@@ -5516,11 +6261,11 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data)
int port_up;
AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(grouppar);
- AST_APP_ARG(timeout);
+ AST_APP_ARG(grouppar);
+ AST_APP_ARG(timeout);
);
- if (ast_strlen_zero((char *)data)) {
+ if (ast_strlen_zero((char *) data)) {
ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n");
return -1;
}
@@ -5543,7 +6288,7 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data)
ast_copy_string(group, port_str, sizeof(group));
chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group);
- for ( port = misdn_cfg_get_next_port(port);
+ for (port = misdn_cfg_get_next_port(port);
port > 0;
port = misdn_cfg_get_next_port(port)) {
char cfg_group[BUFFERSIZE + 1];
@@ -5554,7 +6299,6 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data)
if (!strcasecmp(cfg_group, group)) {
port_up = misdn_lib_port_up(port, 1);
-
if (!port_up) {
chan_misdn_log(2, 0, " --> port '%d'\n", port);
misdn_lib_get_port_up(port);
@@ -5752,12 +6496,15 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data)
chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
/* CRICH: callingpres!!! */
if (strstr(tok, "allowed")) {
- ch->bc->pres = 0;
+ ch->bc->presentation = 0;
+ ch->bc->set_presentation = 1;
} else if (strstr(tok, "restricted")) {
- ch->bc->pres = 1;
+ ch->bc->presentation = 1;
+ ch->bc->set_presentation = 1;
} else if (strstr(tok, "not_screened")) {
chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
- ch->bc->pres = 1;
+ ch->bc->presentation = 1;
+ ch->bc->set_presentation = 1;
}
break;
case 'i' :
@@ -5975,16 +6722,10 @@ int misdn_jb_empty(struct misdn_jb *jb, char *data, int len)
return read;
}
-
-
-
/*******************************************************/
/*************** JITTERBUFFER END *********************/
/*******************************************************/
-
-
-
static void chan_misdn_log(int level, int port, char *tmpl, ...)
{
va_list ap;
@@ -6005,7 +6746,6 @@ static void chan_misdn_log(int level, int port, char *tmpl, ...)
if (level == -1) {
ast_log(LOG_WARNING, "%s", buf);
-
} else if (misdn_debug_only[port] ?
(level == 1 && misdn_debug[port]) || (level == misdn_debug[port])
: level <= misdn_debug[port]) {
@@ -6021,7 +6761,8 @@ static void chan_misdn_log(int level, int port, char *tmpl, ...)
FILE *fp = fopen(global_tracefile, "a+");
- if ((p = strchr(tmp, '\n'))) {
+ p = strchr(tmp, '\n');
+ if (p) {
*p = ':';
}
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index 82a37cc36..dd1578cb8 100644
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -303,13 +303,13 @@ static int phone_call(struct ast_channel *ast, char *dest, int timeout)
snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
}
/* the standard format of ast->callerid is: "name" <number>, but not always complete */
- if (ast_strlen_zero(ast->cid.cid_name))
+ if (ast_strlen_zero(ast->connected.id.name))
strcpy(cid.name, DEFAULT_CALLER_ID);
else
- ast_copy_string(cid.name, ast->cid.cid_name, sizeof(cid.name));
+ ast_copy_string(cid.name, ast->connected.id.name, sizeof(cid.name));
- if (ast->cid.cid_num)
- ast_copy_string(cid.number, ast->cid.cid_num, sizeof(cid.number));
+ if (ast->connected.id.number)
+ ast_copy_string(cid.number, ast->connected.id.number, sizeof(cid.number));
p = ast->tech_pvt;
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 4fb164f9c..10883c5f3 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -942,6 +942,54 @@ static const struct cfsip_options {
{ SIP_OPT_TARGET_DIALOG,NOT_SUPPORTED, "tdialog" },
};
+/*! \brief Diversion header reasons
+ *
+ * The core defines a bunch of constants used to define
+ * redirecting reasons. This provides a translation table
+ * between those and the strings which may be present in
+ * a SIP Diversion header
+ */
+static const struct sip_reasons {
+ enum AST_REDIRECTING_REASON code;
+ char * const text;
+} sip_reason_table[] = {
+ { AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
+ { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
+ { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" },
+ { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable" },
+ { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" },
+ { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" },
+ { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" },
+ { AST_REDIRECTING_REASON_DEFLECTION, "deflection" },
+ { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
+ { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
+ { AST_REDIRECTING_REASON_AWAY, "away" },
+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"}
+};
+
+static enum AST_REDIRECTING_REASON sip_reason_str_to_code(const char *text)
+{
+ enum AST_REDIRECTING_REASON ast = AST_REDIRECTING_REASON_UNKNOWN;
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(sip_reason_table); ++i) {
+ if (!strcasecmp(text, sip_reason_table[i].text)) {
+ ast = sip_reason_table[i].code;
+ break;
+ }
+ }
+
+ return ast;
+}
+
+static const char *sip_reason_code_to_str(enum AST_REDIRECTING_REASON code)
+{
+ if (code >= 0 && code < ARRAY_LEN(sip_reason_table)) {
+ return sip_reason_table[code].text;
+ }
+
+ return "unknown";
+}
/*! \brief SIP Methods we support
\todo This string should be set dynamically. We only support REFER and SUBSCRIBE if we have
@@ -1354,7 +1402,10 @@ struct sip_auth {
#define SIP_PROG_INBAND_NO (1 << 25)
#define SIP_PROG_INBAND_YES (2 << 25)
-#define SIP_SENDRPID (1 << 29) /*!< DP: Remote Party-ID Support */
+#define SIP_SENDRPID (3 << 29) /*!< DP: Remote Party-ID Support */
+#define SIP_SENDRPID_NO (0 << 29)
+#define SIP_SENDRPID_PAI (1 << 29) /*!< Use "P-Asserted-Identity" for rpid */
+#define SIP_SENDRPID_RPID (2 << 29) /*!< Use "Remote-Party-ID" for rpid */
#define SIP_G726_NONSTANDARD (1 << 31) /*!< DP: Use non-standard packing for G726-32 data */
/*! \brief Flags to copy from peer/user to dialog */
@@ -1373,6 +1424,9 @@ struct sip_auth {
/* Space for addition of other realtime flags in the future */
#define SIP_PAGE2_STATECHANGEQUEUE (1 << 9) /*!< D: Unsent state pending change exists */
+#define SIP_PAGE2_CONNECTLINEUPDATE_PEND (1 << 10)
+#define SIP_PAGE2_RPID_IMMEDIATE (1 << 11)
+
#define SIP_PAGE2_PREFERRED_CODEC (1 << 13) /*!< GDP: Only respond with single most preferred joint codec */
#define SIP_PAGE2_VIDEOSUPPORT (1 << 14) /*!< DP: Video supported if offered? */
#define SIP_PAGE2_TEXTSUPPORT (1 << 15) /*!< GDP: Global text enable */
@@ -1403,7 +1457,8 @@ struct sip_auth {
(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_IGNORESDPVERSION | \
SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | \
SIP_PAGE2_BUGGY_MWI | SIP_PAGE2_TEXTSUPPORT | SIP_PAGE2_FAX_DETECT | \
- SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC)
+ SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC | \
+ SIP_PAGE2_RPID_IMMEDIATE)
/*@}*/
@@ -1611,8 +1666,6 @@ struct sip_pvt {
AST_STRING_FIELD(fullcontact); /*!< The Contact: that the UA registers with us */
/* we only store the part in <brackets> in this field. */
AST_STRING_FIELD(our_contact); /*!< Our contact header */
- AST_STRING_FIELD(rpid); /*!< Our RPID header */
- AST_STRING_FIELD(rpid_from); /*!< Our RPID From header */
AST_STRING_FIELD(url); /*!< URL to be sent with next message to peer */
AST_STRING_FIELD(parkinglot); /*!< Parkinglot */
AST_STRING_FIELD(engine); /*!< RTP engine to use */
@@ -2237,7 +2290,7 @@ static int transmit_response_using_temp(ast_string_field callid, struct sockaddr
static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req);
static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req);
-static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp);
+static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid);
static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
@@ -2258,7 +2311,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty
static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
static void copy_request(struct sip_request *dst, const struct sip_request *src);
static void receive_message(struct sip_pvt *p, struct sip_request *req);
-static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req);
+static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward);
static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only);
/*--- Dialog management */
@@ -2506,11 +2559,14 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
static int set_address_from_contact(struct sip_pvt *pvt);
static void check_via(struct sip_pvt *p, struct sip_request *req);
static char *get_calleridname(const char *input, char *output, size_t outputsize);
-static int get_rpid_num(const char *input, char *output, int maxlen);
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq);
+static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
static int get_destination(struct sip_pvt *p, struct sip_request *oreq);
static int get_msg_text(char *buf, int len, struct sip_request *req, int addnewline);
static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
+static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
+static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen);
+static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward);
/*-- TCP connection handling ---*/
static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session);
@@ -2537,6 +2593,7 @@ static int add_header_contentLength(struct sip_request *req, int len);
static int add_line(struct sip_request *req, const char *line);
static int add_text(struct sip_request *req, const char *text);
static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
+static int add_rpid(struct sip_request *req, struct sip_pvt *p);
static int add_vidupdate(struct sip_request *req);
static void add_route(struct sip_request *req, struct sip_route *route);
static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
@@ -2545,7 +2602,6 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st
static void set_destination(struct sip_pvt *p, char *uri);
static void append_date(struct sip_request *req);
static void build_contact(struct sip_pvt *p);
-static void build_rpid(struct sip_pvt *p);
/*------Request handling functions */
static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock);
@@ -4808,6 +4864,8 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
ast_string_field_set(dialog, tohost, peer->tohost);
ast_string_field_set(dialog, fullcontact, peer->fullcontact);
ast_string_field_set(dialog, context, peer->context);
+ ast_string_field_set(dialog, cid_num, peer->cid_num);
+ ast_string_field_set(dialog, cid_name, peer->cid_name);
ast_string_field_set(dialog, parkinglot, peer->parkinglot);
ast_string_field_set(dialog, engine, peer->engine);
ref_proxy(dialog, obproxy_get(dialog, peer));
@@ -5072,11 +5130,13 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
p->t38.jointcapability = p->t38.capability;
ast_debug(2, "Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
+ sip_pvt_lock(p);
xmitres = transmit_invite(p, SIP_INVITE, 1, 2);
+ sip_pvt_unlock(p);
if (xmitres == XMIT_ERROR)
return -1;
p->invitestate = INV_CALLING;
-
+
/* Initialize auto-congest time */
AST_SCHED_REPLACE_UNREF(p->initid, sched, p->timer_b, auto_congest, p,
dialog_unref(_data, "dialog ptr dec when SCHED_REPLACE del op succeeded"),
@@ -5810,7 +5870,7 @@ static int sip_answer(struct ast_channel *ast)
change_t38_state(p, T38_ENABLED);
}
ast_rtp_instance_new_source(p->rtp);
- res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE);
+ res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE, TRUE);
ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
}
sip_pvt_unlock(p);
@@ -5846,8 +5906,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
ast_rtp_instance_new_source(p->rtp);
p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
+ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
+ ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
} else if (p->t38.state == T38_ENABLED && !p->t38.direct) {
change_t38_state(p, T38_DISABLED);
transmit_reinvite_with_sdp(p, FALSE, FALSE);
@@ -5868,8 +5928,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
+ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
+ ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
}
p->lastrtptx = time(NULL);
res = ast_rtp_instance_write(p->vrtp, frame);
@@ -5889,8 +5949,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
+ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
+ ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
}
p->lastrtptx = time(NULL);
res = ast_rtp_instance_write(p->trtp, frame);
@@ -6109,8 +6169,8 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
+ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
+ ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
break;
}
res = -1;
@@ -6168,6 +6228,12 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
case AST_CONTROL_SRCUPDATE:
ast_rtp_instance_new_source(p->rtp);
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ update_connectedline(p, data, datalen);
+ break;
+ case AST_CONTROL_REDIRECTING:
+ update_redirecting(p, data, datalen);
+ break;
case -1:
res = -1;
break;
@@ -8709,9 +8775,6 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, in
if (!ast_strlen_zero(global_useragent))
add_header(req, "User-Agent", global_useragent);
- if (!ast_strlen_zero(p->rpid))
- add_header(req, "Remote-Party-ID", p->rpid);
-
if (!ast_strlen_zero(p->url)) {
add_header(req, "Access-URL", p->url);
ast_string_field_set(p, url, NULL);
@@ -8749,6 +8812,14 @@ static int __transmit_response(struct sip_pvt *p, const char *msg, const struct
return -1;
}
respprep(&resp, p, msg, req);
+
+ if (ast_test_flag(&p->flags[0], SIP_SENDRPID)
+ && ast_test_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND)
+ && (!strncmp(msg, "180", 3) || !strncmp(msg, "183", 3))) {
+ ast_clear_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND);
+ add_rpid(&resp, p);
+ }
+
add_header_contentLength(&resp, 0);
/* If we are cancelling an incoming invite for some reason, add information
about the reason why we are doing this in clear text */
@@ -8968,6 +9039,89 @@ static int add_digit(struct sip_request *req, char digit, unsigned int duration,
return 0;
}
+/*!
+ * \pre if p->owner exists, it must be locked
+ * \brief Add Remote-Party-ID header to SIP message
+ */
+static int add_rpid(struct sip_request *req, struct sip_pvt *p)
+{
+ struct ast_str *tmp = ast_str_alloca(256);
+ char *lid_num = NULL;
+ char *lid_name = NULL;
+ int lid_pres;
+ const char *fromdomain;
+ const char *privacy = NULL;
+ const char *screen = NULL;
+ const char *anonymous_string = "\"Anonymous\" <anonymous@anonymous.invalid>";
+
+ if (!ast_test_flag(&p->flags[0], SIP_SENDRPID)) {
+ return 0;
+ }
+
+ if (p->owner && p->owner->connected.id.number)
+ lid_num = p->owner->connected.id.number;
+ if (p->owner && p->owner->connected.id.name)
+ lid_name = p->owner->connected.id.name;
+ lid_pres = (p->owner) ? p->owner->connected.id.number_presentation : AST_PRES_NUMBER_NOT_AVAILABLE;
+
+ if (ast_strlen_zero(lid_num))
+ return 0;
+ if (ast_strlen_zero(lid_name))
+ lid_name = lid_num;
+ fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr));
+
+ if (ast_test_flag(&p->flags[0], SIP_SENDRPID_PAI)) {
+ if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) {
+ ast_str_set(&tmp, -1, "%s", anonymous_string);
+ } else {
+ ast_str_set(&tmp, -1, "\"%s\" <sip:%s@%s>", lid_name, lid_num, fromdomain);
+ }
+ add_header(req, "P-Asserted-Identity", ast_str_buffer(tmp));
+ } else {
+ ast_str_set(&tmp, -1, "\"%s\" <sip:%s@%s>;party=%s", lid_name, lid_num, fromdomain, ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "calling" : "called");
+
+ switch (lid_pres) {
+ case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
+ case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
+ privacy = "off";
+ screen = "no";
+ break;
+ case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
+ case AST_PRES_ALLOWED_NETWORK_NUMBER:
+ privacy = "off";
+ screen = "yes";
+ break;
+ case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
+ case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
+ privacy = "full";
+ screen = "no";
+ break;
+ case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
+ case AST_PRES_PROHIB_NETWORK_NUMBER:
+ privacy = "full";
+ screen = "yes";
+ break;
+ case AST_PRES_NUMBER_NOT_AVAILABLE:
+ break;
+ default:
+ if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) {
+ privacy = "full";
+ }
+ else
+ privacy = "off";
+ screen = "no";
+ break;
+ }
+
+ if (!ast_strlen_zero(privacy) && !ast_strlen_zero(screen)) {
+ ast_str_append(&tmp, -1, ";privacy=%s;screen=%s", privacy, screen);
+ }
+
+ add_header(req, "Remote-Party-ID", ast_str_buffer(tmp));
+ }
+ return 0;
+}
+
/*! \brief add XML encoded media control with update
\note XML: The only way to turn 0 bits of information into a few hundred. (markster) */
static int add_vidupdate(struct sip_request *req)
@@ -9581,7 +9735,7 @@ static void copy_request(struct sip_request *dst, const struct sip_request *src)
/*! \brief Used for 200 OK and 183 early media
\return Will return XMIT_ERROR for network errors.
*/
-static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp)
+static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid)
{
struct sip_request resp;
int seqno;
@@ -9590,6 +9744,9 @@ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const
return -1;
}
respprep(&resp, p, msg, req);
+ if (rpid == TRUE) {
+ add_rpid(&resp, p);
+ }
if (p->rtp) {
if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
ast_debug(1, "Setting framing from config on incoming call\n");
@@ -9739,85 +9896,6 @@ static void build_contact(struct sip_pvt *p)
}
}
-/*! \brief Build the Remote Party-ID & From using callingpres options */
-static void build_rpid(struct sip_pvt *p)
-{
- int send_pres_tags = TRUE;
- const char *privacy=NULL;
- const char *screen=NULL;
- char buf[256];
- const char *clid = default_callerid;
- const char *clin = NULL;
- const char *fromdomain;
-
- if (!ast_strlen_zero(p->rpid) || !ast_strlen_zero(p->rpid_from))
- return;
-
- if (p->owner && p->owner->cid.cid_num)
- clid = p->owner->cid.cid_num;
- if (p->owner && p->owner->cid.cid_name)
- clin = p->owner->cid.cid_name;
- if (ast_strlen_zero(clin))
- clin = clid;
-
- switch (p->callingpres) {
- case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
- privacy = "off";
- screen = "no";
- break;
- case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
- privacy = "off";
- screen = "yes";
- break;
- case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
- privacy = "off";
- screen = "no";
- break;
- case AST_PRES_ALLOWED_NETWORK_NUMBER:
- privacy = "off";
- screen = "yes";
- break;
- case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
- privacy = "full";
- screen = "no";
- break;
- case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
- privacy = "full";
- screen = "yes";
- break;
- case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
- privacy = "full";
- screen = "no";
- break;
- case AST_PRES_PROHIB_NETWORK_NUMBER:
- privacy = "full";
- screen = "yes";
- break;
- case AST_PRES_NUMBER_NOT_AVAILABLE:
- send_pres_tags = FALSE;
- break;
- default:
- ast_log(LOG_WARNING, "Unsupported callingpres (%d)\n", p->callingpres);
- if ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)
- privacy = "full";
- else
- privacy = "off";
- screen = "no";
- break;
- }
-
- fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr));
-
- snprintf(buf, sizeof(buf), "\"%s\" <sip:%s@%s>", clin, clid, fromdomain);
- if (send_pres_tags)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";privacy=%s;screen=%s", privacy, screen);
- ast_string_field_set(p, rpid, buf);
-
- ast_string_field_build(p, rpid_from, "\"%s\" <sip:%s@%s>;tag=%s", clin,
- S_OR(p->fromuser, clid),
- fromdomain, p->tag);
-}
-
/*! \brief Initiate new SIP request to peer/user */
static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod)
{
@@ -9853,15 +9931,9 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text);
- if (p->owner) {
- l = p->owner->cid.cid_num;
- n = p->owner->cid.cid_name;
- }
- /* if we are not sending RPID and user wants his callerid restricted */
- if (!ast_test_flag(&p->flags[0], SIP_SENDRPID) &&
- ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)) {
- l = CALLERID_UNKNOWN;
- n = l;
+ if (p->owner && (p->owner->connected.id.number_presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
+ l = p->owner->connected.id.number;
+ n = p->owner->connected.id.name;
}
if (ast_strlen_zero(l))
l = default_callerid;
@@ -9950,12 +10022,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
/* SLD: FIXME?: do Route: here too? I think not cos this is the first request.
* OTOH, then we won't have anything in p->route anyway */
- /* Build Remote Party-ID and From */
- if (ast_test_flag(&p->flags[0], SIP_SENDRPID) && (sipmethod == SIP_INVITE)) {
- build_rpid(p);
- add_header(req, "From", p->rpid_from);
- } else
- add_header(req, "From", from);
+ add_header(req, "From", from);
add_header(req, "To", to);
ast_string_field_set(p, exten, l);
build_contact(p);
@@ -9964,8 +10031,44 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
add_header(req, "CSeq", tmp_n);
if (!ast_strlen_zero(global_useragent))
add_header(req, "User-Agent", global_useragent);
- if (!ast_strlen_zero(p->rpid))
- add_header(req, "Remote-Party-ID", p->rpid);
+}
+
+/*! \brief Add "Diversion" header to outgoing message
+ *
+ * We need to add a Diversion header if the owner channel of
+ * this dialog has redirecting information associated with it.
+ *
+ * \param req The request/response to which we will add the header
+ * \param pvt The sip_pvt which represents the call-leg
+ * \param apr Redirecting data used to make the diversion header
+ */
+static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt)
+{
+ const char *diverting_number;
+ const char *diverting_name;
+ const char *reason;
+ char header_text[256];
+
+ if (!pvt->owner) {
+ return;
+ }
+
+ diverting_number = pvt->owner->cid.cid_rdnis;
+ diverting_name = pvt->owner->redirecting.from.name;
+ reason = sip_reason_code_to_str(pvt->owner->redirecting.reason);
+
+ if (ast_strlen_zero(diverting_number)) {
+ return;
+ }
+
+ /* We at least have a number to place in the Diversion header, which is enough */
+ if (ast_strlen_zero(diverting_name)) {
+ snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason);
+ } else {
+ snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s", diverting_name, diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason);
+ }
+
+ add_header(req, "Diversion", header_text);
}
/*! \brief Build REFER/INVITE/OPTIONS/SUBSCRIBE message and transmit it
@@ -10086,6 +10189,11 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
ast_channel_unlock(chan);
}
+ if ((sipmethod == SIP_INVITE || sipmethod == SIP_UPDATE) && ast_test_flag(&p->flags[0], SIP_SENDRPID))
+ add_rpid(&req, p);
+ if (sipmethod == SIP_INVITE) {
+ add_diversion_header(&req, p);
+ }
if (sdp) {
if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
ast_udptl_offered_from_local(p->udptl, 1);
@@ -10568,6 +10676,80 @@ static char mandescr_sipnotify[] =
" *Variable: <name>=<value> At least one variable pair must be specified.\n"
" ActionID: <id> Action ID for this transaction. Will be returned.\n";
+/*! \brief Send a provisional response indicating that a call was redirected
+ */
+static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen)
+{
+ struct sip_request resp;
+
+ if (p->owner->_state == AST_STATE_UP || ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+ return;
+ }
+
+ if (!ast_strlen_zero(p->owner->redirecting.to.number)) {
+ ast_string_field_set(p, exten, p->owner->redirecting.to.number);
+ build_contact(p);
+ }
+ respprep(&resp, p, "181 Call is being forwarded", &p->initreq);
+ add_diversion_header(&resp, p);
+ send_response(p, &resp, XMIT_UNRELIABLE, 0);
+}
+
+/*! \brief Notify peer that the connected line has changed */
+static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen)
+{
+
+ if (!ast_test_flag(&p->flags[0], SIP_SENDRPID))
+ return;
+ if (ast_strlen_zero(p->owner->connected.id.number))
+ return;
+
+ append_history(p, "ConnectedLine", "%s party is now %s <%s>", ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "Calling" : "Called", p->owner->connected.id.name, p->owner->connected.id.number);
+
+ if (p->owner->_state == AST_STATE_UP || ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+ struct sip_request req;
+
+ if (p->invitestate == INV_CONFIRMED || p->invitestate == INV_TERMINATED) {
+ reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1);
+
+ add_header(&req, "Allow", ALLOWED_METHODS);
+ add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_rpid(&req, p);
+ add_sdp(&req, p, FALSE, TRUE, FALSE);
+
+ initialize_initreq(p, &req);
+ p->lastinvite = p->ocseq;
+ ast_set_flag(&p->flags[0], SIP_OUTGOING);
+ send_request(p, &req, XMIT_CRITICAL, p->ocseq);
+ } else {
+ reqprep(&req, p, SIP_UPDATE, 0, 1);
+ add_rpid(&req, p);
+ add_header_contentLength(&req, 0);
+ send_request(p, &req, XMIT_CRITICAL, p->ocseq);
+ }
+ } else {
+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_RPID_IMMEDIATE)) {
+ struct sip_request resp;
+
+ if ((p->owner->_state == AST_STATE_RING) && !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT)) {
+ respprep(&resp, p, "180 Ringing", &p->initreq);
+ add_rpid(&resp, p);
+ send_response(p, &resp, XMIT_UNRELIABLE, 0);
+ ast_set_flag(&p->flags[0], SIP_RINGING);
+ } else if (p->owner->_state == AST_STATE_RINGING) {
+ respprep(&resp, p, "183 Session Progress", &p->initreq);
+ add_rpid(&resp, p);
+ send_response(p, &resp, XMIT_UNRELIABLE, 0);
+ ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
+ } else {
+ ast_log(LOG_DEBUG, "Unable able to send update to '%s' in state '%s'\n", p->owner->name, ast_state2str(p->owner->_state));
+ }
+ } else {
+ ast_set_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND);
+ }
+ }
+}
+
static const struct _map_x_s regstatestrings[] = {
{ REG_STATE_FAILED, "Failed" },
{ REG_STATE_UNREGISTERED, "Unregistered"},
@@ -10595,7 +10777,7 @@ static const char *regstate2str(enum sipregistrystate regstate)
static int sip_reregister(const void *data)
{
/* if we are here, we know that we need to reregister. */
- struct sip_registry *r= (struct sip_registry *) data;
+ struct sip_registry *r = (struct sip_registry *) data;
/* if we couldn't get a reference to the registry object, punt */
if (!r)
@@ -12260,23 +12442,199 @@ static void sip_set_redirstr(struct sip_pvt *p, char *reason) {
}
}
+/*! \brief Parse the parts of the P-Asserted-Identity header
+ * on an incoming packet. Returns 1 if a valid header is found
+ * and it is different from the current caller id.
+ */
+static int get_pai(struct sip_pvt *p, struct sip_request *req)
+{
+ char pai[256];
+ char privacy[64];
+ char *cid_num = "";
+ char *cid_name = "";
+ int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+ char *start = NULL, *end = NULL;
+
+ ast_copy_string(pai, get_header(req, "P-Asserted-Identity"), sizeof(pai));
+
+ if (ast_strlen_zero(pai)) {
+ return 0;
+ }
+
+ start = pai;
+ if (*start == '"') {
+ *start++ = '\0';
+ end = strchr(start, '"');
+ if (!end)
+ return 0;
+ *end++ = '\0';
+ cid_name = start;
+ start = ast_skip_blanks(end);
+ }
+
+ if (*start != '<')
+ return 0;
+ *start++ = '\0';
+ end = strchr(start, '@');
+ if (!end)
+ return 0;
+ *end++ = '\0';
+ if (!strncasecmp(start, "anonymous@anonymous.invalid", 27)) {
+ callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+ /*XXX Assume no change in cid_num. Perhaps it should be
+ * blanked?
+ */
+ cid_num = (char *)p->cid_num;
+ } else if (!strncasecmp(start, "sip:", 4)) {
+ cid_num = start + 4;
+ if (ast_is_shrinkable_phonenumber(cid_num))
+ ast_shrink_phone_number(cid_num);
+ start = end;
+
+ end = strchr(start, '>');
+ if (!end)
+ return 0;
+ *end = '\0';
+ } else {
+ return 0;
+ }
+
+ ast_copy_string(privacy, get_header(req, "Privacy"), sizeof(privacy));
+ if (!ast_strlen_zero(privacy) && strncmp(privacy, "id", 2)) {
+ callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+ }
+
+ /* Only return true if the supplied caller id is different */
+ if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres)
+ return 0;
+
+ ast_string_field_set(p, cid_num, cid_num);
+ ast_string_field_set(p, cid_name, cid_name);
+ p->callingpres = callingpres;
+
+ if (p->owner) {
+ ast_set_callerid(p->owner, cid_num, cid_name, NULL);
+ p->owner->cid.cid_pres = callingpres;
+ }
+
+ return 1;
+}
+
+/*! \brief Get name, number and presentation from remote party id header,
+ * returns true if a valid header was found and it was different from the
+ * current caller id.
+ */
+static int get_rpid(struct sip_pvt *p, struct sip_request *oreq)
+{
+ char tmp[256];
+ struct sip_request *req;
+ char *cid_num = "";
+ char *cid_name = "";
+ int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+ char *privacy = "";
+ char *screen = "";
+ char *start, *end;
+
+ if (!ast_test_flag(&p->flags[0], SIP_TRUSTRPID))
+ return 0;
+ req = oreq;
+ if (!req)
+ req = &p->initreq;
+ ast_copy_string(tmp, get_header(req, "Remote-Party-ID"), sizeof(tmp));
+ if (ast_strlen_zero(tmp)) {
+ return get_pai(p, req);
+ }
+
+ start = tmp;
+ if (*start == '"') {
+ *start++ = '\0';
+ end = strchr(start, '"');
+ if (!end)
+ return 0;
+ *end++ = '\0';
+ cid_name = start;
+ start = ast_skip_blanks(end);
+ }
+
+ if (*start != '<')
+ return 0;
+ *start++ = '\0';
+ end = strchr(start, '@');
+ if (!end)
+ return 0;
+ *end++ = '\0';
+ if (strncasecmp(start, "sip:", 4))
+ return 0;
+ cid_num = start + 4;
+ if (ast_is_shrinkable_phonenumber(cid_num))
+ ast_shrink_phone_number(cid_num);
+ start = end;
+
+ end = strchr(start, '>');
+ if (!end)
+ return 0;
+ *end++ = '\0';
+ if (*end) {
+ start = end;
+ if (*start != ';')
+ return 0;
+ *start++ = '\0';
+ while (!ast_strlen_zero(start)) {
+ end = strchr(start, ';');
+ if (end)
+ *end++ = '\0';
+ if (!strncasecmp(start, "privacy=", 8))
+ privacy = start + 8;
+ else if (!strncasecmp(start, "screen=", 7))
+ screen = start + 7;
+ start = end;
+ }
+
+ if (!strcasecmp(privacy, "full")) {
+ if (!strcasecmp(screen, "yes"))
+ callingpres = AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
+ else if (!strcasecmp(screen, "no"))
+ callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+ } else {
+ if (!strcasecmp(screen, "yes"))
+ callingpres = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
+ else if (!strcasecmp(screen, "no"))
+ callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+ }
+ }
+
+ /* Only return true if the supplied caller id is different */
+ if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres)
+ return 0;
+
+ ast_string_field_set(p, cid_num, cid_num);
+ ast_string_field_set(p, cid_name, cid_name);
+ p->callingpres = callingpres;
+
+ if (p->owner) {
+ ast_set_callerid(p->owner, cid_num, cid_name, NULL);
+ p->owner->cid.cid_pres = callingpres;
+ }
+
+ return 1;
+}
+
/*! \brief Get referring dnis */
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq)
+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason)
{
- char tmp[256], *exten, *rexten, *rdomain;
- char *params, *reason = NULL;
+ char tmp[256], *exten, *rexten, *rdomain, *rname = NULL;
+ char *params, *reason_param = NULL;
struct sip_request *req;
-
+
req = oreq ? oreq : &p->initreq;
ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp));
if (ast_strlen_zero(tmp))
- return 0;
+ return -1;
- /*! \todo This function does not take user-parameters into consideration.
- First look for @, then start looking for ; to find uri-parameters.
- */
- params = strchr(tmp, ';');
+ if ((params = strchr(tmp, '>'))) {
+ params = strchr(params, ';');
+ }
exten = get_in_brackets(tmp);
if (!strncasecmp(exten, "sip:", 4)) {
@@ -12295,16 +12653,16 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq)
while (*params == ';' || *params == ' ')
params++;
/* Check if we have a reason parameter */
- if ((reason = strcasestr(params, "reason="))) {
- reason+=7;
+ if ((reason_param = strcasestr(params, "reason="))) {
+ reason_param+=7;
/* Remove enclosing double-quotes */
- if (*reason == '"')
- ast_strip_quoted(reason, "\"", "\"");
- if (!ast_strlen_zero(reason)) {
- sip_set_redirstr(p, reason);
+ if (*reason_param == '"')
+ ast_strip_quoted(reason_param, "\"", "\"");
+ if (!ast_strlen_zero(reason_param)) {
+ sip_set_redirstr(p, reason_param);
if (p->owner) {
pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause);
- pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason);
+ pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason_param);
}
}
}
@@ -12312,13 +12670,32 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq)
rdomain = exten;
rexten = strsep(&rdomain, "@"); /* trim anything after @ */
- if (p->owner)
+ if (p->owner)
pbx_builtin_setvar_helper(p->owner, "__SIPRDNISDOMAIN", rdomain);
if (sip_debug_test_pvt(p))
- ast_verbose("RDNIS for this call is is %s (reason %s)\n", exten, reason ? reason : "");
+ ast_verbose("RDNIS for this call is %s (reason %s)\n", exten, reason ? reason_param : "");
+
+ /*ast_string_field_set(p, rdnis, rexten);*/
+
+ if (*tmp == '\"') {
+ char *end_quote;
+ rname = tmp + 1;
+ end_quote = strchr(rname, '\"');
+ *end_quote = '\0';
+ }
- ast_string_field_set(p, rdnis, rexten);
+ if (number) {
+ *number = ast_strdup(rexten);
+ }
+
+ if (name && rname) {
+ *name = ast_strdup(rname);
+ }
+
+ if (reason && !ast_strlen_zero(reason_param)) {
+ *reason = sip_reason_str_to_code(reason_param);
+ }
return 0;
}
@@ -12931,58 +13308,12 @@ static char *get_calleridname(const char *input, char *output, size_t outputsize
return output;
}
-/*! \brief Get caller id number from Remote-Party-ID header field
- * Returns true if number should be restricted (privacy setting found)
- * output is set to NULL if no number found
- */
-static int get_rpid_num(const char *input, char *output, int maxlen)
-{
- char *start;
- char *end;
-
- start = strchr(input, ':');
- if (!start) {
- output[0] = '\0';
- return 0;
- }
- start++;
-
- /* we found "number" */
- ast_copy_string(output, start, maxlen);
- output[maxlen-1] = '\0';
-
- end = strchr(output, '@');
- if (end)
- *end = '\0';
- else
- output[0] = '\0';
- if (strstr(input, "privacy=full") || strstr(input, "privacy=uri"))
- return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
-
- return 0;
-}
-
-
-/*! \brief helper function for check_{user|peer}_ok() */
-static void replace_cid(struct sip_pvt *p, const char *rpid_num, const char *calleridname)
-{
- /* replace callerid if rpid found, and not restricted */
- if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
- char *tmp = ast_strdupa(rpid_num); /* XXX the copy can be done later */
- if (!ast_strlen_zero(calleridname))
- ast_string_field_set(p, cid_name, calleridname);
- if (ast_is_shrinkable_phonenumber(tmp))
- ast_shrink_phone_number(tmp);
- ast_string_field_set(p, cid_num, tmp);
- }
-}
/*! \brief Validate device authentication */
static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
struct sip_request *req, int sipmethod, struct sockaddr_in *sin,
struct sip_peer **authpeer,
- enum xmittype reliable,
- char *rpid_num, char *calleridname, char *uri2)
+ enum xmittype reliable, char *calleridname, char *uri2)
{
enum check_auth_result res;
int debug=sip_debug_test_addr(sin);
@@ -13030,7 +13361,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
if (p->sipoptions)
peer->sipoptions = p->sipoptions;
- replace_cid(p, rpid_num, calleridname);
do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE));
ast_string_field_set(p, peersecret, peer->secret);
@@ -13083,14 +13413,18 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
/* XXX this takes the name from the caller... can we override ? */
ast_string_field_set(p, authname, peer->username);
}
- if (!ast_strlen_zero(peer->cid_num)) {
- char *tmp = ast_strdupa(peer->cid_num);
- if (ast_is_shrinkable_phonenumber(tmp))
- ast_shrink_phone_number(tmp);
- ast_string_field_set(p, cid_num, tmp);
+ if (!get_rpid(p, req)) {
+ if (!ast_strlen_zero(peer->cid_num)) {
+ char *tmp = ast_strdupa(peer->cid_num);
+ if (ast_is_shrinkable_phonenumber(tmp))
+ ast_shrink_phone_number(tmp);
+ ast_string_field_set(p, cid_num, tmp);
+ }
+ if (!ast_strlen_zero(peer->cid_name))
+ ast_string_field_set(p, cid_name, peer->cid_name);
+ if (peer->callingpres)
+ p->callingpres = peer->callingpres;
}
- if (!ast_strlen_zero(peer->cid_name))
- ast_string_field_set(p, cid_name, peer->cid_name);
ast_string_field_set(p, fullcontact, peer->fullcontact);
if (!ast_strlen_zero(peer->context))
ast_string_field_set(p, context, peer->context);
@@ -13140,8 +13474,6 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
char *dummy; /* dummy return value for parse_uri */
char *domain; /* dummy return value for parse_uri */
char *of, *of2;
- char rpid_num[50];
- const char *rpid;
enum check_auth_result res;
char calleridname[50];
char *uri2 = ast_strdupa(uri);
@@ -13157,11 +13489,6 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
if (calleridname[0])
ast_string_field_set(p, cid_name, calleridname);
- rpid = get_header(req, "Remote-Party-ID");
- memset(rpid_num, 0, sizeof(rpid_num));
- if (!ast_strlen_zero(rpid))
- p->callingpres = get_rpid_num(rpid, rpid_num, sizeof(rpid_num));
-
of = get_in_brackets(from);
if (ast_strlen_zero(p->exten)) {
char *t = uri2;
@@ -13235,13 +13562,13 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
}
res = check_peer_ok(p, of, req, sipmethod, sin,
- authpeer, reliable, rpid_num, calleridname, uri2);
+ authpeer, reliable, calleridname, uri2);
if (res != AUTH_DONT_KNOW)
return res;
/* Finally, apply the guest policy */
if (sip_cfg.allowguest) {
- replace_cid(p, rpid_num, calleridname);
+ get_rpid(p, req);
if (!dialog_initialize_rtp(p)) {
res = AUTH_SUCCESSFUL;
} else {
@@ -16483,29 +16810,150 @@ static struct ast_custom_function sipchaninfo_function = {
.read = function_sipchaninfo_read,
};
+static int read_to_parts(struct sip_pvt *p, struct sip_request *req, char **name, char **number)
+{
+
+ char to_header[256];
+ char *to_name = NULL;
+ char *to_number = NULL;
+ char *separator;
+
+ ast_copy_string(to_header, get_header(req, "To"), sizeof(to_header));
+
+ /* Let's get that number first! */
+ to_number = get_in_brackets(to_header);
+
+ if (!strncasecmp(to_number, "sip:", 4)) {
+ to_number += 4;
+ } else if (!strncasecmp(to_number, "sips:", 5)) {
+ to_number += 5;
+ } else {
+ ast_log(LOG_WARNING, "Not a SIP URI? (%s)!\n", to_number);
+ return -1;
+ }
+
+ /* Remove the host and such since we just want the number */
+ if ((separator = strchr(to_number, '@'))) {
+ *separator = '\0';
+ }
+
+ /* We have the number. Let's get the name now. */
+
+ if (*to_header == '\"') {
+ to_name = to_header + 1;
+ if (!(separator = (char *)find_closing_quote(to_name, NULL))) {
+ ast_log(LOG_NOTICE, "No closing quote in name section of To: header (%s)\n", to_header);
+ return -1;
+ }
+ *separator = '\0';
+ }
+
+ if (number) {
+ *number = ast_strdup(to_number);
+ }
+ if (name && !ast_strlen_zero(to_name)) {
+ *name = ast_strdup(to_name);
+ }
+
+ return 0;
+}
+
+/*! \brief update redirecting information for a channel based on headers
+ *
+ */
+static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward)
+{
+ char *redirecting_from_name = NULL;
+ char *redirecting_from_number = NULL;
+ char *redirecting_to_name = NULL;
+ char *redirecting_to_number = NULL;
+ int reason = AST_REDIRECTING_REASON_UNCONDITIONAL;
+ int is_response = req->method == SIP_RESPONSE;
+ int res = 0;
+
+ res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason);
+ if (res == -1) {
+ if (is_response) {
+ read_to_parts(p, req, &redirecting_from_name, &redirecting_from_number);
+ } else {
+ return;
+ }
+ }
+
+ /* At this point, all redirecting "from" info should be filled in appropriately
+ * on to the "to" info
+ */
+
+ if (is_response) {
+ parse_moved_contact(p, req, &redirecting_to_name, &redirecting_to_number, set_call_forward);
+ } else {
+ read_to_parts(p, req, &redirecting_to_name, &redirecting_to_number);
+ }
+
+ if (!ast_strlen_zero(redirecting_from_number)) {
+ if (redirecting->from.number) {
+ ast_free(redirecting->from.number);
+ }
+ ast_debug(3, "Got redirecting from number %s\n", redirecting_from_number);
+ redirecting->from.number = redirecting_from_number;
+ }
+ if (!ast_strlen_zero(redirecting_from_name)) {
+ if (redirecting->from.name) {
+ ast_free(redirecting->from.name);
+ }
+ ast_debug(3, "Got redirecting from name %s\n", redirecting_from_name);
+ redirecting->from.name = redirecting_from_name;
+ }
+ if (!ast_strlen_zero(redirecting_to_number)) {
+ if (redirecting->to.number) {
+ ast_free(redirecting->to.number);
+ }
+ ast_debug(3, "Got redirecting to number %s\n", redirecting_to_number);
+ redirecting->to.number = redirecting_to_number;
+ }
+ if (!ast_strlen_zero(redirecting_to_name)) {
+ if (redirecting->to.name) {
+ ast_free(redirecting->to.name);
+ }
+ ast_debug(3, "Got redirecting to name %s\n", redirecting_from_number);
+ redirecting->to.name = redirecting_to_name;
+ }
+ redirecting->reason = reason;
+}
+
/*! \brief Parse 302 Moved temporalily response
\todo XXX Doesn't redirect over TLS on sips: uri's.
If we get a redirect to a SIPS: uri, this needs to be going back to the
dialplan (this is a request for a secure signalling path).
Note that transport=tls is deprecated, but we need to support it on incoming requests.
*/
-static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
+static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward)
{
- char tmp[SIPBUFSIZE];
- char *s, *e, *t, *trans;
+ char contact[SIPBUFSIZE];
+ char *contact_name = NULL;
+ char *contact_number = NULL;
+ char *separator, *trans;
char *domain;
enum sip_transport transport = SIP_TRANSPORT_UDP;
- ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp));
- if ((t = strchr(tmp, ',')))
- *t = '\0';
+ ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact));
+ if ((separator = strchr(contact, ',')))
+ *separator = '\0';
- s = get_in_brackets(tmp);
- if ((trans = strcasestr(s, ";transport="))) do {
+ /* ooh, a name */
+ if (*contact == '"') {
+ contact_name = contact + 1;
+ if ((separator = strchr(contact_name, '"'))) {
+ *separator++ = '\0';
+ }
+ }
+
+ contact_number = get_in_brackets(contact);
+ if ((trans = strcasestr(contact_number, ";transport="))) {
trans += 11;
- if ((e = strchr(trans, ';')))
- *e = '\0';
+ if ((separator = strchr(trans, ';')))
+ *separator = '\0';
if (!strncasecmp(trans, "tcp", 3))
transport = SIP_TRANSPORT_TCP;
@@ -16513,12 +16961,12 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
transport = SIP_TRANSPORT_TLS;
else {
if (strncasecmp(trans, "udp", 3))
- ast_debug(1, "received contact with an invalid transport, '%s'\n", s);
+ ast_debug(1, "received contact with an invalid transport, '%s'\n", contact_number);
/* This will assume UDP for all unknown transports */
transport = SIP_TRANSPORT_UDP;
}
- } while(0);
- s = remove_uri_parameters(s);
+ }
+ contact_number = remove_uri_parameters(contact_number);
if (p->socket.tcptls_session) {
ao2_ref(p->socket.tcptls_session, -1);
@@ -16528,51 +16976,70 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
p->socket.fd = -1;
p->socket.type = transport;
- if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
+ if (set_call_forward && ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
char *host = NULL;
- if (!strncasecmp(s, "sip:", 4))
- s += 4;
- else if (!strncasecmp(s, "sips:", 5))
- s += 5;
- e = strchr(s, '/');
- if (e)
- *e = '\0';
- if ((host = strchr(s, '@'))) {
+ if (!strncasecmp(contact_number, "sip:", 4))
+ contact_number += 4;
+ else if (!strncasecmp(contact_number, "sips:", 5))
+ contact_number += 5;
+ separator = strchr(contact_number, '/');
+ if (separator)
+ *separator = '\0';
+ if ((host = strchr(contact_number, '@'))) {
*host++ = '\0';
- ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", s, get_transport(transport), host);
+ ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", contact_number, get_transport(transport), host);
if (p->owner)
- ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", s, get_transport(transport), host);
+ ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", contact_number, get_transport(transport), host);
} else {
- ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), s);
+ ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), contact_number);
if (p->owner)
- ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), s);
+ ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), contact_number);
}
} else {
- e = strchr(tmp, '@');
- if (e) {
- *e++ = '\0';
- domain = e;
+ separator = strchr(contact, '@');
+ if (separator) {
+ *separator++ = '\0';
+ domain = separator;
} else {
/* No username part */
- domain = tmp;
- }
- e = strchr(tmp, '/'); /* WHEN do we hae a forward slash in the URI? */
- if (e)
- *e = '\0';
-
- if (!strncasecmp(s, "sip:", 4))
- s += 4;
- else if (!strncasecmp(s, "sips:", 5))
- s += 5;
- e = strchr(s, ';'); /* And username ; parameters? */
- if (e)
- *e = '\0';
- ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", s, domain);
- if (p->owner) {
- pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain);
- ast_string_field_set(p->owner, call_forward, s);
+ domain = contact;
+ }
+ separator = strchr(contact, '/'); /* WHEN do we hae a forward slash in the URI? */
+ if (separator)
+ *separator = '\0';
+
+ if (!strncasecmp(contact_number, "sip:", 4))
+ contact_number += 4;
+ else if (!strncasecmp(contact_number, "sips:", 5))
+ contact_number += 5;
+ separator = strchr(contact_number, ';'); /* And username ; parameters? */
+ if (separator)
+ *separator = '\0';
+ if (set_call_forward) {
+ ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", contact_number, domain);
+ if (p->owner) {
+ pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain);
+ ast_string_field_set(p->owner, call_forward, contact_number);
+ }
}
}
+
+ /* We've gotten the number for the contact, now get the name */
+
+ if (*contact == '\"') {
+ contact_name = contact + 1;
+ if (!(separator = (char *)find_closing_quote(contact_name, NULL))) {
+ ast_log(LOG_NOTICE, "No closing quote on name in Contact header? %s\n", contact);
+ }
+ *separator = '\0';
+ }
+
+ if (name && !ast_strlen_zero(contact_name)) {
+ *name = ast_strdup(contact_name);
+ }
+ if (number) {
+ *number = ast_strdup(contact_number);
+ }
}
/*! \brief Check pending actions on SIP call */
@@ -16635,6 +17102,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
char *p_hdrval;
int rtn;
+ struct ast_party_connected_line connected;
if (reinvite)
ast_debug(4, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid);
@@ -16653,7 +17121,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
/* RFC3261 says we must treat every 1xx response (but not 100)
that we don't recognize as if it was 183.
*/
- if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 182 && resp != 183)
+ if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 181 && resp != 182 && resp != 183)
resp = 183;
/* Any response between 100 and 199 is PROCEEDING */
@@ -16681,6 +17149,14 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p))
ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
if (!req->ignore && p->owner) {
+ if (get_rpid(p, req)) {
+ ast_party_connected_line_init(&connected);
+ connected.id.number = (char *) p->cid_num;
+ connected.id.name = (char *) p->cid_name;
+ connected.id.number_presentation = p->callingpres;
+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(p->owner, &connected);
+ }
ast_queue_control(p->owner, AST_CONTROL_RINGING);
if (p->owner->_state != AST_STATE_UP) {
ast_setstate(p->owner, AST_STATE_RINGING);
@@ -16698,10 +17174,32 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
check_pendings(p);
break;
+ case 181: /* Call Is Being Forwarded */
+ if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
+ ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
+ if (!req->ignore && p->owner) {
+ struct ast_party_redirecting redirecting = {{0,},};
+ change_redirecting_information(p, req, &redirecting, FALSE);
+ ast_channel_queue_redirecting_update(p->owner, &redirecting);
+ }
+ check_pendings(p);
+ break;
+
case 183: /* Session progress */
if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
/* Ignore 183 Session progress without SDP */
+ if (!req->ignore && p->owner) {
+ if (get_rpid(p, req)) {
+ /* Queue a connected line update */
+ ast_party_connected_line_init(&connected);
+ connected.id.number = (char *) p->cid_num;
+ connected.id.name = (char *) p->cid_name;
+ connected.id.number_presentation = p->callingpres;
+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(p->owner, &connected);
+ }
+ }
if (find_sdp(req)) {
if (p->invitestate != INV_CANCELLED)
p->invitestate = INV_EARLY_MEDIA;
@@ -16723,7 +17221,17 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
if (!reinvite)
/* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */
/* For re-invites, we try to recover */
- ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
+ ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
+ }
+
+ if (!req->ignore && p->owner && get_rpid(p, req)) {
+ /* Queue a connected line update */
+ ast_party_connected_line_init(&connected);
+ connected.id.number = (char *) p->cid_num;
+ connected.id.name = (char *) p->cid_name;
+ connected.id.number_presentation = p->callingpres;
+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(p->owner, &connected);
}
/* Parse contact header for continued conversation */
@@ -16747,6 +17255,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
if (!req->ignore && p->owner) {
if (!reinvite) {
+ struct ast_party_connected_line connected;
+ ast_party_connected_line_collect_caller(&connected, &p->owner->cid);
+ ast_channel_queue_connected_line_update(p->owner, &connected);
ast_queue_control(p->owner, AST_CONTROL_ANSWER);
if (sip_cfg.callevents)
manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
@@ -17402,6 +17913,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
case 183: /* 183 Session Progress */
case 180: /* 180 Ringing */
case 182: /* 182 Queued */
+ case 181: /* 181 Call Is Being Forwarded */
if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, seqno);
break;
@@ -17569,7 +18081,11 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
case 301: /* Moved permanently */
case 302: /* Moved temporarily */
case 305: /* Use Proxy */
- parse_moved_contact(p, req);
+ {
+ struct ast_party_redirecting redirecting = {{0,},};
+ change_redirecting_information(p, req, &redirecting, TRUE);
+ ast_channel_set_redirecting(p->owner, &redirecting);
+ }
/* Fall through */
case 486: /* Busy here */
case 600: /* Busy everywhere */
@@ -18265,7 +18781,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, in
/* We should answer something here. If we are here, the
call we are replacing exists, so an accepted
can't harm */
- transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE);
+ transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE);
/* Do something more clever here */
ast_channel_unlock(c);
sip_pvt_unlock(p->refer->refer_call);
@@ -18299,7 +18815,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, in
Targetcall is not touched by the masq */
/* Answer the incoming call and set channel to UP state */
- transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE);
+ transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE);
ast_setstate(c, AST_STATE_UP);
@@ -18699,10 +19215,11 @@ static int sip_t38_abort(const void *data)
return 0;
}
-/*! \brief Handle incoming INVITE request
-\note If the INVITE has a Replaces header, it is part of an
+/*!
+ * \brief Handle incoming INVITE request
+ * \note If the INVITE has a Replaces header, it is part of an
* attended transfer. If so, we do not go through the dial
- * plan but tries to find the active call and masquerade
+ * plan but try to find the active call and masquerade
* into it
*/
static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int *nounlock)
@@ -18973,6 +19490,16 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
parse_ok_contact(p, req);
} else { /* Re-invite on existing call */
ast_clear_flag(&p->flags[0], SIP_OUTGOING); /* This is now an inbound dialog */
+ if (get_rpid(p, req)) {
+ struct ast_party_connected_line connected;
+
+ ast_party_connected_line_init(&connected);
+ connected.id.number = (char *) p->cid_num;
+ connected.id.name = (char *) p->cid_name;
+ connected.id.number_presentation = p->callingpres;
+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_queue_connected_line_update(p->owner, &connected);
+ }
/* Handle SDP here if we already have an owner */
if (find_sdp(req)) {
if (process_sdp(p, req, SDP_T38_INITIATE)) {
@@ -18995,6 +19522,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
if (!p->lastinvite && !req->ignore && !p->owner) {
/* This is a new invite */
/* Handle authentication if this is our first invite */
+ struct ast_party_redirecting redirecting = {{0,},};
res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin);
if (res == AUTH_CHALLENGE_SENT) {
p->invitestate = INV_COMPLETED; /* Needs to restart in another INVITE transaction */
@@ -19052,7 +19580,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
return 0;
}
gotdest = get_destination(p, NULL); /* Get destination right away */
- get_rdnis(p, NULL); /* Get redirect information */
+ change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */
extract_uri(p, req); /* Get the Contact URI */
build_contact(p); /* Build our contact header */
@@ -19096,9 +19624,11 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
if (c) {
/* Pre-lock the call */
ast_channel_lock(c);
+ ast_channel_set_redirecting(c, &redirecting);
}
}
} else {
+ struct ast_party_redirecting redirecting = {{0,},};
if (sipdebug) {
if (!req->ignore)
ast_debug(2, "Got a SIP re-invite for call %s\n", p->callid);
@@ -19108,6 +19638,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
if (!req->ignore)
reinvite = 1;
c = p->owner;
+ change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */
+ if (c) {
+ ast_channel_set_redirecting(c, &redirecting);
+ }
}
/* Session-Timers */
@@ -19318,7 +19852,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
c->hangupcause = AST_CAUSE_CALL_REJECTED;
} else {
sip_pvt_unlock(p);
- ast_setstate(c, AST_STATE_DOWN);
c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
}
p->invitestate = INV_COMPLETED;
@@ -19348,7 +19881,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
} else if (p->t38.state == T38_DISABLED) {
/* If this is not a re-invite or something to ignore - it's critical */
ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE:TRUE);
+ transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE : TRUE, FALSE);
}
p->invitestate = INV_TERMINATED;
@@ -19466,6 +19999,8 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *
else
ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
} else {
+ struct ast_party_connected_line connected_caller;
+
/* Transfer succeeded! */
const char *xfersound = pbx_builtin_getvar_helper(target.chan1, "ATTENDED_TRANSFER_COMPLETE_SOUND");
@@ -19480,6 +20015,45 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *
ast_debug(1, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name);
ast_channel_unlock(targetcall_pvt->owner);
}
+
+ if (target.chan2) {
+ if (current->chan2) {
+ /* Tell each of the other channels to whom they are now connected */
+ ast_channel_lock(current->chan2);
+ ast_connected_line_copy_from_caller(&connected_caller, &current->chan2->cid);
+ ast_channel_unlock(current->chan2);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(target.chan2, &connected_caller);
+ ast_channel_lock(target.chan2);
+ ast_connected_line_copy_from_caller(&connected_caller, &target.chan2->cid);
+ ast_channel_unlock(target.chan2);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(current->chan2, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+ } else {
+ /* Notify the first other party that they are connected to someone else assuming that target.chan1
+ has progressed far enough through the dialplan to have it's called party information set. */
+ if (current->chan2) {
+ ast_channel_lock(target.chan1);
+ ast_party_connected_line_copy(&connected_caller, &target.chan1->connected);
+ ast_channel_unlock(target.chan1);
+ connected_caller = target.chan1->connected;
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(current->chan2, &connected_caller);
+ ast_party_connected_line_free(&connected_caller);
+ }
+
+ /* We can't indicate to the called channel directly so we force the masquerade to complete
+ and queue and update to be read and passed-through */
+ ast_channel_lock(target.chan1);
+ ast_do_masquerade(target.chan1);
+ ast_channel_unlock(target.chan1);
+
+ ast_party_connected_line_collect_caller(&connected_caller, &target.chan1->cid);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_queue_connected_line_update(target.chan1, &connected_caller);
+ }
}
if (targetcall_pvt)
ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt");
@@ -20553,10 +21127,10 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so
*/
int ret = 0;
- if (p->ocseq < seqno && seqno != p->lastnoninvite) {
+ if (p->ocseq < seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) {
ast_debug(1, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
ret = -1;
- } else if (p->ocseq != seqno && seqno != p->lastnoninvite) {
+ } else if (p->ocseq != seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) {
/* ignore means "don't do anything with it" but still have to
* respond appropriately.
* But in this case this is a response already, so we really
@@ -22130,7 +22704,16 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID);
} else if (!strcasecmp(v->name, "sendrpid")) {
ast_set_flag(&mask[0], SIP_SENDRPID);
- ast_set2_flag(&flags[0], ast_true(v->value), SIP_SENDRPID);
+ if (!strcasecmp(v->value, "pai")) {
+ ast_set_flag(&flags[0], SIP_SENDRPID_PAI);
+ } else if (!strcasecmp(v->value, "rpid")) {
+ ast_set_flag(&flags[0], SIP_SENDRPID_RPID);
+ } else if (ast_true(v->value)) {
+ ast_set_flag(&flags[0], SIP_SENDRPID_RPID);
+ }
+ } else if (!strcasecmp(v->name, "rpid_immediate")) {
+ ast_set_flag(&mask[1], SIP_PAGE2_RPID_IMMEDIATE);
+ ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RPID_IMMEDIATE);
} else if (!strcasecmp(v->name, "g726nonstandard")) {
ast_set_flag(&mask[0], SIP_G726_NONSTANDARD);
ast_set2_flag(&flags[0], ast_true(v->value), SIP_G726_NONSTANDARD);
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index f4104a89e..588680e3c 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -2516,6 +2516,43 @@ static int skinny_extensionstate_cb(char *context, char *exten, int state, void
return 0;
}
+static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen)
+{
+ struct ast_channel *c = sub->owner;
+ struct skinny_line *l = sub->parent;
+ struct skinny_device *d = l->device;
+
+ if (ast_strlen_zero(c->cid.cid_num) || ast_strlen_zero(c->connected.id.number))
+ return;
+
+ if (sub->owner->_state == AST_STATE_UP) {
+ transmit_callstate(d, l->instance, SKINNY_CONNECTED, sub->callid);
+ transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
+ if (sub->outgoing)
+ transmit_callinfo(d, c->connected.id.name, c->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
+ else
+ transmit_callinfo(d, l->cid_name, l->cid_num, c->connected.id.name, c->connected.id.number, l->instance, sub->callid, 2);
+ } else {
+ if (sub->outgoing) {
+ transmit_callstate(d, l->instance, SKINNY_RINGIN, sub->callid);
+ transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
+ transmit_callinfo(d, c->connected.id.name, c->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
+ } else {
+ if (!sub->ringing) {
+ transmit_callstate(d, l->instance, SKINNY_RINGOUT, sub->callid);
+ transmit_displaypromptstatus(d, "Ring-Out", 0, l->instance, sub->callid);
+ sub->ringing = 1;
+ } else {
+ transmit_callstate(d, l->instance, SKINNY_PROGRESS, sub->callid);
+ transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
+ sub->progress = 1;
+ }
+
+ transmit_callinfo(d, l->cid_name, l->cid_num, c->connected.id.name, c->connected.id.number, l->instance, sub->callid, 2);
+ }
+ }
+}
+
static void mwi_event_cb(const struct ast_event *event, void *userdata)
{
struct skinny_line *l = userdata;
@@ -3610,6 +3647,8 @@ static void *skinny_newcall(void *data)
l->hidecallerid ? "" : l->cid_num,
l->hidecallerid ? "" : l->cid_name,
c->cid.cid_ani ? NULL : l->cid_num);
+ c->connected.id.number = ast_strdup(c->exten);
+ c->connected.id.name = NULL;
ast_setstate(c, AST_STATE_RING);
if (!sub->rtp) {
start_rtp(sub);
@@ -3773,7 +3812,7 @@ static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
transmit_callstateonly(d, sub, SKINNY_RINGIN);
transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
- transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
+ transmit_callinfo(d, ast->connected.id.name, ast->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
transmit_ringer_mode(d, SKINNY_RING_INSIDE);
@@ -3900,7 +3939,7 @@ static int skinny_answer(struct ast_channel *ast)
/* order matters here...
for some reason, transmit_callinfo must be before transmit_callstate,
or you won't get keypad messages in some situations. */
- transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2);
+ transmit_callinfo(d, ast->connected.id.name, ast->connected.id.number, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2);
transmit_callstateonly(d, sub, SKINNY_CONNECTED);
transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
@@ -4095,6 +4134,10 @@ static char *control2str(int ind) {
return "Unhold";
case AST_CONTROL_SRCUPDATE:
return "Media Source Update";
+ case AST_CONTROL_CONNECTED_LINE:
+ return "Connected Line";
+ case AST_CONTROL_REDIRECTING:
+ return "Redirecting";
case -1:
return "Stop tone";
default:
@@ -4202,7 +4245,7 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
transmit_callstateonly(d, sub, SKINNY_RINGOUT);
transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid);
- transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
+ transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, S_OR(ast->connected.id.name, l->lastnumberdialed), S_OR(ast->connected.id.number, l->lastnumberdialed), l->instance, sub->callid, 2); /* 2 = outgoing from phone */
sub->ringing = 1;
if (!d->earlyrtp) {
break;
@@ -4243,7 +4286,7 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
}
transmit_callstateonly(d, sub, SKINNY_PROGRESS);
transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
- transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
+ transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, S_OR(ast->connected.id.name, l->lastnumberdialed), S_OR(ast->connected.id.number, l->lastnumberdialed), l->instance, sub->callid, 2); /* 2 = outgoing from phone */
sub->progress = 1;
if (!d->earlyrtp) {
break;
@@ -4264,6 +4307,9 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
case AST_CONTROL_SRCUPDATE:
ast_rtp_instance_new_source(sub->rtp);
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ update_connectedline(sub, data, datalen);
+ break;
default:
ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
return -1; /* Tell asterisk to provide inband signalling */
diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c
index 1cd94e02f..e4588b368 100644
--- a/channels/chan_unistim.c
+++ b/channels/chan_unistim.c
@@ -3671,16 +3671,16 @@ static int unistim_call(struct ast_channel *ast, char *dest, int timeout)
Sendicon(TEXT_LINE0, FAV_ICON_NONE, session);
if (sub->owner) {
- if (sub->owner->cid.cid_num) {
- send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->cid.cid_num);
- change_callerid(session, 0, sub->owner->cid.cid_num);
+ if (sub->owner->connected.id.number) {
+ send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->connected.id.number);
+ change_callerid(session, 0, sub->owner->connected.id.number);
} else {
send_text(TEXT_LINE1, TEXT_NORMAL, session, DEFAULTCALLERID);
change_callerid(session, 0, DEFAULTCALLERID);
}
- if (sub->owner->cid.cid_name) {
- send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->cid.cid_name);
- change_callerid(session, 1, sub->owner->cid.cid_name);
+ if (sub->owner->connected.id.name) {
+ send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->connected.id.name);
+ change_callerid(session, 1, sub->owner->connected.id.name);
} else {
send_text(TEXT_LINE0, TEXT_NORMAL, session, DEFAULTCALLERNAME);
change_callerid(session, 1, DEFAULTCALLERNAME);
diff --git a/channels/misdn/chan_misdn_config.h b/channels/misdn/chan_misdn_config.h
index c00db864b..d64b8c860 100644
--- a/channels/misdn/chan_misdn_config.h
+++ b/channels/misdn/chan_misdn_config.h
@@ -46,10 +46,16 @@ enum misdn_cfg_elements {
MISDN_CFG_DIALPLAN, /* int */
MISDN_CFG_LOCALDIALPLAN, /* int */
MISDN_CFG_CPNDIALPLAN, /* int */
- MISDN_CFG_NATPREFIX, /* char[] */
- MISDN_CFG_INTERNATPREFIX, /* char[] */
+ MISDN_CFG_TON_PREFIX_UNKNOWN, /* char[] */
+ MISDN_CFG_TON_PREFIX_INTERNATIONAL, /* char[] */
+ MISDN_CFG_TON_PREFIX_NATIONAL, /* char[] */
+ MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC,/* char[] */
+ MISDN_CFG_TON_PREFIX_SUBSCRIBER, /* char[] */
+ MISDN_CFG_TON_PREFIX_ABBREVIATED, /* char[] */
MISDN_CFG_PRES, /* int */
MISDN_CFG_SCREEN, /* int */
+ MISDN_CFG_DISPLAY_CONNECTED, /* int */
+ MISDN_CFG_DISPLAY_SETUP, /* int */
MISDN_CFG_ALWAYS_IMMEDIATE, /* int (bool) */
MISDN_CFG_NODIALTONE, /* int (bool) */
MISDN_CFG_IMMEDIATE, /* int (bool) */
diff --git a/channels/misdn/isdn_lib.c b/channels/misdn/isdn_lib.c
index 071f756eb..d8cf6171a 100644
--- a/channels/misdn/isdn_lib.c
+++ b/channels/misdn/isdn_lib.c
@@ -171,19 +171,24 @@ struct misdn_stack *get_stack_by_bc(struct misdn_bchannel *bc)
void get_show_stack_details(int port, char *buf)
{
- struct misdn_stack *stack=get_misdn_stack();
+ struct misdn_stack *stack = get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- if (stack->port == port) break;
+ for (; stack; stack = stack->next) {
+ if (stack->port == port) {
+ break;
+ }
}
if (stack) {
- sprintf(buf, "* Port %d Type %s Prot. %s L2Link %s L1Link:%s Blocked:%d",
- stack->port, stack->nt ? "NT" : "TE", stack->ptp ? "PTP" : "PMP",
- stack->l2link ? "UP" : "DOWN", stack->l1link ? "UP" : "DOWN",
+ sprintf(buf, "* Port %2d Type %s Prot. %s L2Link %s L1Link:%s Blocked:%d",
+ stack->port,
+ stack->nt ? "NT" : "TE",
+ stack->ptp ? "PTP" : "PMP",
+ stack->l2link ? "UP " : "DOWN",
+ stack->l1link ? "UP " : "DOWN",
stack->blocked);
} else {
- buf[0]=0;
+ buf[0] = 0;
}
}
@@ -644,6 +649,29 @@ static void bc_next_state_change(struct misdn_bchannel *bc, enum bchannel_state
static void empty_bc(struct misdn_bchannel *bc)
{
+ bc->caller.presentation = 0; /* allowed */
+ bc->caller.number_plan = NUMPLAN_ISDN;
+ bc->caller.number_type = NUMTYPE_UNKNOWN;
+ bc->caller.name[0] = 0;
+ bc->caller.number[0] = 0;
+ bc->caller.subaddress[0] = 0;
+
+ bc->connected.presentation = 0; /* allowed */
+ bc->connected.number_plan = NUMPLAN_ISDN;
+ bc->connected.number_type = NUMTYPE_UNKNOWN;
+ bc->connected.name[0] = 0;
+ bc->connected.number[0] = 0;
+ bc->connected.subaddress[0] = 0;
+
+ bc->redirecting.from.presentation = 0; /* allowed */
+ bc->redirecting.from.number_plan = NUMPLAN_ISDN;
+ bc->redirecting.from.number_type = NUMTYPE_UNKNOWN;
+ bc->redirecting.from.name[0] = 0;
+ bc->redirecting.from.number[0] = 0;
+ bc->redirecting.from.subaddress[0] = 0;
+
+ bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
+
bc->dummy=0;
bc->bframe_len=0;
@@ -678,12 +706,6 @@ static void empty_bc(struct misdn_bchannel *bc)
bc->generate_tone=0;
bc->tone_cnt=0;
- bc->dnumplan=NUMPLAN_UNKNOWN;
- bc->onumplan=NUMPLAN_UNKNOWN;
- bc->rnumplan=NUMPLAN_UNKNOWN;
- bc->cpnnumplan=NUMPLAN_UNKNOWN;
-
-
bc->active = 0;
bc->early_bconnect = 1;
@@ -701,7 +723,12 @@ static void empty_bc(struct misdn_bchannel *bc)
bc->cause = AST_CAUSE_NORMAL_CLEARING;
bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
- bc->pres = 0; /* allowed */
+
+ bc->display_connected = 0; /* none */
+ bc->display_setup = 0; /* none */
+
+ bc->presentation = 0; /* allowed */
+ bc->set_presentation = 0;
bc->evq=EVENT_NOTHING;
@@ -719,15 +746,14 @@ static void empty_bc(struct misdn_bchannel *bc)
bc->hdlc=0;
+ bc->dialed.number_plan = NUMPLAN_ISDN;
+ bc->dialed.number_type = NUMTYPE_UNKNOWN;
+ bc->dialed.number[0] = 0;
+ bc->dialed.subaddress[0] = 0;
bc->info_dad[0] = 0;
bc->display[0] = 0;
bc->infos_pending[0] = 0;
- bc->cad[0] = 0;
- bc->oad[0] = 0;
- bc->dad[0] = 0;
- bc->rad[0] = 0;
- bc->orig_dad[0] = 0;
bc->uu[0]=0;
bc->uulen=0;
@@ -929,7 +955,7 @@ static int create_process(int midev, struct misdn_bchannel *bc)
if (stack->procids[proc_id] == 0) {
break;
}
- } /* end for */
+ }
if (proc_id == MAXPROCS) {
cb_log(0, stack->port, "Couldn't Create New ProcId.\n");
return -1;
@@ -1560,7 +1586,14 @@ static int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_
setup_bc(bc);
if ( *bc->crypt_key ) {
- cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad);
+ cb_log(4, stack->port,
+ "ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n",
+ bc->channel,
+ bc->caller.number_type,
+ bc->caller.name,
+ bc->caller.number,
+ bc->dialed.number_type,
+ bc->dialed.number);
manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) );
}
@@ -1582,7 +1615,14 @@ static int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_
case EVENT_CONNECT:
if ( *bc->crypt_key ) {
- cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad);
+ cb_log(4, stack->port,
+ "ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n",
+ bc->channel,
+ bc->caller.number_type,
+ bc->caller.name,
+ bc->caller.number,
+ bc->dialed.number_type,
+ bc->dialed.number);
manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) );
}
case EVENT_ALERTING:
@@ -2454,7 +2494,14 @@ static int handle_bchan(msg_t *msg)
{
unsigned int *cont = (unsigned int *) &frm->data.p;
- cb_log(4, stack->port, "PH_CONTROL: channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad);
+ cb_log(4, stack->port,
+ "PH_CONTROL: channel:%d caller%d:\"%s\" <%s> dialed%d:%s \n",
+ bc->channel,
+ bc->caller.number_type,
+ bc->caller.name,
+ bc->caller.number,
+ bc->dialed.number_type,
+ bc->dialed.number);
if ((*cont & ~DTMF_TONE_MASK) == DTMF_TONE_VAL) {
int dtmf = *cont & DTMF_TONE_MASK;
@@ -3268,10 +3315,6 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
return NULL;
}
-
-
-
-/* ******************************************************************* */
/*!
* \internal
* \brief Convert the facility function enum value into a string.
@@ -3286,14 +3329,8 @@ static const char *fac2str(enum FacFunction facility)
} arr[] = {
/* *INDENT-OFF* */
{ Fac_None, "Fac_None" },
- { Fac_GetSupportedServices, "Fac_GetSupportedServices" },
- { Fac_Listen, "Fac_Listen" },
- { Fac_Suspend, "Fac_Suspend" },
- { Fac_Resume, "Fac_Resume" },
{ Fac_CFActivate, "Fac_CFActivate" },
{ Fac_CFDeactivate, "Fac_CFDeactivate" },
- { Fac_CFInterrogateParameters, "Fac_CFInterrogateParameters" },
- { Fac_CFInterrogateNumbers, "Fac_CFInterrogateNumbers" },
{ Fac_CD, "Fac_CD" },
{ Fac_AOCDCurrency, "Fac_AOCDCurrency" },
{ Fac_AOCDChargingUnit, "Fac_AOCDChargingUnit" },
@@ -3306,10 +3343,10 @@ static const char *fac2str(enum FacFunction facility)
if (arr[index].facility == facility) {
return arr[index].name;
}
- } /* end for */
+ }
return "unknown";
-} /* end fac2str() */
+}
void misdn_lib_log_ies(struct misdn_bchannel *bc)
{
@@ -3321,20 +3358,50 @@ void misdn_lib_log_ies(struct misdn_bchannel *bc)
if (!stack) return;
- cb_log(2, stack->port, " --> channel:%d mode:%s cause:%d ocause:%d rad:%s cad:%s\n", bc->channel, stack->nt?"NT":"TE", bc->cause, bc->out_cause, bc->rad, bc->cad);
+ cb_log(2, stack->port,
+ " --> channel:%d mode:%s cause:%d ocause:%d\n",
+ bc->channel,
+ stack->nt ? "NT" : "TE",
+ bc->cause,
+ bc->out_cause);
+
+ cb_log(2, stack->port,
+ " --> info_dad:%s dialed numtype:%d plan:%d\n",
+ bc->info_dad,
+ bc->dialed.number_type,
+ bc->dialed.number_plan);
+
+ cb_log(2, stack->port,
+ " --> caller:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d\n",
+ bc->caller.name,
+ bc->caller.number,
+ bc->caller.number_type,
+ bc->caller.number_plan,
+ bc->caller.presentation,
+ bc->caller.screening);
+
+ cb_log(2, stack->port,
+ " --> redirecting:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d reason:%d\n",
+ bc->redirecting.from.name,
+ bc->redirecting.from.number,
+ bc->redirecting.from.number_type,
+ bc->redirecting.from.number_plan,
+ bc->redirecting.from.presentation,
+ bc->redirecting.from.screening,
+ bc->redirecting.reason);
cb_log(2, stack->port,
- " --> info_dad:%s onumplan:%c dnumplan:%c rnumplan:%c cpnnumplan:%c\n",
- bc->info_dad,
- bc->onumplan>=0?'0'+bc->onumplan:' ',
- bc->dnumplan>=0?'0'+bc->dnumplan:' ',
- bc->rnumplan>=0?'0'+bc->rnumplan:' ',
- bc->cpnnumplan>=0?'0'+bc->cpnnumplan:' '
- );
+ " --> connected:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d\n",
+ bc->connected.name,
+ bc->connected.number,
+ bc->connected.number_type,
+ bc->connected.number_plan,
+ bc->connected.presentation,
+ bc->connected.screening);
cb_log(3, stack->port, " --> caps:%s pi:%x keypad:%s sending_complete:%d\n", bearer2str(bc->capability),bc->progress_indicator, bc->keypad, bc->sending_complete);
- cb_log(4, stack->port, " --> screen:%d --> pres:%d\n",
- bc->screen, bc->pres);
+
+ cb_log(4, stack->port, " --> set_pres:%d pres:%d\n", bc->set_presentation, bc->presentation);
cb_log(4, stack->port, " --> addr:%x l3id:%x b_stid:%x layer_id:%x\n", bc->addr, bc->l3_id, bc->b_stid, bc->layer_id);
@@ -3373,7 +3440,12 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
stack = get_stack_by_bc(bc);
if (!stack) {
- cb_log(0,bc->port,"SENDEVENT: no Stack for event:%s oad:%s dad:%s \n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad);
+ cb_log(0,bc->port,
+ "SENDEVENT: no Stack for event:%s caller:\"%s\" <%s> dialed:%s \n",
+ isdn_get_info(msgs_g, event, 0),
+ bc->caller.name,
+ bc->caller.number,
+ bc->dialed.number);
RETURN(-1,OUT);
}
@@ -3390,7 +3462,13 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
RETURN(0,OUT);
}
- cb_log(1, stack->port, "I SEND:%s oad:%s dad:%s pid:%d\n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad, bc->pid);
+ cb_log(1, stack->port,
+ "I SEND:%s caller:\"%s\" <%s> dialed:%s pid:%d\n",
+ isdn_get_info(msgs_g, event, 0),
+ bc->caller.name,
+ bc->caller.number,
+ bc->dialed.number,
+ bc->pid);
cb_log(4, stack->port, " --> bc_state:%s\n",bc_state2str(bc->bc_state));
misdn_lib_log_ies(bc);
@@ -3431,7 +3509,14 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
if (misdn_cap_is_speech(bc->capability)) {
if ((event==EVENT_CONNECT)||(event==EVENT_RETRIEVE_ACKNOWLEDGE)) {
if ( *bc->crypt_key ) {
- cb_log(4, stack->port, " --> ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad);
+ cb_log(4, stack->port,
+ " --> ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n",
+ bc->channel,
+ bc->caller.number_type,
+ bc->caller.name,
+ bc->caller.number,
+ bc->dialed.number_type,
+ bc->dialed.number);
manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) );
}
@@ -3571,8 +3656,19 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
/* Later we should think about sending bchannel data directly to misdn. */
msg = isdn_msg_build_event(msgs_g, bc, event, stack->nt);
- msg_queue_tail(&stack->downqueue, msg);
- sem_post(&glob_mgr->new_msg);
+ if (!msg) {
+ /*
+ * The message was not built.
+ *
+ * NOTE: The only time that the message will fail to build
+ * is because the requested FACILITY message is not supported.
+ * A failed malloc() results in exit() being called.
+ */
+ RETURN(-1, OUT);
+ } else {
+ msg_queue_tail(&stack->downqueue, msg);
+ sem_post(&glob_mgr->new_msg);
+ }
OUT:
misdn_send_unlock(bc);
diff --git a/channels/misdn/isdn_lib.h b/channels/misdn/isdn_lib.h
index 638df8a74..ff098c18b 100644
--- a/channels/misdn/isdn_lib.h
+++ b/channels/misdn/isdn_lib.h
@@ -96,15 +96,23 @@ enum misdn_err_e {
ENOCHAN=1
};
-
enum mISDN_NUMBER_PLAN {
- NUMPLAN_UNINITIALIZED=-1,
- NUMPLAN_INTERNATIONAL=0x1,
- NUMPLAN_NATIONAL=0x2,
- NUMPLAN_SUBSCRIBER=0x4,
- NUMPLAN_UNKNOWN=0x0
+ NUMPLAN_UNKNOWN = 0x0,
+ NUMPLAN_ISDN = 0x1, /* ISDN/Telephony numbering plan E.164 */
+ NUMPLAN_DATA = 0x3, /* Data numbering plan X.121 */
+ NUMPLAN_TELEX = 0x4, /* Telex numbering plan F.69 */
+ NUMPLAN_NATIONAL = 0x8,
+ NUMPLAN_PRIVATE = 0x9
};
+enum mISDN_NUMBER_TYPE {
+ NUMTYPE_UNKNOWN = 0x0,
+ NUMTYPE_INTERNATIONAL = 0x1,
+ NUMTYPE_NATIONAL = 0x2,
+ NUMTYPE_NETWORK_SPECIFIC = 0x3,
+ NUMTYPE_SUBSCRIBER = 0x4,
+ NUMTYPE_ABBREVIATED = 0x5
+};
enum event_response_e {
RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE,
@@ -189,6 +197,19 @@ enum { /* progress indicators */
INFO_PI_INTERWORKING_NO_RELEASE_POST_ANSWER =0x13
};
+/*!
+ * \brief Q.931 encoded redirecting reason
+ */
+enum mISDN_REDIRECTING_REASON {
+ mISDN_REDIRECTING_REASON_UNKNOWN = 0x0,
+ mISDN_REDIRECTING_REASON_CALL_FWD_BUSY = 0x1, /* Call forwarding busy or called DTE busy */
+ mISDN_REDIRECTING_REASON_NO_REPLY = 0x2, /* Call forwarding no reply */
+ mISDN_REDIRECTING_REASON_DEFLECTION = 0x4, /* Call deflection */
+ mISDN_REDIRECTING_REASON_OUT_OF_ORDER = 0x9, /* Called DTE out of order */
+ mISDN_REDIRECTING_REASON_CALL_FWD_DTE = 0xA, /* Call forwarding by the called DTE */
+ mISDN_REDIRECTING_REASON_CALL_FWD = 0xF /* Call forwarding unconditional or systematic call redirection */
+};
+
enum { /*CODECS*/
INFO_CODEC_ULAW=2,
INFO_CODEC_ALAW=3
@@ -202,12 +223,81 @@ enum layer_e {
UNKNOWN
};
+/* Maximum phone number (address) length plus null terminator */
+#define MISDN_MAX_NUMBER_LEN (31 + 1)
+
+/* Maximum name length plus null terminator (From ECMA-164) */
+#define MISDN_MAX_NAME_LEN (50 + 1)
+
+/* Maximum subaddress length plus null terminator */
+#define MISDN_MAX_SUBADDRESS_LEN (23 + 1)
+
+/* Maximum keypad facility content length plus null terminator */
+#define MISDN_MAX_KEYPAD_LEN (31 + 1)
+
+/*! \brief Connected-Line/Calling/Redirecting ID info struct */
+struct misdn_party_id {
+ /*! \brief Number presentation restriction code
+ * 0=Allowed, 1=Restricted, 2=Unavailable
+ */
+ int presentation;
+
+ /*! \brief Number screening code
+ * 0=Unscreened, 1=Passed Screen, 2=Failed Screen, 3=Network Number
+ */
+ int screening;
+
+ /*! \brief Type-of-number in ISDN terms for the number */
+ enum mISDN_NUMBER_TYPE number_type;
+
+ /*! \brief Type-of-number numbering plan. */
+ enum mISDN_NUMBER_PLAN number_plan;
+
+ /*! \brief Subscriber Name
+ * \note The name is currently obtained from Asterisk for
+ * potential use in display ie's since basic ISDN does
+ * not support names directly.
+ */
+ char name[MISDN_MAX_NAME_LEN];
+
+ /*! \brief Phone number (Address) */
+ char number[MISDN_MAX_NUMBER_LEN];
+
+ /*! \brief Subaddress number */
+ char subaddress[MISDN_MAX_SUBADDRESS_LEN];
+};
+
+/*! \brief Redirecting information struct */
+struct misdn_party_redirecting {
+ /*! \brief Who is redirecting the call (Sent to the party the call is redirected toward) */
+ struct misdn_party_id from;
+
+ /*! \brief Reason a call is being redirected (Q.931 field value) */
+ enum mISDN_REDIRECTING_REASON reason;
+};
+/*! \brief B channel control structure */
struct misdn_bchannel {
/*! \brief B channel send locking structure */
struct send_lock *send_lock;
+ /*! \brief Originating/Caller ID information struct
+ * \note The number_type element is set to "localdialplan" in /etc/asterisk/misdn.conf for outgoing calls
+ * \note The number element can be set to "callerid" in /etc/asterisk/misdn.conf for outgoing calls
+ */
+ struct misdn_party_id caller;
+
+ /*! \brief Connected-Party/Connected-Line ID information struct
+ * \note The number_type element is set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls
+ */
+ struct misdn_party_id connected;
+
+ /*! \brief Redirecting information struct (Where a call diversion or transfer was invoked)
+ * \note The redirecting subaddress is not defined in Q.931 so it is not used.
+ */
+ struct misdn_party_redirecting redirecting;
+
/*! \brief TRUE if this is a dummy BC record */
int dummy;
@@ -326,26 +416,6 @@ struct misdn_bchannel {
/*! \brief TRUE if we will not use the jitter buffer system */
int nojitter;
- /*! \brief Type-of-number in ISDN terms for the dialed/called number
- * \note This value is set to "dialplan" in /etc/asterisk/misdn.conf for outgoing calls
- */
- enum mISDN_NUMBER_PLAN dnumplan;
-
- /*! \brief Type-of-number in ISDN terms for the redirecting number which a call diversion or transfer was invoked.
- * \note Collected from the incoming SETUP message but not used.
- */
- enum mISDN_NUMBER_PLAN rnumplan;
-
- /*! \brief Type-of-number in ISDN terms for the originating/calling number (Caller-ID)
- * \note This value is set to "localdialplan" in /etc/asterisk/misdn.conf for outgoing calls
- */
- enum mISDN_NUMBER_PLAN onumplan;
-
- /*! \brief Type-of-number in ISDN terms for the connected party number
- * \note This value is set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls
- */
- enum mISDN_NUMBER_PLAN cpnnumplan;
-
/*! \brief Progress Indicator IE coding standard field.
* \note Collected from the incoming messages but not used.
*/
@@ -421,16 +491,38 @@ struct misdn_bchannel {
*/
int stack_holder;
- /*! \brief Caller ID presentation restriction code
+ /*!
+ * \brief Put a display ie in the CONNECT message
+ * \details
+ * Put a display ie in the CONNECT message containing the following
+ * information if it is available (nt port only):
+ * 0 - Do not put the connected line information in the display ie.
+ * 1 - Put the available connected line name in the display ie.
+ * 2 - Put the available connected line number in the display ie.
+ * 3 - Put the available connected line name and number in the display ie.
+ */
+ int display_connected;
+
+ /*!
+ * \brief Put a display ie in the SETUP message
+ * \details
+ * Put a display ie in the SETUP message containing the following
+ * information if it is available (nt port only):
+ * 0 - Do not put the caller information in the display ie.
+ * 1 - Put the available caller name in the display ie.
+ * 2 - Put the available caller number in the display ie.
+ * 3 - Put the available caller name and number in the display ie.
+ */
+ int display_setup;
+
+ /*! \brief User set presentation restriction code
* 0=Allowed, 1=Restricted, 2=Unavailable
* \note It is settable by the misdn_set_opt() application.
*/
- int pres;
+ int presentation;
- /*! \brief Caller ID screening code
- * 0=Unscreened, 1=Passed Screen, 2=Failed Screen, 3=Network Number
- */
- int screen;
+ /*! \brief TRUE if the user set the presentation restriction code */
+ int set_presentation;
/*! \brief SETUP message bearer capability field code value */
int capability;
@@ -462,6 +554,23 @@ struct misdn_bchannel {
int hdlc;
/* V110 */
+ /*! \brief Dialed/Called information struct */
+ struct {
+ /*! \brief Type-of-number in ISDN terms for the dialed/called number
+ * \note This value is set to "dialplan" in /etc/asterisk/misdn.conf for outgoing calls
+ */
+ enum mISDN_NUMBER_TYPE number_type;
+
+ /*! \brief Type-of-number numbering plan. */
+ enum mISDN_NUMBER_PLAN number_plan;
+
+ /*! \brief Dialed/Called Phone Number (Address) */
+ char number[MISDN_MAX_NUMBER_LEN];
+
+ /*! \brief Dialed/Called Subaddress number */
+ char subaddress[MISDN_MAX_SUBADDRESS_LEN];
+ } dialed;
+
/*! \brief Display message that can be displayed by the user phone.
* \note Maximum displayable length is 34 or 82 octets.
* It is also settable by the misdn_set_opt() application.
@@ -469,39 +578,20 @@ struct misdn_bchannel {
char display[84];
/*! \brief Not used. Contents are setup but not used. */
- char msn[32];
-
- /*! \brief Originating/Calling Phone Number (Address)
- * \note This value can be set to "callerid" in /etc/asterisk/misdn.conf for outgoing calls
- */
- char oad[32];
-
- /*! \brief Redirecting Phone Number (Address) where a call diversion or transfer was invoked */
- char rad[32];
-
- /*! \brief Dialed/Called Phone Number (Address) */
- char dad[32];
-
- /*! \brief Connected Party/Line Phone Number (Address) */
- char cad[32];
-
- /*! \brief Original Dialed/Called Phone Number (Address) before national/international dialing prefix added.
- * \note Not used. Contents are setup but not used.
- */
- char orig_dad[32];
+ char msn[MISDN_MAX_NUMBER_LEN];
/*! \brief Q.931 Keypad Facility IE contents
* \note Contents exported and imported to Asterisk variable MISDN_KEYPAD
*/
- char keypad[32];
+ char keypad[MISDN_MAX_KEYPAD_LEN];
/*! \brief Current overlap dialing digits to/from INFORMATION messages */
- char info_dad[64];
+ char info_dad[MISDN_MAX_NUMBER_LEN];
/*! \brief Collected digits to go into info_dad[] while waiting for a SETUP_ACKNOWLEDGE to come in. */
- char infos_pending[64];
+ char infos_pending[MISDN_MAX_NUMBER_LEN];
-/* unsigned char info_keypad[32]; */
+/* unsigned char info_keypad[MISDN_MAX_KEYPAD_LEN]; */
/* unsigned char clisub[24]; */
/* unsigned char cldsub[24]; */
diff --git a/channels/misdn/isdn_lib_intern.h b/channels/misdn/isdn_lib_intern.h
index a4ddc7a49..3347fe335 100644
--- a/channels/misdn/isdn_lib_intern.h
+++ b/channels/misdn/isdn_lib_intern.h
@@ -41,7 +41,6 @@ struct send_lock {
struct isdn_msg {
unsigned long misdn_msg;
- enum layer_e layer;
enum event_e event;
void (*msg_parser)(struct isdn_msg *msgs, msg_t *msg, struct misdn_bchannel *bc, int nt);
diff --git a/channels/misdn/isdn_msg_parser.c b/channels/misdn/isdn_msg_parser.c
index 6c4272ea0..01c084ff7 100644
--- a/channels/misdn/isdn_msg_parser.c
+++ b/channels/misdn/isdn_msg_parser.c
@@ -25,6 +25,42 @@
#include "ie.c"
+/*!
+ * \internal
+ * \brief Build the name, number, name/number display message string
+ *
+ * \param display Display buffer to fill in
+ * \param display_length Length of the display buffer to fill in
+ * \param display_format Display format enumeration
+ * \param name Name string to use
+ * \param number Number string to use
+ *
+ * \return Nothing
+ */
+static void build_display_str(char *display, size_t display_length, int display_format, const char *name, const char *number)
+{
+ display[0] = 0;
+ switch (display_format) {
+ default:
+ case 0: /* none */
+ break;
+
+ case 1: /* name */
+ snprintf(display, display_length, "%s", name);
+ break;
+
+ case 2: /* number */
+ snprintf(display, display_length, "%s", number);
+ break;
+
+ case 3: /* both */
+ if (name[0] || number[0]) {
+ snprintf(display, display_length, "\"%s\" <%s>", name, number);
+ }
+ break;
+ }
+}
+
static void set_channel(struct misdn_bchannel *bc, int channel)
{
@@ -161,62 +197,74 @@ static void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchann
int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
SETUP_t *setup= (SETUP_t*)((unsigned long)msg->data+HEADER_LEN);
Q931_info_t *qi=(Q931_info_t*)((unsigned long)msg->data+HEADER_LEN);
+ int type;
+ int plan;
+ int present;
+ int screen;
+ int reason;
#ifdef DEBUG
printf("Parsing SETUP Msg\n");
#endif
- {
- int type,plan,present, screen;
- char id[32];
- dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, id, sizeof(id)-1, nt,bc);
-
- bc->onumplan=type;
- strcpy(bc->oad, id);
- switch (present) {
- case 0:
- bc->pres=0; /* screened */
- break;
- case 1:
- bc->pres=1; /* not screened */
- break;
- default:
- bc->pres=0;
- }
- switch (screen) {
- case 0:
- break;
- default:
- ;
- }
- }
- {
- int type, plan;
- char number[32];
- dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *)setup, &type, &plan, number, sizeof(number)-1, nt,bc);
- strcpy(bc->dad, number);
- bc->dnumplan=type;
+
+ dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, bc->caller.number, sizeof(bc->caller.number) - 1, nt, bc);
+ bc->caller.number_type = type;
+ bc->caller.number_plan = plan;
+ switch (present) {
+ default:
+ case 0:
+ bc->caller.presentation = 0; /* presentation allowed */
+ break;
+ case 1:
+ bc->caller.presentation = 1; /* presentation restricted */
+ break;
+ case 2:
+ bc->caller.presentation = 2; /* Number not available */
+ break;
}
- {
- char keypad[32];
- dec_ie_keypad(setup->KEYPAD, (Q931_info_t *)setup, keypad, sizeof(keypad)-1, nt,bc);
- strcpy(bc->keypad, keypad);
+ if (0 <= screen) {
+ bc->caller.screening = screen;
+ } else {
+ bc->caller.screening = 0; /* Unscreened */
}
- {
- dec_ie_complete(setup->COMPLETE, (Q931_info_t *)setup, &bc->sending_complete, nt,bc);
-
+ dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *) setup, &type, &plan, bc->dialed.number, sizeof(bc->dialed.number) - 1, nt, bc);
+ bc->dialed.number_type = type;
+ bc->dialed.number_plan = plan;
+
+ dec_ie_keypad(setup->KEYPAD, (Q931_info_t *) setup, bc->keypad, sizeof(bc->keypad) - 1, nt, bc);
+
+ dec_ie_complete(setup->COMPLETE, (Q931_info_t *) setup, &bc->sending_complete, nt, bc);
+
+ dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *) setup, &type, &plan, &present, &screen, &reason, bc->redirecting.from.number, sizeof(bc->redirecting.from.number) - 1, nt, bc);
+ bc->redirecting.from.number_type = type;
+ bc->redirecting.from.number_plan = plan;
+ switch (present) {
+ default:
+ case 0:
+ bc->redirecting.from.presentation = 0; /* presentation allowed */
+ break;
+ case 1:
+ bc->redirecting.from.presentation = 1; /* presentation restricted */
+ break;
+ case 2:
+ bc->redirecting.from.presentation = 2; /* Number not available */
+ break;
}
-
- {
- int type, plan, present, screen, reason;
- char id[32];
- dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *)setup, &type, &plan, &present, &screen, &reason, id, sizeof(id)-1, nt,bc);
-
- strcpy(bc->rad, id);
- bc->rnumplan=type;
+ if (0 <= screen) {
+ bc->redirecting.from.screening = screen;
+ } else {
+ bc->redirecting.from.screening = 0; /* Unscreened */
+ }
+ if (0 <= reason) {
+ bc->redirecting.reason = reason;
+ } else {
+ bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
}
+
{
int coding, capability, mode, rate, multi, user, async, urate, stopbits, dbits, parity;
+
dec_ie_bearer(setup->BEARER, (Q931_info_t *)setup, &coding, &capability, &mode, &rate, &multi, &user, &async, &urate, &stopbits, &dbits, &parity, nt,bc);
switch (capability) {
case -1: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
@@ -271,7 +319,7 @@ static void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchann
}
-#define ANY_CHANNEL 0xff /* IE attribut for 'any channel' */
+#define ANY_CHANNEL 0xff /* IE attribute for 'any channel' */
static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
{
int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
@@ -286,35 +334,43 @@ static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, in
enc_ie_channel_id(&setup->CHANNEL_ID, msg, 1, bc->channel, nt,bc);
- {
- int type=bc->onumplan,plan=1,present=bc->pres,screen=bc->screen;
- enc_ie_calling_pn(&setup->CALLING_PN, msg, type, plan, present,
- screen, bc->oad, nt, bc);
- }
+ enc_ie_calling_pn(&setup->CALLING_PN, msg, bc->caller.number_type, bc->caller.number_plan,
+ bc->caller.presentation, bc->caller.screening, bc->caller.number, nt, bc);
- {
- if (bc->dad[0])
- enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dnumplan, 1, bc->dad, nt,bc);
+ if (bc->dialed.number[0]) {
+ enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dialed.number_type, bc->dialed.number_plan, bc->dialed.number, nt, bc);
}
- {
- if (bc->rad[0])
- enc_ie_redir_nr(&setup->REDIR_NR, msg, 1, 1, bc->pres, bc->screen, 0, bc->rad, nt,bc);
+ if (bc->redirecting.from.number[0]) {
+ enc_ie_redir_nr(&setup->REDIR_NR, msg, bc->redirecting.from.number_type, bc->redirecting.from.number_plan,
+ bc->redirecting.from.presentation, bc->redirecting.from.screening, bc->redirecting.reason,
+ bc->redirecting.from.number, nt, bc);
}
- {
- if (bc->keypad[0])
- enc_ie_keypad(&setup->KEYPAD, msg, bc->keypad, nt,bc);
+ if (bc->keypad[0]) {
+ enc_ie_keypad(&setup->KEYPAD, msg, bc->keypad, nt,bc);
}
+
if (*bc->display) {
- enc_ie_display(&setup->DISPLAY, msg, bc->display, nt,bc);
+ enc_ie_display(&setup->DISPLAY, msg, bc->display, nt, bc);
+ } else if (nt && bc->caller.presentation == 0) {
+ char display[sizeof(bc->display)];
+
+ /* Presentation is allowed */
+ build_display_str(display, sizeof(display), bc->display_setup, bc->caller.name, bc->caller.number);
+ if (display[0]) {
+ enc_ie_display(&setup->DISPLAY, msg, display, nt, bc);
+ }
}
{
- int coding=0, capability, mode=0 /* 2 for packet ! */
- ,user, rate=0x10;
+ int coding = 0;
+ int capability;
+ int mode = 0; /* 2 for packet! */
+ int user;
+ int rate = 0x10;
switch (bc->law) {
case INFO_CODEC_ULAW: user=2;
@@ -340,8 +396,6 @@ static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, in
capability=bc->capability;
}
-
-
enc_ie_bearer(&setup->BEARER, msg, coding, capability, mode, rate, -1, user, nt,bc);
}
@@ -365,15 +419,36 @@ static void parse_connect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bcha
{
int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
CONNECT_t *connect=(CONNECT_t*)((unsigned long)(msg->data+HEADER_LEN));
+ int type;
+ int plan;
+ int pres;
+ int screen;
- int plan,pres,screen;
-
- bc->ces = connect->ces;
bc->ces = connect->ces;
dec_ie_progress(connect->PROGRESS, (Q931_info_t *)connect, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
- dec_ie_connected_pn(connect->CONNECT_PN,(Q931_info_t *)connect, &bc->cpnnumplan, &plan, &pres, &screen, bc->cad, 31, nt, bc);
+ dec_ie_connected_pn(connect->CONNECT_PN, (Q931_info_t *) connect, &type, &plan,
+ &pres, &screen, bc->connected.number, sizeof(bc->connected.number) - 1, nt, bc);
+ bc->connected.number_type = type;
+ bc->connected.number_plan = plan;
+ switch (pres) {
+ default:
+ case 0:
+ bc->connected.presentation = 0; /* presentation allowed */
+ break;
+ case 1:
+ bc->connected.presentation = 1; /* presentation restricted */
+ break;
+ case 2:
+ bc->connected.presentation = 2; /* Number not available */
+ break;
+ }
+ if (0 <= screen) {
+ bc->connected.screening = screen;
+ } else {
+ bc->connected.screening = 0; /* Unscreened */
+ }
/*
cb_log(1,bc->port,"CONNETED PN: %s cpn_dialplan:%d\n", connected_pn, type);
@@ -400,9 +475,17 @@ static msg_t *build_connect (struct isdn_msg msgs[], struct misdn_bchannel *bc,
enc_ie_date(&connect->DATE, msg, now, nt,bc);
}
- {
- int type=bc->cpnnumplan, plan=1, present=2, screen=0;
- enc_ie_connected_pn(&connect->CONNECT_PN, msg, type,plan, present, screen, bc->cad, nt , bc);
+ enc_ie_connected_pn(&connect->CONNECT_PN, msg, bc->connected.number_type, bc->connected.number_plan,
+ bc->connected.presentation, bc->connected.screening, bc->connected.number, nt, bc);
+
+ if (nt && bc->connected.presentation == 0) {
+ char display[sizeof(bc->display)];
+
+ /* Presentation is allowed */
+ build_display_str(display, sizeof(display), bc->display_connected, bc->connected.name, bc->connected.number);
+ if (display[0]) {
+ enc_ie_display(&connect->DISPLAY, msg, display, nt, bc);
+ }
}
#ifdef DEBUG
@@ -982,12 +1065,12 @@ static void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bch
static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
{
- int len,
- HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN;
- unsigned char *ie_fac,
- fac_tmp[256];
- msg_t *msg =(msg_t*)create_l3msg(CC_FACILITY | REQUEST, MT_FACILITY, bc?bc->l3_id:-1, sizeof(FACILITY_t) ,nt);
- FACILITY_t *facility = (FACILITY_t*)(msg->data+HEADER_LEN);
+ int len;
+ int HEADER_LEN;
+ unsigned char *ie_fac;
+ unsigned char fac_tmp[256];
+ msg_t *msg;
+ FACILITY_t *facility;
Q931_info_t *qi;
#ifdef DEBUG
@@ -995,8 +1078,14 @@ static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc,
#endif
len = encodeFac(fac_tmp, &(bc->fac_out));
- if (len <= 0)
+ if (len <= 0) {
+ /* mISDN does not know how to build the requested facility structure */
return NULL;
+ }
+
+ msg = (msg_t *) create_l3msg(CC_FACILITY | REQUEST, MT_FACILITY, bc ? bc->l3_id : -1, sizeof(FACILITY_t), nt);
+ HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN;
+ facility = (FACILITY_t *) (msg->data + HEADER_LEN);
ie_fac = msg_put(msg, len);
if (bc->nt) {
@@ -1009,7 +1098,9 @@ static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc,
memcpy(ie_fac, fac_tmp, len);
if (*bc->display) {
+#ifdef DEBUG
printf("Sending %s as Display\n", bc->display);
+#endif
enc_ie_display(&facility->DISPLAY, msg, bc->display, nt,bc);
}
@@ -1062,15 +1153,11 @@ static void parse_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_
{
int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
INFORMATION_t *information=(INFORMATION_t*)((unsigned long)(msg->data+HEADER_LEN));
- {
- int type, plan;
- char number[32];
- char keypad[32];
- dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *)information, &type, &plan, number, sizeof(number)-1, nt, bc);
- dec_ie_keypad(information->KEYPAD, (Q931_info_t *)information, keypad, sizeof(keypad)-1, nt, bc);
- strcpy(bc->info_dad, number);
- strcpy(bc->keypad,keypad);
- }
+ int type, plan;
+
+ dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *) information, &type, &plan, bc->info_dad, sizeof(bc->info_dad) - 1, nt, bc);
+ dec_ie_keypad(information->KEYPAD, (Q931_info_t *) information, bc->keypad, sizeof(bc->keypad) - 1, nt, bc);
+
#ifdef DEBUG
printf("Parsing INFORMATION Msg\n");
#endif
@@ -1084,13 +1171,13 @@ static msg_t *build_information (struct isdn_msg msgs[], struct misdn_bchannel *
information=(INFORMATION_t*)((msg->data+HEADER_LEN));
- {
- enc_ie_called_pn(&information->CALLED_PN, msg, 0, 1, bc->info_dad, nt,bc);
- }
+ enc_ie_called_pn(&information->CALLED_PN, msg, 0, 1, bc->info_dad, nt,bc);
{
if (*bc->display) {
+#ifdef DEBUG
printf("Sending %s as Display\n", bc->display);
+#endif
enc_ie_display(&information->DISPLAY, msg, bc->display, nt,bc);
}
}
@@ -1110,7 +1197,6 @@ static void parse_status (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchan
dec_ie_cause(status->CAUSE, (Q931_info_t *)(status), &location, &cause, nt,bc);
if (cause>0) bc->cause=cause;
- ;
#ifdef DEBUG
printf("Parsing STATUS Msg\n");
@@ -1161,97 +1247,40 @@ static msg_t *build_timeout (struct isdn_msg msgs[], struct misdn_bchannel *bc,
/** Msg Array **/
struct isdn_msg msgs_g[] = {
- {CC_PROCEEDING,L3,EVENT_PROCEEDING,
- parse_proceeding,build_proceeding,
- "PROCEEDING"},
- {CC_ALERTING,L3,EVENT_ALERTING,
- parse_alerting,build_alerting,
- "ALERTING"},
- {CC_PROGRESS,L3,EVENT_PROGRESS,
- parse_progress,build_progress,
- "PROGRESS"},
- {CC_SETUP,L3,EVENT_SETUP,
- parse_setup,build_setup,
- "SETUP"},
- {CC_CONNECT,L3,EVENT_CONNECT,
- parse_connect,build_connect,
- "CONNECT"},
- {CC_SETUP_ACKNOWLEDGE,L3,EVENT_SETUP_ACKNOWLEDGE,
- parse_setup_acknowledge,build_setup_acknowledge,
- "SETUP_ACKNOWLEDGE"},
- {CC_CONNECT_ACKNOWLEDGE ,L3,EVENT_CONNECT_ACKNOWLEDGE ,
- parse_connect_acknowledge ,build_connect_acknowledge,
- "CONNECT_ACKNOWLEDGE "},
- {CC_USER_INFORMATION,L3,EVENT_USER_INFORMATION,
- parse_user_information,build_user_information,
- "USER_INFORMATION"},
- {CC_SUSPEND_REJECT,L3,EVENT_SUSPEND_REJECT,
- parse_suspend_reject,build_suspend_reject,
- "SUSPEND_REJECT"},
- {CC_RESUME_REJECT,L3,EVENT_RESUME_REJECT,
- parse_resume_reject,build_resume_reject,
- "RESUME_REJECT"},
- {CC_HOLD,L3,EVENT_HOLD,
- parse_hold,build_hold,
- "HOLD"},
- {CC_SUSPEND,L3,EVENT_SUSPEND,
- parse_suspend,build_suspend,
- "SUSPEND"},
- {CC_RESUME,L3,EVENT_RESUME,
- parse_resume,build_resume,
- "RESUME"},
- {CC_HOLD_ACKNOWLEDGE,L3,EVENT_HOLD_ACKNOWLEDGE,
- parse_hold_acknowledge,build_hold_acknowledge,
- "HOLD_ACKNOWLEDGE"},
- {CC_SUSPEND_ACKNOWLEDGE,L3,EVENT_SUSPEND_ACKNOWLEDGE,
- parse_suspend_acknowledge,build_suspend_acknowledge,
- "SUSPEND_ACKNOWLEDGE"},
- {CC_RESUME_ACKNOWLEDGE,L3,EVENT_RESUME_ACKNOWLEDGE,
- parse_resume_acknowledge,build_resume_acknowledge,
- "RESUME_ACKNOWLEDGE"},
- {CC_HOLD_REJECT,L3,EVENT_HOLD_REJECT,
- parse_hold_reject,build_hold_reject,
- "HOLD_REJECT"},
- {CC_RETRIEVE,L3,EVENT_RETRIEVE,
- parse_retrieve,build_retrieve,
- "RETRIEVE"},
- {CC_RETRIEVE_ACKNOWLEDGE,L3,EVENT_RETRIEVE_ACKNOWLEDGE,
- parse_retrieve_acknowledge,build_retrieve_acknowledge,
- "RETRIEVE_ACKNOWLEDGE"},
- {CC_RETRIEVE_REJECT,L3,EVENT_RETRIEVE_REJECT,
- parse_retrieve_reject,build_retrieve_reject,
- "RETRIEVE_REJECT"},
- {CC_DISCONNECT,L3,EVENT_DISCONNECT,
- parse_disconnect,build_disconnect,
- "DISCONNECT"},
- {CC_RESTART,L3,EVENT_RESTART,
- parse_restart,build_restart,
- "RESTART"},
- {CC_RELEASE,L3,EVENT_RELEASE,
- parse_release,build_release,
- "RELEASE"},
- {CC_RELEASE_COMPLETE,L3,EVENT_RELEASE_COMPLETE,
- parse_release_complete,build_release_complete,
- "RELEASE_COMPLETE"},
- {CC_FACILITY,L3,EVENT_FACILITY,
- parse_facility,build_facility,
- "FACILITY"},
- {CC_NOTIFY,L3,EVENT_NOTIFY,
- parse_notify,build_notify,
- "NOTIFY"},
- {CC_STATUS_ENQUIRY,L3,EVENT_STATUS_ENQUIRY,
- parse_status_enquiry,build_status_enquiry,
- "STATUS_ENQUIRY"},
- {CC_INFORMATION,L3,EVENT_INFORMATION,
- parse_information,build_information,
- "INFORMATION"},
- {CC_STATUS,L3,EVENT_STATUS,
- parse_status,build_status,
- "STATUS"},
- {CC_TIMEOUT,L3,EVENT_TIMEOUT,
- parse_timeout,build_timeout,
- "TIMEOUT"},
- {0,0,0,NULL,NULL,NULL}
+/* *INDENT-OFF* */
+ /* misdn_msg, event, msg_parser, msg_builder, info */
+ { CC_PROCEEDING, EVENT_PROCEEDING, parse_proceeding, build_proceeding, "PROCEEDING" },
+ { CC_ALERTING, EVENT_ALERTING, parse_alerting, build_alerting, "ALERTING" },
+ { CC_PROGRESS, EVENT_PROGRESS, parse_progress, build_progress, "PROGRESS" },
+ { CC_SETUP, EVENT_SETUP, parse_setup, build_setup, "SETUP" },
+ { CC_CONNECT, EVENT_CONNECT, parse_connect, build_connect, "CONNECT" },
+ { CC_SETUP_ACKNOWLEDGE, EVENT_SETUP_ACKNOWLEDGE, parse_setup_acknowledge, build_setup_acknowledge, "SETUP_ACKNOWLEDGE" },
+ { CC_CONNECT_ACKNOWLEDGE, EVENT_CONNECT_ACKNOWLEDGE, parse_connect_acknowledge, build_connect_acknowledge, "CONNECT_ACKNOWLEDGE " },
+ { CC_USER_INFORMATION, EVENT_USER_INFORMATION, parse_user_information, build_user_information, "USER_INFORMATION" },
+ { CC_SUSPEND_REJECT, EVENT_SUSPEND_REJECT, parse_suspend_reject, build_suspend_reject, "SUSPEND_REJECT" },
+ { CC_RESUME_REJECT, EVENT_RESUME_REJECT, parse_resume_reject, build_resume_reject, "RESUME_REJECT" },
+ { CC_HOLD, EVENT_HOLD, parse_hold, build_hold, "HOLD" },
+ { CC_SUSPEND, EVENT_SUSPEND, parse_suspend, build_suspend, "SUSPEND" },
+ { CC_RESUME, EVENT_RESUME, parse_resume, build_resume, "RESUME" },
+ { CC_HOLD_ACKNOWLEDGE, EVENT_HOLD_ACKNOWLEDGE, parse_hold_acknowledge, build_hold_acknowledge, "HOLD_ACKNOWLEDGE" },
+ { CC_SUSPEND_ACKNOWLEDGE, EVENT_SUSPEND_ACKNOWLEDGE, parse_suspend_acknowledge, build_suspend_acknowledge, "SUSPEND_ACKNOWLEDGE" },
+ { CC_RESUME_ACKNOWLEDGE, EVENT_RESUME_ACKNOWLEDGE, parse_resume_acknowledge, build_resume_acknowledge, "RESUME_ACKNOWLEDGE" },
+ { CC_HOLD_REJECT, EVENT_HOLD_REJECT, parse_hold_reject, build_hold_reject, "HOLD_REJECT" },
+ { CC_RETRIEVE, EVENT_RETRIEVE, parse_retrieve, build_retrieve, "RETRIEVE" },
+ { CC_RETRIEVE_ACKNOWLEDGE, EVENT_RETRIEVE_ACKNOWLEDGE, parse_retrieve_acknowledge, build_retrieve_acknowledge, "RETRIEVE_ACKNOWLEDGE" },
+ { CC_RETRIEVE_REJECT, EVENT_RETRIEVE_REJECT, parse_retrieve_reject, build_retrieve_reject, "RETRIEVE_REJECT" },
+ { CC_DISCONNECT, EVENT_DISCONNECT, parse_disconnect, build_disconnect, "DISCONNECT" },
+ { CC_RESTART, EVENT_RESTART, parse_restart, build_restart, "RESTART" },
+ { CC_RELEASE, EVENT_RELEASE, parse_release, build_release, "RELEASE" },
+ { CC_RELEASE_COMPLETE, EVENT_RELEASE_COMPLETE, parse_release_complete, build_release_complete, "RELEASE_COMPLETE" },
+ { CC_FACILITY, EVENT_FACILITY, parse_facility, build_facility, "FACILITY" },
+ { CC_NOTIFY, EVENT_NOTIFY, parse_notify, build_notify, "NOTIFY" },
+ { CC_STATUS_ENQUIRY, EVENT_STATUS_ENQUIRY, parse_status_enquiry, build_status_enquiry, "STATUS_ENQUIRY" },
+ { CC_INFORMATION, EVENT_INFORMATION, parse_information, build_information, "INFORMATION" },
+ { CC_STATUS, EVENT_STATUS, parse_status, build_status, "STATUS" },
+ { CC_TIMEOUT, EVENT_TIMEOUT, parse_timeout, build_timeout, "TIMEOUT" },
+ { 0, 0, NULL, NULL, NULL }
+/* *INDENT-ON* */
};
#define msgs_max (sizeof(msgs_g)/sizeof(struct isdn_msg))
diff --git a/channels/misdn_config.c b/channels/misdn_config.c
index f447c5c21..444b939f2 100644
--- a/channels/misdn_config.c
+++ b/channels/misdn_config.c
@@ -132,7 +132,7 @@ static const struct misdn_cfg_spec port_spec[] = {
{ "musicclass", MISDN_CFG_MUSICCLASS, MISDN_CTYPE_STR, "default", NONE,
"Sets the musiconhold class." },
{ "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE,
- "Sets the caller ID." },
+ "Set the outgoing caller id to the value." },
{ "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE,
"Set the method to use for channel selection:\n"
"\t standard - Use the first free channel starting from the lowest number.\n"
@@ -140,62 +140,71 @@ static const struct misdn_cfg_spec port_spec[] = {
"\t round_robin - Use the round robin algorithm to select a channel. Use this\n"
"\t if you want to balance your load." },
{ "dialplan", MISDN_CFG_DIALPLAN, MISDN_CTYPE_INT, "0", NONE,
- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
- "\n"
+ "Dialplan means Type Of Number in ISDN Terms\n"
"\tThere are different types of the dialplan:\n"
"\n"
- "\tdialplan -> outgoing Number\n"
- "\tlocaldialplan -> callerid\n"
- "\tcpndialplan -> connected party number\n"
+ "\tdialplan -> for outgoing call's dialed number\n"
+ "\tlocaldialplan -> for outgoing call's callerid\n"
+ "\t (if -1 is set use the value from the asterisk channel)\n"
+ "\tcpndialplan -> for incoming call's connected party number sent to caller\n"
+ "\t (if -1 is set use the value from the asterisk channel)\n"
"\n"
"\tdialplan options:\n"
"\n"
"\t0 - unknown\n"
"\t1 - International\n"
"\t2 - National\n"
- "\t4 - Subscriber\n"
- "\n"
- "\tThis setting is used for outgoing calls." },
+ "\t4 - Subscriber" },
{ "localdialplan", MISDN_CFG_LOCALDIALPLAN, MISDN_CTYPE_INT, "0", NONE,
- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
- "\n"
+ "Dialplan means Type Of Number in ISDN Terms\n"
"\tThere are different types of the dialplan:\n"
"\n"
- "\tdialplan -> outgoing Number\n"
- "\tlocaldialplan -> callerid\n"
- "\tcpndialplan -> connected party number\n"
+ "\tdialplan -> for outgoing call's dialed number\n"
+ "\tlocaldialplan -> for outgoing call's callerid\n"
+ "\t (if -1 is set use the value from the asterisk channel)\n"
+ "\tcpndialplan -> for incoming call's connected party number sent to caller\n"
+ "\t (if -1 is set use the value from the asterisk channel)\n"
"\n"
"\tdialplan options:\n"
"\n"
"\t0 - unknown\n"
"\t1 - International\n"
"\t2 - National\n"
- "\t4 - Subscriber\n"
- "\n"
- "\tThis setting is used for outgoing calls." },
+ "\t4 - Subscriber" },
{ "cpndialplan", MISDN_CFG_CPNDIALPLAN, MISDN_CTYPE_INT, "0", NONE,
- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
- "\n"
+ "Dialplan means Type Of Number in ISDN Terms\n"
"\tThere are different types of the dialplan:\n"
"\n"
- "\tdialplan -> outgoing Number\n"
- "\tlocaldialplan -> callerid\n"
- "\tcpndialplan -> connected party number\n"
+ "\tdialplan -> for outgoing call's dialed number\n"
+ "\tlocaldialplan -> for outgoing call's callerid\n"
+ "\t (if -1 is set use the value from the asterisk channel)\n"
+ "\tcpndialplan -> for incoming call's connected party number sent to caller\n"
+ "\t (if -1 is set use the value from the asterisk channel)\n"
"\n"
"\tdialplan options:\n"
"\n"
"\t0 - unknown\n"
"\t1 - International\n"
"\t2 - National\n"
- "\t4 - Subscriber\n"
- "\n"
- "\tThis setting is used for outgoing calls." },
- { "nationalprefix", MISDN_CFG_NATPREFIX, MISDN_CTYPE_STR, "0", NONE,
- "Prefix for national, this is put before the\n"
- "\toad if an according dialplan is set by the other end." },
- { "internationalprefix", MISDN_CFG_INTERNATPREFIX, MISDN_CTYPE_STR, "00", NONE,
- "Prefix for international, this is put before the\n"
- "\toad if an according dialplan is set by the other end." },
+ "\t4 - Subscriber" },
+ { "unknownprefix", MISDN_CFG_TON_PREFIX_UNKNOWN, MISDN_CTYPE_STR, "", NONE,
+ "Prefix for unknown numbers, this is put before an incoming number\n"
+ "\tif its type-of-number is unknown." },
+ { "internationalprefix", MISDN_CFG_TON_PREFIX_INTERNATIONAL, MISDN_CTYPE_STR, "00", NONE,
+ "Prefix for international numbers, this is put before an incoming number\n"
+ "\tif its type-of-number is international." },
+ { "nationalprefix", MISDN_CFG_TON_PREFIX_NATIONAL, MISDN_CTYPE_STR, "0", NONE,
+ "Prefix for national numbers, this is put before an incoming number\n"
+ "\tif its type-of-number is national." },
+ { "netspecificprefix", MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC, MISDN_CTYPE_STR, "", NONE,
+ "Prefix for network-specific numbers, this is put before an incoming number\n"
+ "\tif its type-of-number is network-specific." },
+ { "subscriberprefix", MISDN_CFG_TON_PREFIX_SUBSCRIBER, MISDN_CTYPE_STR, "", NONE,
+ "Prefix for subscriber numbers, this is put before an incoming number\n"
+ "\tif its type-of-number is subscriber." },
+ { "abbreviatedprefix", MISDN_CFG_TON_PREFIX_ABBREVIATED, MISDN_CTYPE_STR, "", NONE,
+ "Prefix for abbreviated numbers, this is put before an incoming number\n"
+ "\tif its type-of-number is abbreviated." },
{ "presentation", MISDN_CFG_PRES, MISDN_CTYPE_INT, "-1", NONE,
"These (presentation and screen) are the exact isdn screening and presentation\n"
"\tindicators.\n"
@@ -212,6 +221,22 @@ static const struct misdn_cfg_spec port_spec[] = {
"\n"
"\tscreen=0, presentation=0 -> callerid presented\n"
"\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" },
+ { "display_connected", MISDN_CFG_DISPLAY_CONNECTED, MISDN_CTYPE_INT, "0", NONE,
+ "Put a display ie in the CONNECT message containing the following\n"
+ "\tinformation if it is available (nt port only):\n"
+ "\n"
+ "\t0 - Do not put the connected line information in the display ie.\n"
+ "\t1 - Put the available connected line name in the display ie.\n"
+ "\t2 - Put the available connected line number in the display ie.\n"
+ "\t3 - Put the available connected line name and number in the display ie." },
+ { "display_setup", MISDN_CFG_DISPLAY_SETUP, MISDN_CTYPE_INT, "0", NONE,
+ "Put a display ie in the SETUP message containing the following\n"
+ "\tinformation if it is available (nt port only):\n"
+ "\n"
+ "\t0 - Do not put the caller information in the display ie.\n"
+ "\t1 - Put the available caller name in the display ie.\n"
+ "\t2 - Put the available caller number in the display ie.\n"
+ "\t3 - Put the available caller name and number in the display ie." },
{ "always_immediate", MISDN_CFG_ALWAYS_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
"Enable this to get into the s dialplan-extension.\n"
"\tThere you can use DigitTimeout if you can't or don't want to use\n"
@@ -220,7 +245,7 @@ static const struct misdn_cfg_spec port_spec[] = {
{ "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE,
"Enable this to prevent chan_misdn to generate the dialtone\n"
"\tThis makes only sense together with the always_immediate=yes option\n"
- "\tto generate your own dialtone with Playtones or so."},
+ "\tto generate your own dialtone with Playtones or so." },
{ "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
"Enable this if you want callers which called exactly the base\n"
"\tnumber (so no extension is set) to jump into the s extension.\n"
@@ -257,17 +282,17 @@ static const struct misdn_cfg_spec port_spec[] = {
#endif
#ifdef WITH_BEROEC
{ "bnechocancel", MISDN_CFG_BNECHOCANCEL, MISDN_CTYPE_BOOLINT, "yes", 64,
- "echotail in ms (1-200)\n"},
+ "echotail in ms (1-200)" },
{ "bnec_antihowl", MISDN_CFG_BNEC_ANTIHOWL, MISDN_CTYPE_INT, "0", NONE,
- "Use antihowl\n"},
+ "Use antihowl" },
{ "bnec_nlp", MISDN_CFG_BNEC_NLP, MISDN_CTYPE_BOOL, "yes", NONE,
- "Nonlinear Processing (much faster adaption)"},
+ "Nonlinear Processing (much faster adaption)" },
{ "bnec_zerocoeff", MISDN_CFG_BNEC_ZEROCOEFF, MISDN_CTYPE_BOOL, "no", NONE,
- "ZeroCoeffeciens\n"},
+ "ZeroCoeffeciens" },
{ "bnec_tonedisabler", MISDN_CFG_BNEC_TD, MISDN_CTYPE_BOOL, "no", NONE,
- "Disable Tone\n"},
+ "Disable Tone" },
{ "bnec_adaption", MISDN_CFG_BNEC_ADAPT, MISDN_CTYPE_INT, "1", NONE,
- "Adaption mode (0=no,1=full,2=fast)\n"},
+ "Adaption mode (0=no,1=full,2=fast)" },
#endif
{ "need_more_infos", MISDN_CFG_NEED_MORE_INFOS, MISDN_CTYPE_BOOL, "0", NONE,
"Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),\n"
@@ -311,13 +336,13 @@ static const struct misdn_cfg_spec port_spec[] = {
{ "faxdetect_context", MISDN_CFG_FAXDETECT_CONTEXT, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
"Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." },
{ "l1watcher_timeout", MISDN_CFG_L1_TIMEOUT, MISDN_CTYPE_BOOLINT, "0", 4,
- "Watches the layer 1. If the layer 1 is down, it tries to\n"
- "\tget it up. The timeout is given in seconds. with 0 as value it\n"
- "\tdoes not watch the l1 at all\n"
+ "Monitors L1 of the port. If L1 is down it tries\n"
+ "\tto bring it up. The polling timeout is given in seconds.\n"
+ "\tSetting the value to 0 disables monitoring L1 of the port.\n"
"\n"
- "\tThis option is only read at loading time of chan_misdn, which\n"
- "\tmeans you need to unload and load chan_misdn to change the value,\n"
- "\tan Asterisk restart should do the trick." },
+ "\tThis option is only read at chan_misdn loading time.\n"
+ "\tYou need to unload and load chan_misdn to change the\n"
+ "\tvalue. An asterisk restart will also do the trick." },
{ "overlapdial", MISDN_CFG_OVERLAP_DIAL, MISDN_CTYPE_BOOLINT, "0", 4,
"Enables overlap dial for the given amount of seconds.\n"
"\tPossible values are positive integers or:\n"
diff --git a/configs/misdn.conf.sample b/configs/misdn.conf.sample
index ca7f45497..e813953b3 100644
--- a/configs/misdn.conf.sample
+++ b/configs/misdn.conf.sample
@@ -7,13 +7,13 @@
; for debugging and general setup, things that are not bound to port groups
;
-[general]
+[general]
;
; Sets the Path to the misdn-init.conf (for nt_ptp mode checking)
;
misdn_init=/etc/misdn-init.conf
-; set debugging flag:
+; set debugging flag:
; 0 - No Debug
; 1 - mISDN Messages and * - Messages, and * - State changes
; 2 - Messages + Message specific Informations (e.g. bearer capability)
@@ -26,8 +26,8 @@ debug=0
-; set debugging file and flags for mISDNuser (NT-Stack)
-;
+; set debugging file and flags for mISDNuser (NT-Stack)
+;
; flags can be or'ed with the following values:
;
; DBGM_NET 0x00000001
@@ -57,7 +57,7 @@ ntdebugflags=0
ntdebugfile=/var/log/misdn-nt.log
-; some pbx systems do cut the L1 for some milliseconds, to avoid
+; some pbx systems do cut the L1 for some milliseconds, to avoid
; dropping running calls, we can set this flag to yes and tell
; mISDNuser not to drop the calls on L2_RELEASE
ntkeepcalls=no
@@ -76,26 +76,13 @@ ntkeepcalls=no
bridging=no
-;
-; watches the L1s of every port. If one l1 is down it tries to
-; get it up. The timeout is given in seconds. with 0 as value it
-; does not watch the l1 at all
-;
-; default value: 0
-;
-; this option is only read at loading time of chan_misdn,
-; which means you need to unload and load chan_misdn to change the
-; value, an asterisk restart should do the trick
-;
-l1watcher_timeout=0
-
; stops dialtone after getting first digit on nt Port
;
; default value: yes
;
stop_tone_after_first_digit=yes
-; whether to append overlapdialed Digits to Extension or not
+; whether to append overlapdialed Digits to Extension or not
;
; default value: yes
;
@@ -122,19 +109,6 @@ crypt_prefix=**
;
crypt_keys=test,muh
-; users sections:
-;
-; name your sections as you which but not "general" !
-; the sections are Groups, you can dial out in extensions.conf
-; with Dial(mISDN/g:extern/101) where extern is a section name,
-; chan_misdn tries every port in this section to find a
-; new free channel
-;
-
-; The default section is not a group section, it just contains config elements
-; which are inherited by group sections.
-;
-
;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a
; SIP channel. Defaults to "no". An enabled jitterbuffer will
@@ -161,6 +135,17 @@ crypt_keys=test,muh
; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
;-----------------------------------------------------------------------------------
+; users sections:
+;
+; name your sections as you wish but not "general" or "default" !
+; the sections are Groups, you can dial out in extensions.conf
+; with Dial(mISDN/g:extern/101) where extern is a section name,
+; chan_misdn tries every port in this section to find a
+; new free channel
+;
+; The default section is not a group section, it just contains config elements
+; which are inherited by group sections.
+;
[default]
; define your default context here
@@ -182,7 +167,7 @@ musicclass=default
;
; Either if we should produce DTMF Tones ourselves
-;
+;
senddtmf=yes
;
@@ -205,14 +190,26 @@ far_alerting=no
;
allowed_bearers=all
-; Prefixes for national and international, those are put before the
-; oad if an according dialplan is set by the other end.
-;
-; default values: nationalprefix : 0
-; internationalprefix : 00
-;
-nationalprefix=0
+; Prefixes for national and international Type-Of-Number. These are
+; inserted before any number (caller, dialed, connected, redirecting,
+; redirection) received from the ISDN link if that number has the
+; correspondng Type-Of-Number.
+; See the dialplan options.
+;
+; default values:
+; unknownprefix=
+; internationalprefix=00
+; nationalprefix=0
+; netspecificprefix=
+; subscriberprefix=
+; abbreviatedprefix=
+;
+;unknownprefix=
internationalprefix=00
+nationalprefix=0
+;netspecificprefix=
+;subscriberprefix=
+;abbreviatedprefix=
; set rx/tx gains between -8 and 8 to change the RX/TX Gain
;
@@ -222,7 +219,7 @@ internationalprefix=00
rxgain=0
txgain=0
-; some telcos especially in NL seem to need this set to yes, also in
+; some telcos especially in NL seem to need this set to yes, also in
; switzerland this seems to be important
;
; default value: no
@@ -232,7 +229,20 @@ te_choose_channel=no
;
-; This option defines, if chan_misdn should check the L1 on a PMP
+; Monitors L1 of the port. If L1 is down it tries
+; to bring it up. The polling timeout is given in seconds.
+; Setting the value to 0 disables monitoring L1 of the port.
+;
+; default value: 0
+;
+; This option is only read at chan_misdn loading time.
+; You need to unload and load chan_misdn to change the
+; value. An asterisk restart will also do the trick.
+;
+l1watcher_timeout=0
+
+;
+; This option defines, if chan_misdn should check the L1 on a PMP
; before making a group call on it. The L1 may go down for PMP Ports
; so we might need this.
; But be aware! a broken or plugged off cable might be used for a group call
@@ -245,19 +255,19 @@ pmp_l1_check=no
;
-; in PMP this option defines which cause should be sent out to
+; in PMP this option defines which cause should be sent out to
; the 3. caller. chan_misdn does not support callwaiting on TE
-; PMP side. This allows to modify the RELEASE_COMPLETE cause
+; PMP side. This allows to modify the RELEASE_COMPLETE cause
; at least.
;
reject_cause=16
;
-; Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),
-; this requests additional Infos, so we can waitfordigits
+; Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),
+; this requests additional Infos, so we can waitfordigits
; without much issues. This works only for PTP Ports
-;
+;
; default value: no
;
need_more_infos=no
@@ -280,29 +290,30 @@ nttimeout=no
method=standard
-; specify if chan_misdn should collect digits before going into the
+; specify if chan_misdn should collect digits before going into the
; dialplan, you can choose yes=4 Seconds, no, or specify the amount
; of seconds you need;
-;
+;
overlapdial=yes
;
-; dialplan means Type Of Number in ISDN Terms (for outgoing calls)
+; dialplan means Type Of Number in ISDN Terms
+; There are different types of the dialplan:
;
-; there are different types of the dialplan:
+; dialplan -> for outgoing call's dialed number
+; localdialplan -> for outgoing call's callerid
+; (if -1 is set use the value from the asterisk channel)
+; cpndialplan -> for incoming call's connected party number sent to caller
+; (if -1 is set use the value from the asterisk channel)
;
-; dialplan -> outgoing Number
-; localdialplan -> callerid
-; cpndialplan -> connected party number
-;
-; dialplan options:
+; dialplan options:
;
; 0 - unknown
; 1 - International
; 2 - National
+; 3 - Network-Specific
; 4 - Subscriber
-;
-; This setting is used for outgoing calls
+; 5 - Abbreviated
;
; default value: 0
;
@@ -313,7 +324,7 @@ cpndialplan=0
;
-; turn this to no if you don't mind correct handling of Progress Indicators
+; turn this to no if you don't mind correct handling of Progress Indicators
;
early_bconnect=yes
@@ -321,16 +332,16 @@ early_bconnect=yes
;
; turn this on if you like to send Tone Indications to a Incoming
; isdn channel on a TE Port. Rarely used, only if the Telco allows
-; you to send indications by yourself, normally the Telco sends the
+; you to send indications by yourself, normally the Telco sends the
; indications to the remote party.
-;
+;
; default: no
;
incoming_early_audio=no
; uncomment the following to get into s extension at extension conf
; there you can use DigitTimeout if you can't or don't want to use
-; isdn overlap dial.
+; isdn overlap dial.
; note: This will jump into the s exten for every exten!
;
; default value: no
@@ -338,7 +349,7 @@ incoming_early_audio=no
;always_immediate=no
;
-; set this to yes if you want to generate your own dialtone
+; set this to yes if you want to generate your own dialtone
; with always_immediate=yes, else chan_misdn generates the dialtone
;
; default value: no
@@ -346,9 +357,9 @@ incoming_early_audio=no
nodialtone=no
-; uncomment the following if you want callers which called exactly the
+; uncomment the following if you want callers which called exactly the
; base number (so no extension is set) jump to the s extension.
-; if the user dials something more it jumps to the correct extension
+; if the user dials something more it jumps to the correct extension
; instead
;
; default value: no
@@ -369,6 +380,8 @@ nodialtone=no
;callgroup=1
;pickupgroup=1
+; Set the outgoing caller id to the value.
+;callerid="name" <number>
;
; these are the exact isdn screening and presentation indicators
@@ -376,11 +389,31 @@ nodialtone=no
; from asterisks CALLERPRES function.
; s=0, p=0 -> callerid presented
; s=1, p=1 -> callerid restricted (the remote end does not see it!)
-;
+;
; default values s=-1, p=-1
presentation=-1
screen=-1
+; Put a display ie in the CONNECT message containing the following
+; information if it is available (nt port only):
+;
+; 0 - Do not put the connected line information in the display ie.
+; 1 - Put the available connected line name in the display ie.
+; 2 - Put the available connected line number in the display ie.
+; 3 - Put the available connected line name and number in the display ie.
+;
+display_connected=0
+
+; Put a display ie in the SETUP message containing the following
+; information if it is available (nt port only):
+;
+; 0 - Do not put the caller information in the display ie.
+; 1 - Put the available caller name in the display ie.
+; 2 - Put the available caller number in the display ie.
+; 3 - Put the available caller name and number in the display ie.
+;
+display_setup=0
+
; This enables echo cancellation with the given number of taps.
; Be aware: Move this setting only to outgoing portgroups!
; A value of zero turns echo cancellation off.
@@ -391,18 +424,9 @@ screen=-1
;
;echocancel=no
-; Set this to no to disable echotraining. You can enter a number > 10
-; the value is a multiple of 0.125 ms.
-;
-; default value: no
-; yes = 2000
-; no = 0
-;
-echotraining=no
-
;
; chan_misdns jitterbuffer, default 4000
-;
+;
jitterbuffer=4000
;
@@ -412,7 +436,7 @@ jitterbuffer_upper_threshold=0
;
-; change this to yes, if you want to bridge a mISDN data channel to
+; change this to yes, if you want to bridge a mISDN data channel to
; another channel type or to an application.
;
hdlc=no
@@ -420,8 +444,8 @@ hdlc=no
;
; defines the maximum amount of incoming calls per port for
-; this group. Calls which exceed the maximum will be marked with
-; the channel variable MAX_OVERFLOW. It will contain the amount of
+; this group. Calls which exceed the maximum will be marked with
+; the channel variable MAX_OVERFLOW. It will contain the amount of
; overflowed calls
;
max_incoming=-1
@@ -433,7 +457,7 @@ max_incoming=-1
max_outgoing=-1
[intern]
-; define your ports, e.g. 1,2 (depends on mISDN-driver loading order)
+; define your ports, e.g. 1,2 (depends on mISDN-driver loading order)
ports=1,2
; context where to go to when incoming Call on one of the above ports
context=Intern
@@ -445,21 +469,21 @@ context=Intern
; configs. For backwards compatibility you can still set ptp here.
;
ports=3
-
+
[first_extern]
; again port defs
ports=4
; again a context for incoming calls
context=Extern1
-; msns for te ports, listen on those numbers on the above ports, and
+; msns for te ports, listen on those numbers on the above ports, and
; indicate the incoming calls to asterisk
-; here you can give a comma separated list or simply an '*' for
-; any msn.
+; here you can give a comma separated list or simply an '*' for
+; any msn.
msns=*
; here an example with given msns
[second_extern]
ports=5
context=Extern2
-callerid=15
+callerid="Asterisk" <1234>
msns=102,144,101,104
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index 3785618e3..65e5a7e2e 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -214,6 +214,14 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;relaxdtmf=yes ; Relax dtmf handling
;trustrpid = no ; If Remote-Party-ID should be trusted
;sendrpid = yes ; If Remote-Party-ID should be sent
+;sendrpid = rpid ; Use the "Remote-Party-ID" header
+ ; to send the identity of the remote party
+ ; This is identical to sendrpid=yes
+;sendrpid = pai ; Use the "P-Asserted-Identity" header
+ ; to send the identity of the remote party
+;rpid_header = rpid ; Which header should be used when sending Remote Party ID
+ ; 'rpid' means to send "Remote-Party-ID"
+ ; 'pai' means to send "P-Asserted-Identity"
;progressinband=never ; If we should generate in-band ringing always
; use 'never' to never use in-band signalling, even in cases
; where some buggy devices might not render it
diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h
index 2d06dedc1..b8ff53cc1 100644
--- a/include/asterisk/callerid.h
+++ b/include/asterisk/callerid.h
@@ -86,21 +86,24 @@ typedef struct callerid_state CIDSTATE;
void callerid_init(void);
/*! \brief Generates a CallerID FSK stream in ulaw format suitable for transmission.
- * \param buf Buffer to use. If "buf" is supplied, it will use that buffer instead of allocating its own. "buf" must be at least 32000 bytes in size of you want to be sure you don't have an overrun.
+ * \param buf Buffer to use. If "buf" is supplied, it will use that buffer instead of allocating its own.
+ * "buf" must be at least 32000 bytes in size of you want to be sure you don't have an overrun.
* \param number Use NULL for no number or "P" for "private"
* \param name name to be used
* \param flags passed flags
* \param callwaiting callwaiting flag
* \param codec -- either AST_FORMAT_ULAW or AST_FORMAT_ALAW
+ * \details
* This function creates a stream of callerid (a callerid spill) data in ulaw format.
* \return It returns the size
* (in bytes) of the data (if it returns a size of 0, there is probably an error)
-*/
+ */
int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, int codec);
/*! \brief Create a callerID state machine
* \param cid_signalling Type of signalling in use
*
+ * \details
* This function returns a malloc'd instance of the callerid_state data structure.
* \return Returns a pointer to a malloc'd callerid_state structure, or NULL on error.
*/
@@ -112,9 +115,11 @@ struct callerid_state *callerid_new(int cid_signalling);
* \param samples number of samples contained within the buffer.
* \param codec which codec (AST_FORMAT_ALAW or AST_FORMAT_ULAW)
*
+ * \details
* Send received audio to the Caller*ID demodulator.
- * \return Returns -1 on error, 0 for "needs more samples",
- * and 1 if the CallerID spill reception is complete.
+ * \retval -1 on error
+ * \retval 0 for "needs more samples"
+ * \retval 1 if the CallerID spill reception is complete.
*/
int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int samples, int codec);
@@ -124,9 +129,11 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int samples,
* \param samples number of samples contained within the buffer.
* \param codec which codec (AST_FORMAT_ALAW or AST_FORMAT_ULAW)
*
+ * \details
* Send received audio to the Caller*ID demodulator (for japanese style lines).
- * \return Returns -1 on error, 0 for "needs more samples",
- * and 1 if the CallerID spill reception is complete.
+ * \retval -1 on error
+ * \retval 0 for "needs more samples"
+ * \retval 1 if the CallerID spill reception is complete.
*/
int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int samples, int codec);
@@ -136,6 +143,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int sample
* \param name Pass the address of a pointer-to-char (will contain the name)
* \param flags Pass the address of an int variable(will contain the various callerid flags)
*
+ * \details
* This function extracts a callerid string out of a callerid_state state machine.
* If no number is found, *number will be set to NULL. Likewise for the name.
* Flags can contain any of the following:
@@ -144,18 +152,16 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int sample
*/
void callerid_get(struct callerid_state *cid, char **number, char **name, int *flags);
-/*! Get and parse DTMF-based callerid */
/*!
+ * \brief Get and parse DTMF-based callerid
* \param cidstring The actual transmitted string.
* \param number The cid number is returned here.
* \param flags The cid flags are returned here.
- * This function parses DTMF callerid.
*/
void callerid_get_dtmf(char *cidstring, char *number, int *flags);
-/*! \brief Free a callerID state
+/*! \brief This function frees callerid_state cid.
* \param cid This is the callerid_state state machine to free
- * This function frees callerid_state cid.
*/
void callerid_free(struct callerid_state *cid);
@@ -165,36 +171,44 @@ void callerid_free(struct callerid_state *cid);
* \param number Caller-ID Number
* \param codec Asterisk codec (either AST_FORMAT_ALAW or AST_FORMAT_ULAW)
*
+ * \details
* Acts like callerid_generate except uses an asterisk format callerid string.
*/
int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int codec);
-/*! \brief Generate message waiting indicator
- * \param active The message indicator state
+/*!
+ * \brief Generate message waiting indicator
+ * \param active The message indicator state
* -- either 0 no messages in mailbox or 1 messages in mailbox
- * \param type Format of message (any of CID_MWI_TYPE_*)
- * \see callerid_generate() for more info as it use the same encoding
- * \version 1.6.1 changed mdmf parameter to type, added name, number and flags for caller id message generation
-*/
+ * \param type Format of message (any of CID_MWI_TYPE_*)
+ * \see callerid_generate() for more info as it uses the same encoding
+ * \version 1.6.1 changed mdmf parameter to type, added name, number and flags for caller id message generation
+ */
int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, int codec, const char *name,
const char *number, int flags);
/*! \brief Generate Caller-ID spill but in a format suitable for Call Waiting(tm)'s Caller*ID(tm)
- * See ast_callerid_generate() for other details
+ * \see ast_callerid_generate() for other details
*/
int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, int codec);
/*! \brief Destructively parse inbuf into name and location (or number)
+ * \details
* Parses callerid stream from inbuf and changes into useable form, outputed in name and location.
* \param instr buffer of callerid stream (in audio form) to be parsed. Warning, data in buffer is changed.
* \param name address of a pointer-to-char for the name value of the stream.
* \param location address of a pointer-to-char for the phone number value of the stream.
+ * \note XXX 'name' is not parsed consistently e.g. we have
+ * input location name
+ * " foo bar " <123> 123 ' foo bar ' (with spaces around)
+ * " foo bar " NULL 'foo bar' (without spaces around)
+ * The parsing of leading and trailing space/quotes should be more consistent.
* \return Returns 0 on success, -1 on failure.
*/
int ast_callerid_parse(char *instr, char **name, char **location);
-/*! Generate a CAS (CPE Alert Signal) tone for 'n' samples */
/*!
+ * \brief Generate a CAS (CPE Alert Signal) tone for 'n' samples
* \param outbuf Allocated buffer for data. Must be at least 2400 bytes unless no SAS is desired
* \param sas Non-zero if CAS should be preceeded by SAS
* \param len How many samples to generate.
@@ -203,23 +217,26 @@ int ast_callerid_parse(char *instr, char **name, char **location);
*/
int ast_gen_cas(unsigned char *outbuf, int sas, int len, int codec);
-/*! \brief Shrink a phone number in place to just digits (more accurately it just removes ()'s, .'s, and -'s... */
/*!
+ * \brief Shrink a phone number in place to just digits (more accurately it just removes ()'s, .'s, and -'s...
* \param n The number to be stripped/shrunk
* \return Returns nothing important
*/
void ast_shrink_phone_number(char *n);
-/*! \brief Check if a string consists only of digits and + \#
- \param n number to be checked.
- \return Returns 0 if n is a number, 1 if it's not.
+/*!
+ * \brief Check if a string consists only of digits and + \#
+ * \param n number to be checked.
+ * \return Returns 0 if n is a number, 1 if it's not.
*/
int ast_isphonenumber(const char *n);
-/*! \brief Check if a string consists only of digits and and + \# ( ) - .
- (meaning it can be cleaned with ast_shrink_phone_number)
- \param exten The extension (or URI) to be checked.
- \return Returns 0 if n is a number, 1 if it's not.
+/*!
+ * \brief Check if a string consists only of digits and and + \# ( ) - .
+ * (meaning it can be cleaned with ast_shrink_phone_number)
+ * \param exten The extension (or URI) to be checked.
+ * \retval 1 if string is valid AST shrinkable phone number
+ * \retval 0 if not
*/
int ast_is_shrinkable_phonenumber(const char *exten);
@@ -289,71 +306,171 @@ static inline float callerid_getcarrier(float *cr, float *ci, int bit)
/* Various defines and bits for handling PRI- and SS7-type restriction */
-#define AST_PRES_NUMBER_TYPE 0x03
+#define AST_PRES_NUMBER_TYPE 0x03
#define AST_PRES_USER_NUMBER_UNSCREENED 0x00
#define AST_PRES_USER_NUMBER_PASSED_SCREEN 0x01
#define AST_PRES_USER_NUMBER_FAILED_SCREEN 0x02
-#define AST_PRES_NETWORK_NUMBER 0x03
+#define AST_PRES_NETWORK_NUMBER 0x03
-#define AST_PRES_RESTRICTION 0x60
-#define AST_PRES_ALLOWED 0x00
-#define AST_PRES_RESTRICTED 0x20
-#define AST_PRES_UNAVAILABLE 0x40
-#define AST_PRES_RESERVED 0x60
+#define AST_PRES_RESTRICTION 0x60
+#define AST_PRES_ALLOWED 0x00
+#define AST_PRES_RESTRICTED 0x20
+#define AST_PRES_UNAVAILABLE 0x40
+#define AST_PRES_RESERVED 0x60
#define AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED \
- AST_PRES_USER_NUMBER_UNSCREENED + AST_PRES_ALLOWED
+ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED)
#define AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN \
- AST_PRES_USER_NUMBER_PASSED_SCREEN + AST_PRES_ALLOWED
+ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN)
#define AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN \
- AST_PRES_USER_NUMBER_FAILED_SCREEN + AST_PRES_ALLOWED
+ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN)
#define AST_PRES_ALLOWED_NETWORK_NUMBER \
- AST_PRES_NETWORK_NUMBER + AST_PRES_ALLOWED
+ (AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER)
#define AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED \
- AST_PRES_USER_NUMBER_UNSCREENED + AST_PRES_RESTRICTED
+ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED)
#define AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN \
- AST_PRES_USER_NUMBER_PASSED_SCREEN + AST_PRES_RESTRICTED
+ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN)
#define AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN \
- AST_PRES_USER_NUMBER_FAILED_SCREEN + AST_PRES_RESTRICTED
+ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN)
#define AST_PRES_PROHIB_NETWORK_NUMBER \
- AST_PRES_NETWORK_NUMBER + AST_PRES_RESTRICTED
+ (AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER)
#define AST_PRES_NUMBER_NOT_AVAILABLE \
- AST_PRES_NETWORK_NUMBER + AST_PRES_UNAVAILABLE
+ (AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER)
int ast_parse_caller_presentation(const char *data);
const char *ast_describe_caller_presentation(int data);
const char *ast_named_caller_presentation(int data);
-/*! \page Def_CallerPres Caller ID Presentation
+/*!
+ * \page Def_CallerPres Caller ID Presentation
+ *
+ * Caller ID presentation values are used to set properties to a
+ * caller ID in PSTN networks, and as RPID value in SIP transactions.
+ *
+ * The following values are available to use:
+ * \arg \b Defined value, text string in config file, explanation
+ *
+ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", Presentation Allowed, Not Screened,
+ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", Presentation Allowed, Passed Screen,
+ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", Presentation Allowed, Failed Screen,
+ * \arg \b AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", Presentation Allowed, Network Number,
+ * \arg \b AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", Presentation Prohibited, Not Screened,
+ * \arg \b AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", Presentation Prohibited, Passed Screen,
+ * \arg \b AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", Presentation Prohibited, Failed Screen,
+ * \arg \b AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", Presentation Prohibited, Network Number,
+ *
+ * \par References
+ * \arg \ref callerid.h Definitions
+ * \arg \ref callerid.c Functions
+ * \arg \ref CID Caller ID names and numbers
+ */
+
+/*!
+ * \brief redirecting reason codes.
+ *
+ * This list attempts to encompass redirecting reasons
+ * as defined by several channel technologies.
+ */
+enum AST_REDIRECTING_REASON {
+ AST_REDIRECTING_REASON_UNKNOWN,
+ AST_REDIRECTING_REASON_USER_BUSY,
+ AST_REDIRECTING_REASON_NO_ANSWER,
+ AST_REDIRECTING_REASON_UNAVAILABLE,
+ AST_REDIRECTING_REASON_UNCONDITIONAL,
+ AST_REDIRECTING_REASON_TIME_OF_DAY,
+ AST_REDIRECTING_REASON_DO_NOT_DISTURB,
+ AST_REDIRECTING_REASON_DEFLECTION,
+ AST_REDIRECTING_REASON_FOLLOW_ME,
+ AST_REDIRECTING_REASON_OUT_OF_ORDER,
+ AST_REDIRECTING_REASON_AWAY,
+ AST_REDIRECTING_REASON_CALL_FWD_DTE, /* This is something defined in Q.931, and no I don't know what it means */
+};
+
+/*!
+ * \since 1.6.3
+ * \brief Convert redirecting reason text code to value (used in config file parsing)
+ *
+ * \param data text string from config file
+ *
+ * \retval Q931_REDIRECTING_REASON from callerid.h
+ * \retval -1 if not in table
+ */
+int ast_redirecting_reason_parse(const char *data);
+
+/*!
+ * \since 1.6.3
+ * \brief Convert redirecting reason value to explanatory string
+ *
+ * \param data Q931_REDIRECTING_REASON from callerid.h
+ *
+ * \return string for human presentation
+ */
+const char *ast_redirecting_reason_describe(int data);
+
+/*!
+ * \since 1.6.3
+ * \brief Convert redirecting reason value to text code
+ *
+ * \param data Q931_REDIRECTING_REASON from callerid.h
+ *
+ * \return string for config file
+ */
+const char *ast_redirecting_reason_name(int data);
- Caller ID presentation values are used to set properties to a
- caller ID in PSTN networks, and as RPID value in SIP transactions.
+/*!
+ * \brief Connected line update source code
+ */
+enum AST_CONNECTED_LINE_UPDATE_SOURCE {
+ /*! Update for unknown reason (May be interpreted to mean from answer) */
+ AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN,
+ /*! Update from normal call answering */
+ AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER,
+ /*! Update from call diversion (Deprecated, use REDIRECTING updates instead.) */
+ AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION,
+ /*! Update from call transfer(active) (Party has already answered) */
+ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,
+ /*! Update from call transfer(alerting) (Party has not answered yet) */
+ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
+};
- The following values are available to use:
- \arg \b Defined value, text string in config file, explanation
+/*!
+ * \since 1.6.3
+ * \brief Convert connected line update source text code to value (used in config file parsing)
+ *
+ * \param data text string from config file
+ *
+ * \retval AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
+ * \retval -1 if not in table
+ */
+int ast_connected_line_source_parse(const char *data);
- \arg \b AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", Presentation Allowed, Not Screened,
- \arg \b AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", Presentation Allowed, Passed Screen,
- \arg \b AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", Presentation Allowed, Failed Screen,
- \arg \b AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", Presentation Allowed, Network Number,
- \arg \b AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", Presentation Prohibited, Not Screened,
- \arg \b AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", Presentation Prohibited, Passed Screen,
- \arg \b AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", Presentation Prohibited, Failed Screen,
- \arg \b AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", Presentation Prohibited, Network Number,
+/*!
+ * \since 1.6.3
+ * \brief Convert connected line update source value to explanatory string
+ *
+ * \param data AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
+ *
+ * \return string for human presentation
+ */
+const char *ast_connected_line_source_describe(int data);
- \par References
- \arg \ref callerid.h Definitions
- \arg \ref callerid.c Functions
- \arg \ref CID Caller ID names and numbers
-*/
+/*!
+ * \since 1.6.3
+ * \brief Convert connected line update source value to text code
+ *
+ * \param data AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
+ *
+ * \return string for config file
+ */
+const char *ast_connected_line_source_name(int data);
#endif /* _ASTERISK_CALLERID_H */
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 1a0a6ec07..8f5464569 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -102,7 +102,7 @@
can create a native bridge without sending media through the
core.
- Native briding can be disabled by a number of reasons,
+ Native bridging can be disabled by a number of reasons,
like DTMF being needed by the core or codecs being incompatible
so a transcoding module is needed.
@@ -183,45 +183,173 @@ struct ast_generator {
void (*digit)(struct ast_channel *chan, char digit);
};
-/*! \brief Structure for all kinds of caller ID identifications.
+/*!
+ * \brief Structure for all kinds of caller ID identifications.
* \note All string fields here are malloc'ed, so they need to be
* freed when the structure is deleted.
* Also, NULL and "" must be considered equivalent.
*
- * SIP and IAX2 has utf8 encoded Unicode caller ID names.
+ * \note SIP and IAX2 has utf8 encoded Unicode caller ID names.
* In some cases, we also have an alternative (RPID) E.164 number that can be used
- * as caller ID on numeric E.164 phone networks (DAHDI or SIP/IAX2 to pstn gateway).
+ * as caller ID on numeric E.164 phone networks (DAHDI or SIP/IAX2 to PSTN gateway).
*
* \todo Implement settings for transliteration between UTF8 caller ID names in
* to Ascii Caller ID's (DAHDI). Östen Åsklund might be transliterated into
- * Osten Asklund or Oesten Aasklund depending upon language and person...
- * We need automatic routines for incoming calls and static settings for
- * our own accounts.
+ * Osten Asklund or Oesten Aasklund depending upon language and person...
+ * We need automatic routines for incoming calls and static settings for
+ * our own accounts.
*/
struct ast_callerid {
- char *cid_dnid; /*!< Malloc'd Dialed Number Identifier */
- char *cid_num; /*!< Malloc'd Caller Number */
- char *cid_name; /*!< Malloc'd Caller Name (ASCII) */
- char *cid_ani; /*!< Malloc'd ANI */
- char *cid_rdnis; /*!< Malloc'd RDNIS */
- int cid_pres; /*!< Callerid presentation/screening */
- int cid_ani2; /*!< Callerid ANI 2 (Info digits) */
- int cid_ton; /*!< Callerid Type of Number */
- int cid_tns; /*!< Callerid Transit Network Select */
+ /*!
+ * \brief Malloc'd Dialed Number Identifier
+ * (Field will eventually move to struct ast_channel.dialed.number)
+ */
+ char *cid_dnid;
+
+ /*!
+ * \brief Malloc'd Caller Number
+ * (Field will eventually move to struct ast_channel.caller.id.number)
+ */
+ char *cid_num;
+
+ /*!
+ * \brief Malloc'd Caller Name (ASCII)
+ * (Field will eventually move to struct ast_channel.caller.id.name)
+ */
+ char *cid_name;
+
+ /*!
+ * \brief Malloc'd Automatic Number Identification (ANI)
+ * (Field will eventually move to struct ast_channel.caller.ani)
+ */
+ char *cid_ani;
+
+ /*!
+ * \brief Malloc'd Redirecting Directory Number Information Service (RDNIS)
+ * (Field will eventually move to struct ast_channel.redirecting.from.number)
+ */
+ char *cid_rdnis;
+
+ /*!
+ * \brief Callerid Q.931 encoded number presentation/screening fields
+ * (Field will eventually move to struct ast_channel.caller.id.number_presentation)
+ */
+ int cid_pres;
+
+ /*!
+ * \brief Callerid ANI 2 (Info digits)
+ * (Field will eventually move to struct ast_channel.caller.ani2)
+ */
+ int cid_ani2;
+
+ /*!
+ * \brief Callerid Q.931 encoded type-of-number/numbering-plan fields
+ * \note Currently this value is mostly just passed around the system.
+ * The H.323 interfaces set the value from received messages and uses the value for sent messages.
+ * The DAHDI PRI interfaces set the value from received messages but does not use it for sent messages.
+ * You can read it and set it but only H.323 uses it.
+ * (Field will eventually move to struct ast_channel.caller.id.number_type)
+ */
+ int cid_ton;
+
+ /*!
+ * \brief Callerid Transit Network Select
+ * \note Currently this value is just passed around the system.
+ * You can read it and set it but it is never used for anything.
+ * (Field will eventually move to struct ast_channel.dialed.transit_network_select)
+ */
+ int cid_tns;
};
-/*! \brief
- Structure to describe a channel "technology", ie a channel driver
- See for examples:
- \arg chan_iax2.c - The Inter-Asterisk exchange protocol
- \arg chan_sip.c - The SIP channel driver
- \arg chan_dahdi.c - PSTN connectivity (TDM, PRI, T1/E1, FXO, FXS)
-
- If you develop your own channel driver, this is where you
- tell the PBX at registration of your driver what properties
- this driver supports and where different callbacks are
- implemented.
-*/
+/*!
+ * \since 1.6.3
+ * \brief Information needed to identify an endpoint in a call.
+ * \note All string fields here are malloc'ed, so they need to be
+ * freed when the structure is deleted.
+ * \note NULL and "" must be considered equivalent.
+ */
+struct ast_party_id {
+ /*! \brief Subscriber phone number (Malloced) */
+ char *number;
+
+ /*! \brief Subscriber name (Malloced) */
+ char *name;
+
+ /*! \brief Q.931 encoded type-of-number/numbering-plan fields */
+ int number_type;
+
+ /*! \brief Q.931 encoded number presentation/screening fields */
+ int number_presentation;
+};
+
+/*!
+ * \since 1.6.3
+ * \brief Connected Line/Party information.
+ * \note All string fields here are malloc'ed, so they need to be
+ * freed when the structure is deleted.
+ * \note NULL and "" must be considered equivalent.
+ */
+struct ast_party_connected_line {
+ struct ast_party_id id; /*! \brief Connected party ID */
+
+ /*!
+ * \brief Automatic Number Identification (ANI) (Malloced)
+ * \note Not really part of connected line data but needed to
+ * save the corresponding caller id value.
+ */
+ char *ani;
+
+ /*!
+ * \brief Automatic Number Identification 2 (Info Digits)
+ * \note Not really part of connected line data but needed to
+ * save the corresponding caller id value.
+ */
+ int ani2;
+
+ /*! \brief Information about the source of an update (Q.SIG/ISDN requirement).
+ * \note enum AST_CONNECTED_LINE_UPDATE_SOURCE values
+ * for Normal-Answer, Call-transfer, Call-diversion
+ */
+ int source;
+};
+
+/*!
+ * \since 1.6.3
+ * \brief Redirecting Line information.
+ * RDNIS (Redirecting Directory Number Information Service)
+ * Where a call diversion or transfer was invoked.
+ * \note All string fields here are malloc'ed, so they need to be
+ * freed when the structure is deleted.
+ * \note NULL and "" must be considered equivalent.
+ */
+struct ast_party_redirecting {
+ /*! \brief Who is redirecting the call (Sent to the party the call is redirected toward) */
+ struct ast_party_id from;
+
+ /*! \brief Call is redirecting to a new party (Sent to the caller) */
+ struct ast_party_id to;
+
+ /*! \brief Number of times the call was redirected */
+ int count;
+
+ /*! \brief enum AST_REDIRECTING_REASON value for redirection */
+ int reason;
+};
+
+/*!
+ * \brief
+ * Structure to describe a channel "technology", ie a channel driver
+ * See for examples:
+ * \arg chan_iax2.c - The Inter-Asterisk exchange protocol
+ * \arg chan_sip.c - The SIP channel driver
+ * \arg chan_dahdi.c - PSTN connectivity (TDM, PRI, T1/E1, FXO, FXS)
+ *
+ * \details
+ * If you develop your own channel driver, this is where you
+ * tell the PBX at registration of your driver what properties
+ * this driver supports and where different callbacks are
+ * implemented.
+ */
struct ast_channel_tech {
const char * const type;
const char * const description;
@@ -250,7 +378,7 @@ struct ast_channel_tech {
int (* const send_digit_end)(struct ast_channel *chan, char digit, unsigned int duration);
/*! \brief Call a given phone number (address, etc), but don't
- take longer than timeout seconds to do so. */
+ * take longer than timeout seconds to do so. */
int (* const call)(struct ast_channel *chan, char *addr, int timeout);
/*! \brief Hangup (and possibly destroy) the channel */
@@ -381,7 +509,8 @@ enum ast_t38_state {
T38_STATE_NEGOTIATED, /*!< T38 established */
};
-/*! \brief Main Channel structure associated with a channel.
+/*!
+ * \brief Main Channel structure associated with a channel.
* This is the side of it mostly used by the pbx and call management.
*
* \note XXX It is important to remember to increment .cleancount each time
@@ -395,7 +524,6 @@ enum ast_t38_state {
* and 8-byte fields causes 4 bytes of padding to be added before many
* 8-byte fields.
*/
-
struct ast_channel {
const struct ast_channel_tech *tech; /*!< Technology (point to channel driver) */
void *tech_pvt; /*!< Private data used by the technology driver */
@@ -403,8 +531,8 @@ struct ast_channel {
void *generatordata; /*!< Current generator data if there is any */
struct ast_generator *generator; /*!< Current active data generator */
struct ast_channel *_bridge; /*!< Who are we bridged to, if we're bridged.
- Who is proxying for us, if we are proxied (i.e. chan_agent).
- Do not access directly, use ast_bridged_channel(chan) */
+ * Who is proxying for us, if we are proxied (i.e. chan_agent).
+ * Do not access directly, use ast_bridged_channel(chan) */
struct ast_channel *masq; /*!< Channel that will masquerade as us */
struct ast_channel *masqr; /*!< Who we are masquerading as */
const char *blockproc; /*!< Procedure causing blocking */
@@ -421,7 +549,7 @@ struct ast_channel {
struct ast_audiohook_list *audiohooks;
struct ast_cdr *cdr; /*!< Call Detail Record */
struct ast_tone_zone *zone; /*!< Tone zone as set in indications.conf or
- in the CHANNEL dialplan function */
+ * in the CHANNEL dialplan function */
struct ast_channel_monitor *monitor; /*!< Channel monitoring */
#ifdef HAVE_EPOLL
struct ast_epoll_data *epfd_data[AST_MAX_FDS];
@@ -441,7 +569,29 @@ struct ast_channel {
struct timeval whentohangup; /*!< Non-zero, set to actual time when channel is to be hung up */
pthread_t blocker; /*!< If anyone is blocking, this is them */
ast_mutex_t lock_dont_use; /*!< Lock a channel for some operations. See ast_channel_lock() */
- struct ast_callerid cid; /*!< Caller ID, name, presentation etc */
+
+ /*!
+ * \brief Channel Caller ID information.
+ * \note The caller id information is the caller id of this
+ * channel when it is used to initiate a call.
+ */
+ struct ast_callerid cid;
+
+ /*!
+ * \brief Channel Connected Line ID information.
+ * \note The connected line information identifies the channel
+ * connected/bridged to this channel.
+ */
+ struct ast_party_connected_line connected;
+
+ /*!
+ * \brief Redirecting/Diversion information
+ * \note Until struct ast_channel.cid.cid_rdnis is replaced
+ * with ast_channel.redirecting.from.number, the
+ * ast_channel.redirecting.from.number field is not used.
+ */
+ struct ast_party_redirecting redirecting;
+
struct ast_frame dtmff; /*!< DTMF frame */
struct varshead varshead; /*!< A linked list for channel variables. See \ref AstChanVar */
ast_group_t callgroup; /*!< Call group for call pickups */
@@ -456,11 +606,11 @@ struct ast_channel {
unsigned long outsmpl; /*!< Track the read/written samples for monitor use */
int fds[AST_MAX_FDS]; /*!< File descriptors for channel -- Drivers will poll on
- these file descriptors, so at least one must be non -1.
- See \arg \ref AstFileDesc */
+ * these file descriptors, so at least one must be non -1.
+ * See \arg \ref AstFileDesc */
int cdrflags; /*!< Call Detail Record Flags */
int _softhangup; /*!< Whether or not we have been hung up... Do not set this value
- directly, use ast_softhangup() */
+ * directly, use ast_softhangup() */
int fdno; /*!< Which fd had an event detected on */
int streamid; /*!< For streaming playback, the schedule ID */
int vstreamid; /*!< For streaming video playback, the schedule ID */
@@ -473,9 +623,9 @@ struct ast_channel {
int amaflags; /*!< Set BEFORE PBX is started to determine AMA flags */
enum ast_channel_adsicpe adsicpe; /*!< Whether or not ADSI is detected on CPE */
unsigned int fin; /*!< Frames in counters. The high bit is a debug mask, so
- the counter is only in the remaining bits */
+ * the counter is only in the remaining bits */
unsigned int fout; /*!< Frames out counters. The high bit is a debug mask, so
- the counter is only in the remaining bits */
+ * the counter is only in the remaining bits */
int hangupcause; /*!< Why is the channel hanged up. See causes.h */
unsigned int flags; /*!< channel flags of AST_FLAG_ type */
int alertpipe[2];
@@ -490,7 +640,7 @@ struct ast_channel {
#endif
int visible_indication; /*!< Indication currently playing on the channel */
- unsigned short transfercapability; /*!< ISDN Transfer Capbility - AST_FLAG_DIGITAL is not enough */
+ unsigned short transfercapability; /*!< ISDN Transfer Capability - AST_FLAG_DIGITAL is not enough */
union {
char unused_old_dtmfq[AST_MAX_EXTENSION]; /*!< (deprecated, use readq instead) Any/all queued DTMF characters */
@@ -509,17 +659,21 @@ struct ast_channel {
/*! \brief ast_channel_tech Properties */
enum {
- /*! \brief Channels have this property if they can accept input with jitter;
- * i.e. most VoIP channels */
+ /*!
+ * \brief Channels have this property if they can accept input with jitter;
+ * i.e. most VoIP channels
+ */
AST_CHAN_TP_WANTSJITTER = (1 << 0),
- /*! \brief Channels have this property if they can create jitter;
- * i.e. most VoIP channels */
+ /*!
+ * \brief Channels have this property if they can create jitter;
+ * i.e. most VoIP channels
+ */
AST_CHAN_TP_CREATESJITTER = (1 << 1),
};
/*! \brief ast_channel flags */
enum {
- /*! Queue incoming dtmf, to be released when this flag is turned off */
+ /*! Queue incoming DTMF, to be released when this flag is turned off */
AST_FLAG_DEFER_DTMF = (1 << 1),
/*! write should be interrupt generator */
AST_FLAG_WRITE_INT = (1 << 2),
@@ -550,7 +704,7 @@ enum {
* to instead only generate END frames. */
AST_FLAG_END_DTMF_ONLY = (1 << 14),
/*! Flag to show channels that this call is hangup due to the fact that the call
- was indeed anwered, but in another channel */
+ was indeed answered, but in another channel */
AST_FLAG_ANSWERED_ELSEWHERE = (1 << 15),
/*! This flag indicates that on a masquerade, an active stream should not
* be carried over */
@@ -675,7 +829,6 @@ int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *
* \retval 0 success
* \retval non-zero failure
*/
-
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore);
/*!
@@ -778,6 +931,7 @@ int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type cont
* \retval 0 success
* \retval non-zero failure
*
+ * \details
* The supplied payload data is copied into the frame, so the caller's copy
* is not modified nor freed, and the resulting frame will retain a copy of
* the data even if the caller frees their local copy.
@@ -812,6 +966,7 @@ void ast_channel_free(struct ast_channel *);
* \param data data to pass to the channel requester
* \param status status
*
+ * \details
* Request a channel of a given type, with data as optional information used
* by the low level module
*
@@ -855,54 +1010,63 @@ struct ast_channel *ast_request_and_dial(const char *type, int format, void *dat
struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data,
int timeout, int *reason, const char *cid_num, const char *cid_name, struct outgoing_helper *oh);
-/*!\brief Register a channel technology (a new channel driver)
+/*!
+ * \brief Register a channel technology (a new channel driver)
* Called by a channel module to register the kind of channels it supports.
* \param tech Structure defining channel technology or "type"
* \return Returns 0 on success, -1 on failure.
*/
int ast_channel_register(const struct ast_channel_tech *tech);
-/*! \brief Unregister a channel technology
+/*!
+ * \brief Unregister a channel technology
* \param tech Structure defining channel technology or "type" that was previously registered
* \return No return value.
*/
void ast_channel_unregister(const struct ast_channel_tech *tech);
-/*! \brief Get a channel technology structure by name
+/*!
+ * \brief Get a channel technology structure by name
* \param name name of technology to find
* \return a pointer to the structure, or NULL if no matching technology found
*/
const struct ast_channel_tech *ast_get_channel_tech(const char *name);
#ifdef CHANNEL_TRACE
-/*! \brief Update the context backtrace if tracing is enabled
+/*!
+ * \brief Update the context backtrace if tracing is enabled
* \return Returns 0 on success, -1 on failure
*/
int ast_channel_trace_update(struct ast_channel *chan);
-/*! \brief Enable context tracing in the channel
+/*!
+ * \brief Enable context tracing in the channel
* \return Returns 0 on success, -1 on failure
*/
int ast_channel_trace_enable(struct ast_channel *chan);
-/*! \brief Disable context tracing in the channel.
+/*!
+ * \brief Disable context tracing in the channel.
* \note Does not remove current trace entries
* \return Returns 0 on success, -1 on failure
*/
int ast_channel_trace_disable(struct ast_channel *chan);
-/*! \brief Whether or not context tracing is enabled
+/*!
+ * \brief Whether or not context tracing is enabled
* \return Returns -1 when the trace is enabled. 0 if not.
*/
int ast_channel_trace_is_enabled(struct ast_channel *chan);
-/*! \brief Put the channel backtrace in a string
+/*!
+ * \brief Put the channel backtrace in a string
* \return Returns the amount of lines in the backtrace. -1 on error.
*/
int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **out);
#endif
-/*! \brief Hang up a channel
+/*!
+ * \brief Hang up a channel
* \note This function performs a hard hangup on a channel. Unlike the soft-hangup, this function
* performs all stream stopping, etc, on the channel that needs to end.
* chan is no longer valid after this call.
@@ -917,6 +1081,7 @@ int ast_hangup(struct ast_channel *chan);
* \param chan channel to be soft-hung-up
* \param cause Ast hangupcause for hangup
*
+ * \details
* Call the protocol layer, but don't destroy the channel structure
* (use this if you are trying to
* safely hangup a channel managed by another thread.
@@ -927,9 +1092,11 @@ int ast_hangup(struct ast_channel *chan);
*/
int ast_softhangup(struct ast_channel *chan, int cause);
-/*! \brief Softly hangup up a channel (no channel lock)
+/*!
+ * \brief Softly hangup up a channel (no channel lock)
* \param chan channel to be soft-hung-up
- * \param cause Ast hangupcause for hangup (see cause.h) */
+ * \param cause Ast hangupcause for hangup (see cause.h)
+ */
int ast_softhangup_nolock(struct ast_channel *chan, int cause);
/*! \brief Check to see if a channel is needing hang up
@@ -944,6 +1111,7 @@ int ast_check_hangup(struct ast_channel *chan);
* \param chan channel on which to check for hang up
* \param offset offset in seconds from current time
* \return 1, 0, or -1
+ * \details
* This function compares a offset from current time with the absolute time
* out on a channel (when to hang up). If the absolute time out on a channel
* is earlier than current time plus the offset, it returns 1, if the two
@@ -966,11 +1134,13 @@ int ast_channel_cmpwhentohangup(struct ast_channel *chan, time_t offset) __attri
*/
int ast_channel_cmpwhentohangup_tv(struct ast_channel *chan, struct timeval offset);
-/*! \brief Set when to hang a channel up
+/*!
+ * \brief Set when to hang a channel up
*
* \param chan channel on which to check for hang up
* \param offset offset in seconds relative to the current time of when to hang up
*
+ * \details
* This function sets the absolute time out on a channel (when to hang up).
*
* \note This function does not require that the channel is locked before
@@ -982,7 +1152,8 @@ int ast_channel_cmpwhentohangup_tv(struct ast_channel *chan, struct timeval offs
*/
void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset) __attribute__((deprecated));
-/*! \brief Set when to hang a channel up
+/*!
+ * \brief Set when to hang a channel up
*
* \param chan channel on which to check for hang up
* \param offset offset in seconds and useconds relative to the current time of when to hang up
@@ -1002,6 +1173,7 @@ void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval off
*
* \param chan channel to answer
*
+ * \details
* This function answers a channel and handles all necessary call
* setup functions.
*
@@ -1062,18 +1234,21 @@ int ast_raw_answer(struct ast_channel *chan, int cdr_answer);
*/
int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer);
-/*! \brief Make a call
+/*!
+ * \brief Make a call
* \param chan which channel to make the call on
* \param addr destination of the call
* \param timeout time to wait on for connect
+ * \details
* Place a call, take no longer than timeout ms.
- \return Returns -1 on failure, 0 on not enough time
- (does not automatically stop ringing), and
- the number of seconds the connect took otherwise.
- */
+ * \return -1 on failure, 0 on not enough time
+ * (does not automatically stop ringing), and
+ * the number of seconds the connect took otherwise.
+ */
int ast_call(struct ast_channel *chan, char *addr, int timeout);
-/*! \brief Indicates condition of channel
+/*!
+ * \brief Indicates condition of channel
* \note Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel
* \param chan channel to change the indication
* \param condition which condition to indicate on the channel
@@ -1081,7 +1256,8 @@ int ast_call(struct ast_channel *chan, char *addr, int timeout);
*/
int ast_indicate(struct ast_channel *chan, int condition);
-/*! \brief Indicates condition of channel, with payload
+/*!
+ * \brief Indicates condition of channel, with payload
* \note Indicate a condition such as AST_CONTROL_HOLD with payload being music on hold class
* \param chan channel to change the indication
* \param condition which condition to indicate on the channel
@@ -1093,33 +1269,43 @@ int ast_indicate_data(struct ast_channel *chan, int condition, const void *data,
/* Misc stuff ------------------------------------------------ */
-/*! \brief Wait for input on a channel
+/*!
+ * \brief Wait for input on a channel
* \param chan channel to wait on
* \param ms length of time to wait on the channel
+ * \details
* Wait for input on a channel for a given # of milliseconds (<0 for indefinite).
- \return Returns < 0 on failure, 0 if nothing ever arrived, and the # of ms remaining otherwise */
+ * \retval < 0 on failure
+ * \retval 0 if nothing ever arrived
+ * \retval the # of ms remaining otherwise
+ */
int ast_waitfor(struct ast_channel *chan, int ms);
-/*! \brief Wait for a specified amount of time, looking for hangups
+/*!
+ * \brief Wait for a specified amount of time, looking for hangups
* \param chan channel to wait for
* \param ms length of time in milliseconds to sleep
+ * \details
* Waits for a specified amount of time, servicing the channel as required.
* \return returns -1 on hangup, otherwise 0.
*/
int ast_safe_sleep(struct ast_channel *chan, int ms);
-/*! \brief Wait for a specified amount of time, looking for hangups and a condition argument
+/*!
+ * \brief Wait for a specified amount of time, looking for hangups and a condition argument
* \param chan channel to wait for
* \param ms length of time in milliseconds to sleep
* \param cond a function pointer for testing continue condition
* \param data argument to be passed to the condition test function
* \return returns -1 on hangup, otherwise 0.
+ * \details
* Waits for a specified amount of time, servicing the channel as required. If cond
* returns 0, this function returns.
*/
int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data );
-/*! \brief Waits for activity on a group of channels
+/*!
+ * \brief Waits for activity on a group of channels
* \param chan an array of pointers to channels
* \param n number of channels that are to be waited upon
* \param fds an array of fds to wait upon
@@ -1127,44 +1313,55 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(voi
* \param exception exception flag
* \param outfd fd that had activity on it
* \param ms how long the wait was
+ * \details
* Big momma function here. Wait for activity on any of the n channels, or any of the nfds
- file descriptors.
- \return Returns the channel with activity, or NULL on error or if an FD
- came first. If the FD came first, it will be returned in outfd, otherwise, outfd
- will be -1 */
+ * file descriptors.
+ * \return Returns the channel with activity, or NULL on error or if an FD
+ * came first. If the FD came first, it will be returned in outfd, otherwise, outfd
+ * will be -1
+ */
struct ast_channel *ast_waitfor_nandfds(struct ast_channel **chan, int n,
int *fds, int nfds, int *exception, int *outfd, int *ms);
-/*! \brief Waits for input on a group of channels
- Wait for input on an array of channels for a given # of milliseconds.
- \return Return channel with activity, or NULL if none has activity.
- \param chan an array of pointers to channels
- \param n number of channels that are to be waited upon
- \param ms time "ms" is modified in-place, if applicable */
+/*!
+ * \brief Waits for input on a group of channels
+ * Wait for input on an array of channels for a given # of milliseconds.
+ * \return Return channel with activity, or NULL if none has activity.
+ * \param chan an array of pointers to channels
+ * \param n number of channels that are to be waited upon
+ * \param ms time "ms" is modified in-place, if applicable
+ */
struct ast_channel *ast_waitfor_n(struct ast_channel **chan, int n, int *ms);
-/*! \brief Waits for input on an fd
- This version works on fd's only. Be careful with it. */
+/*!
+ * \brief Waits for input on an fd
+ * \note This version works on fd's only. Be careful with it.
+ */
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception);
-/*! \brief Reads a frame
+/*!
+ * \brief Reads a frame
* \param chan channel to read a frame from
* \return Returns a frame, or NULL on error. If it returns NULL, you
- best just stop reading frames and assume the channel has been
- disconnected. */
+ * best just stop reading frames and assume the channel has been
+ * disconnected.
+ */
struct ast_frame *ast_read(struct ast_channel *chan);
-/*! \brief Reads a frame, returning AST_FRAME_NULL frame if audio.
- \param chan channel to read a frame from
- \return Returns a frame, or NULL on error. If it returns NULL, you
- best just stop reading frames and assume the channel has been
- disconnected.
- \note Audio is replaced with AST_FRAME_NULL to avoid
- transcode when the resulting audio is not necessary. */
+/*!
+ * \brief Reads a frame, returning AST_FRAME_NULL frame if audio.
+ * \param chan channel to read a frame from
+ * \return Returns a frame, or NULL on error. If it returns NULL, you
+ * best just stop reading frames and assume the channel has been
+ * disconnected.
+ * \note Audio is replaced with AST_FRAME_NULL to avoid
+ * transcode when the resulting audio is not necessary.
+ */
struct ast_frame *ast_read_noaudio(struct ast_channel *chan);
-/*! \brief Write a frame to a channel
+/*!
+ * \brief Write a frame to a channel
* This function writes the given frame to the indicated channel.
* \param chan destination channel of the frame
* \param frame frame that will be written
@@ -1172,7 +1369,8 @@ struct ast_frame *ast_read_noaudio(struct ast_channel *chan);
*/
int ast_write(struct ast_channel *chan, struct ast_frame *frame);
-/*! \brief Write video frame to a channel
+/*!
+ * \brief Write video frame to a channel
* This function writes the given frame to the indicated channel.
* \param chan destination channel of the frame
* \param frame frame that will be written
@@ -1180,7 +1378,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *frame);
*/
int ast_write_video(struct ast_channel *chan, struct ast_frame *frame);
-/*! \brief Write text frame to a channel
+/*!
+ * \brief Write text frame to a channel
* This function writes the given frame to the indicated channel.
* \param chan destination channel of the frame
* \param frame frame that will be written
@@ -1191,7 +1390,8 @@ int ast_write_text(struct ast_channel *chan, struct ast_frame *frame);
/*! \brief Send empty audio to prime a channel driver */
int ast_prod(struct ast_channel *chan);
-/*! \brief Sets read format on channel chan
+/*!
+ * \brief Sets read format on channel chan
* Set read format for channel to whichever component of "format" is best.
* \param chan channel to change
* \param format format to change to
@@ -1199,7 +1399,8 @@ int ast_prod(struct ast_channel *chan);
*/
int ast_set_read_format(struct ast_channel *chan, int format);
-/*! \brief Sets write format on channel chan
+/*!
+ * \brief Sets write format on channel chan
* Set write format for channel to whichever component of "format" is best.
* \param chan channel to change
* \param format new format for writing
@@ -1213,6 +1414,7 @@ int ast_set_write_format(struct ast_channel *chan, int format);
* \param chan channel to act upon
* \param text string of text to send on the channel
*
+ * \details
* Write text to a display on a channel
*
* \note The channel does not need to be locked before calling this function.
@@ -1222,34 +1424,35 @@ int ast_set_write_format(struct ast_channel *chan, int format);
*/
int ast_sendtext(struct ast_channel *chan, const char *text);
-/*! \brief Receives a text character from a channel
+/*!
+ * \brief Receives a text character from a channel
* \param chan channel to act upon
* \param timeout timeout in milliseconds (0 for infinite wait)
+ * \details
* Read a char of text from a channel
- * Returns 0 on success, -1 on failure
+ * \return 0 on success, -1 on failure
*/
int ast_recvchar(struct ast_channel *chan, int timeout);
-/*! \brief Send a DTMF digit to a channel
- * Send a DTMF digit to a channel.
+/*!
+ * \brief Send a DTMF digit to a channel.
* \param chan channel to act upon
* \param digit the DTMF digit to send, encoded in ASCII
* \param duration the duration of the digit ending in ms
- * \return Returns 0 on success, -1 on failure
+ * \return 0 on success, -1 on failure
*/
int ast_senddigit(struct ast_channel *chan, char digit, unsigned int duration);
-/*! \brief Send a DTMF digit to a channel
- * Send a DTMF digit to a channel.
+/*!
+ * \brief Send a DTMF digit to a channel.
* \param chan channel to act upon
* \param digit the DTMF digit to send, encoded in ASCII
- * \return Returns 0 on success, -1 on failure
+ * \return 0 on success, -1 on failure
*/
int ast_senddigit_begin(struct ast_channel *chan, char digit);
-/*! \brief Send a DTMF digit to a channel
-
- * Send a DTMF digit to a channel.
+/*!
+ * \brief Send a DTMF digit to a channel.
* \param chan channel to act upon
* \param digit the DTMF digit to send, encoded in ASCII
* \param duration the duration of the digit ending in ms
@@ -1257,7 +1460,8 @@ int ast_senddigit_begin(struct ast_channel *chan, char digit);
*/
int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duration);
-/*! \brief Receives a text string from a channel
+/*!
+ * \brief Receives a text string from a channel
* Read a string of text from a channel
* \param chan channel to act upon
* \param timeout timeout in milliseconds (0 for infinite wait)
@@ -1265,11 +1469,12 @@ int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duratio
*/
char *ast_recvtext(struct ast_channel *chan, int timeout);
-/*! \brief Browse channels in use
+/*!
+ * \brief Browse channels in use
* Browse the channels currently in use
* \param prev where you want to start in the channel list
* \return Returns the next channel in the list, NULL on end.
- * If it returns a channel, that channel *has been locked*!
+ * If it returns a channel, that channel *has been locked*!
*/
struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev);
@@ -1289,7 +1494,8 @@ struct ast_channel *ast_get_channel_by_exten_locked(const char *exten, const cha
struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *chan, const char *exten,
const char *context);
-/*! \brief Search for a channel based on the passed channel matching callback
+/*!
+ * \brief Search for a channel based on the passed channel matching callback
* Search for a channel based on the specified is_match callback, and return the
* first channel that we match. When returned, the channel will be locked. Note
* that the is_match callback is called with the passed channel locked, and should
@@ -1301,33 +1507,41 @@ struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *c
*/
struct ast_channel *ast_channel_search_locked(int (*is_match)(struct ast_channel *, void *), void *data);
-/*! ! \brief Waits for a digit
+/*!
+ * \brief Waits for a digit
* \param c channel to wait for a digit on
* \param ms how many milliseconds to wait
- * \return Returns <0 on error, 0 on no entry, and the digit on success. */
+ * \return Returns <0 on error, 0 on no entry, and the digit on success.
+ */
int ast_waitfordigit(struct ast_channel *c, int ms);
-/*! \brief Wait for a digit
- Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading.
+/*!
+ * \brief Wait for a digit
+ * Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading.
* \param c channel to wait for a digit on
* \param ms how many milliseconds to wait
* \param audiofd audio file descriptor to write to if audio frames are received
* \param ctrlfd control file descriptor to monitor for reading
- * \return Returns 1 if ctrlfd becomes available */
+ * \return Returns 1 if ctrlfd becomes available
+ */
int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd);
-/*! Reads multiple digits
+/*!
+ * \brief Reads multiple digits
* \param c channel to read from
* \param s string to read in to. Must be at least the size of your length
* \param len how many digits to read (maximum)
* \param timeout how long to timeout between digits
* \param rtimeout timeout to wait on the first digit
* \param enders digits to end the string
+ * \details
* Read in a digit string "s", max length "len", maximum timeout between
- digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
- for the first digit. Returns 0 on normal return, or 1 on a timeout. In the case of
- a timeout, any digits that were read before the timeout will still be available in s.
- RETURNS 2 in full version when ctrlfd is available, NOT 1*/
+ * digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
+ * for the first digit.
+ * \return Returns 0 on normal return, or 1 on a timeout. In the case of
+ * a timeout, any digits that were read before the timeout will still be available in s.
+ * RETURNS 2 in full version when ctrlfd is available, NOT 1
+ */
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders, int audiofd, int ctrlfd);
@@ -1343,28 +1557,37 @@ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, in
#define AST_BRIDGE_IGNORE_SIGS (1 << 4)
-/*! \brief Makes two channel formats compatible
+/*!
+ * \brief Makes two channel formats compatible
* \param c0 first channel to make compatible
* \param c1 other channel to make compatible
- * Set two channels to compatible formats -- call before ast_channel_bridge in general .
- * \return Returns 0 on success and -1 if it could not be done */
+ * \details
+ * Set two channels to compatible formats -- call before ast_channel_bridge in general.
+ * \return Returns 0 on success and -1 if it could not be done
+ */
int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
-/*! Bridge two channels together (early)
+/*!
+ * \brief Bridge two channels together (early)
* \param c0 first channel to bridge
* \param c1 second channel to bridge
+ * \details
* Bridge two channels (c0 and c1) together early. This implies either side may not be answered yet.
- * \return Returns 0 on success and -1 if it could not be done */
+ * \return Returns 0 on success and -1 if it could not be done
+ */
int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
-/*! Bridge two channels together
+/*!
+ * \brief Bridge two channels together
* \param c0 first channel to bridge
* \param c1 second channel to bridge
* \param config config for the channels
* \param fo destination frame(?)
* \param rc destination channel(?)
+ * \details
* Bridge two channels (c0 and c1) together. If an important frame occurs, we return that frame in
- *rf (remember, it could be NULL) and which channel (0 or 1) in rc */
+ * *rf (remember, it could be NULL) and which channel (0 or 1) in rc
+ */
/* int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); */
int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,
struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc);
@@ -1375,6 +1598,7 @@ int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,
* \param original channel to make a copy of
* \param clone copy of the original channel
*
+ * \details
* This is a very strange and freaky function used primarily for transfer. Suppose that
* "original" and "clone" are two channels in random situations. This function takes
* the guts out of "clone" and puts them into the "original" channel, then alerts the
@@ -1386,100 +1610,114 @@ int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,
*/
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
-/*! Gives the string form of a given cause code */
/*!
+ * \brief Gives the string form of a given cause code.
+ *
* \param state cause to get the description of
- * Give a name to a cause code
- * Returns the text form of the binary cause code given
+ * \return the text form of the binary cause code given
*/
const char *ast_cause2str(int state) attribute_pure;
-/*! Convert the string form of a cause code to a number */
/*!
+ * \brief Convert the string form of a cause code to a number
+ *
* \param name string form of the cause
- * Returns the cause code
+ * \return the cause code
*/
int ast_str2cause(const char *name) attribute_pure;
-/*! Gives the string form of a given channel state */
/*!
+ * \brief Gives the string form of a given channel state
+ *
* \param ast_channel_state state to get the name of
- * Give a name to a state
- * Returns the text form of the binary state given
+ * \return the text form of the binary state given
*/
const char *ast_state2str(enum ast_channel_state);
-/*! Gives the string form of a given transfer capability */
/*!
- * \param transfercapability transfercapabilty to get the name of
- * Give a name to a transfercapbility
- * See above
- * Returns the text form of the binary transfer capability
+ * \brief Gives the string form of a given transfer capability
+ *
+ * \param transfercapability transfer capability to get the name of
+ * \return the text form of the binary transfer capability
*/
char *ast_transfercapability2str(int transfercapability) attribute_const;
-/* Options: Some low-level drivers may implement "options" allowing fine tuning of the
- low level channel. See frame.h for options. Note that many channel drivers may support
- none or a subset of those features, and you should not count on this if you want your
- asterisk application to be portable. They're mainly useful for tweaking performance */
+/*
+ * Options: Some low-level drivers may implement "options" allowing fine tuning of the
+ * low level channel. See frame.h for options. Note that many channel drivers may support
+ * none or a subset of those features, and you should not count on this if you want your
+ * asterisk application to be portable. They're mainly useful for tweaking performance
+ */
-/*! Sets an option on a channel */
/*!
+ * \brief Sets an option on a channel
+ *
* \param channel channel to set options on
* \param option option to change
* \param data data specific to option
* \param datalen length of the data
* \param block blocking or not
+ * \details
* Set an option on a channel (see frame.h), optionally blocking awaiting the reply
- * Returns 0 on success and -1 on failure
+ * \return 0 on success and -1 on failure
*/
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block);
-/*! Pick the best codec */
-/* Choose the best codec... Uhhh... Yah. */
+/*! Pick the best codec
+ * Choose the best codec... Uhhh... Yah. */
int ast_best_codec(int fmts);
-/*! Checks the value of an option */
/*!
+ * \brief Checks the value of an option
+ *
* Query the value of an option
* Works similarly to setoption except only reads the options.
*/
int ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block);
-/*! Checks for HTML support on a channel */
-/*! Returns 0 if channel does not support HTML or non-zero if it does */
+/*!
+ * \brief Checks for HTML support on a channel
+ * \return 0 if channel does not support HTML or non-zero if it does
+ */
int ast_channel_supports_html(struct ast_channel *channel);
-/*! Sends HTML on given channel */
-/*! Send HTML or URL on link. Returns 0 on success or -1 on failure */
+/*!
+ * \brief Sends HTML on given channel
+ * Send HTML or URL on link.
+ * \return 0 on success or -1 on failure
+ */
int ast_channel_sendhtml(struct ast_channel *channel, int subclass, const char *data, int datalen);
-/*! Sends a URL on a given link */
-/*! Send URL on link. Returns 0 on success or -1 on failure */
+/*!
+ * \brief Sends a URL on a given link
+ * Send URL on link.
+ * \return 0 on success or -1 on failure
+ */
int ast_channel_sendurl(struct ast_channel *channel, const char *url);
-/*! Defers DTMF */
-/*! Defer DTMF so that you only read things like hangups and audio. Returns
- non-zero if channel was already DTMF-deferred or 0 if channel is just now
- being DTMF-deferred */
+/*!
+ * \brief Defers DTMF so that you only read things like hangups and audio.
+ * \return non-zero if channel was already DTMF-deferred or
+ * 0 if channel is just now being DTMF-deferred
+ */
int ast_channel_defer_dtmf(struct ast_channel *chan);
-/*! Undo defer. ast_read will return any dtmf characters that were queued */
+/*! Undo defer. ast_read will return any DTMF characters that were queued */
void ast_channel_undefer_dtmf(struct ast_channel *chan);
/*! Initiate system shutdown -- prevents new channels from being allocated.
- If "hangup" is non-zero, all existing channels will receive soft
- hangups */
+ * \param hangup If "hangup" is non-zero, all existing channels will receive soft
+ * hangups */
void ast_begin_shutdown(int hangup);
/*! Cancels an existing shutdown and returns to normal operation */
void ast_cancel_shutdown(void);
-/*! Returns number of active/allocated channels */
+/*! \return number of active/allocated channels */
int ast_active_channels(void);
-/*! Returns non-zero if Asterisk is being shut down */
+/*! \return non-zero if Asterisk is being shut down */
int ast_shutting_down(void);
/*! Activate a given generator */
@@ -1537,105 +1775,119 @@ int ast_autoservice_stop(struct ast_channel *chan);
*
* \param rate number of timer ticks per second
*
+ * \details
* If timers are supported, force a scheduled expiration on the
* timer fd, at which point we call the callback function / data
*
- * Call this function with a rate of 0 to turn off the timer ticks
+ * \note Call this function with a rate of 0 to turn off the timer ticks
*
* \version 1.6.1 changed samples parameter to rate, accomodates new timing methods
*/
int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data);
-/*! \brief Transfer a channel (if supported). Returns -1 on error, 0 if not supported
- and 1 if supported and requested
- \param chan current channel
- \param dest destination extension for transfer
-*/
+/*!
+ * \brief Transfer a channel (if supported).
+ * \retval -1 on error
+ * \retval 0 if not supported
+ * \retval 1 if supported and requested
+ * \param chan current channel
+ * \param dest destination extension for transfer
+ */
int ast_transfer(struct ast_channel *chan, char *dest);
-/*! \brief Start masquerading a channel
- XXX This is a seriously whacked out operation. We're essentially putting the guts of
- the clone channel into the original channel. Start by killing off the original
- channel's backend. I'm not sure we're going to keep this function, because
- while the features are nice, the cost is very high in terms of pure nastiness. XXX
- \param chan Channel to masquerade
-*/
+/*!
+ * \brief Start masquerading a channel
+ * \details
+ * XXX This is a seriously whacked out operation. We're essentially putting the guts of
+ * the clone channel into the original channel. Start by killing off the original
+ * channel's backend. I'm not sure we're going to keep this function, because
+ * while the features are nice, the cost is very high in terms of pure nastiness. XXX
+ * \param chan Channel to masquerade
+ */
int ast_do_masquerade(struct ast_channel *chan);
-/*! \brief Find bridged channel
- \param chan Current channel
-*/
+/*!
+ * \brief Find bridged channel
+ * \param chan Current channel
+ */
struct ast_channel *ast_bridged_channel(struct ast_channel *chan);
/*!
- \brief Inherits channel variable from parent to child channel
- \param parent Parent channel
- \param child Child channel
-
- Scans all channel variables in the parent channel, looking for those
- that should be copied into the child channel.
- Variables whose names begin with a single '_' are copied into the
- child channel with the prefix removed.
- Variables whose names begin with '__' are copied into the child
- channel with their names unchanged.
-*/
+ * \brief Inherits channel variable from parent to child channel
+ * \param parent Parent channel
+ * \param child Child channel
+ *
+ * \details
+ * Scans all channel variables in the parent channel, looking for those
+ * that should be copied into the child channel.
+ * Variables whose names begin with a single '_' are copied into the
+ * child channel with the prefix removed.
+ * Variables whose names begin with '__' are copied into the child
+ * channel with their names unchanged.
+ */
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child);
/*!
- \brief adds a list of channel variables to a channel
- \param chan the channel
- \param vars a linked list of variables
-
- Variable names can be for a regular channel variable or a dialplan function
- that has the ability to be written to.
-*/
+ * \brief adds a list of channel variables to a channel
+ * \param chan the channel
+ * \param vars a linked list of variables
+ *
+ * \details
+ * Variable names can be for a regular channel variable or a dialplan function
+ * that has the ability to be written to.
+ */
void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars);
/*!
- \brief An opaque 'object' structure use by silence generators on channels.
+ * \brief An opaque 'object' structure use by silence generators on channels.
*/
struct ast_silence_generator;
/*!
- \brief Starts a silence generator on the given channel.
- \param chan The channel to generate silence on
- \return An ast_silence_generator pointer, or NULL if an error occurs
-
- This function will cause SLINEAR silence to be generated on the supplied
- channel until it is disabled; if the channel cannot be put into SLINEAR
- mode then the function will fail.
-
- The pointer returned by this function must be preserved and passed to
- ast_channel_stop_silence_generator when you wish to stop the silence
- generation.
+ * \brief Starts a silence generator on the given channel.
+ * \param chan The channel to generate silence on
+ * \return An ast_silence_generator pointer, or NULL if an error occurs
+ *
+ * \details
+ * This function will cause SLINEAR silence to be generated on the supplied
+ * channel until it is disabled; if the channel cannot be put into SLINEAR
+ * mode then the function will fail.
+ *
+ * \note
+ * The pointer returned by this function must be preserved and passed to
+ * ast_channel_stop_silence_generator when you wish to stop the silence
+ * generation.
*/
struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan);
/*!
- \brief Stops a previously-started silence generator on the given channel.
- \param chan The channel to operate on
- \param state The ast_silence_generator pointer return by a previous call to
- ast_channel_start_silence_generator.
- \return nothing
-
- This function will stop the operating silence generator and return the channel
- to its previous write format.
+ * \brief Stops a previously-started silence generator on the given channel.
+ * \param chan The channel to operate on
+ * \param state The ast_silence_generator pointer return by a previous call to
+ * ast_channel_start_silence_generator.
+ * \return nothing
+ *
+ * \details
+ * This function will stop the operating silence generator and return the channel
+ * to its previous write format.
*/
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state);
/*!
- \brief Check if the channel can run in internal timing mode.
- \param chan The channel to check
- \return boolean
-
- This function will return 1 if internal timing is enabled and the timing
- device is available.
+ * \brief Check if the channel can run in internal timing mode.
+ * \param chan The channel to check
+ * \return boolean
+ *
+ * \details
+ * This function will return 1 if internal timing is enabled and the timing
+ * device is available.
*/
int ast_internal_timing_enabled(struct ast_channel *chan);
/* Misc. functions below */
-/*! \brief if fd is a valid descriptor, set *pfd with the descriptor
+/*!
+ * \brief if fd is a valid descriptor, set *pfd with the descriptor
* \return Return 1 (not -1!) if added, 0 otherwise (so we can add the
* return value to the index into the array)
*/
@@ -1678,12 +1930,14 @@ static inline void timersub(struct timeval *tvend, struct timeval *tvstart, stru
}
#endif
-/*! \brief Waits for activity on a group of channels
+/*!
+ * \brief Waits for activity on a group of channels
* \param nfds the maximum number of file descriptors in the sets
* \param rfds file descriptors to check for read availability
* \param wfds file descriptors to check for write availability
* \param efds file descriptors to check for exceptions (OOB data)
* \param tvp timeout while waiting for events
+ * \details
* This is the same as a standard select(), except it guarantees the
* behaviour where the passed struct timeval is updated with how much
* time was not slept while waiting for the specified events
@@ -1740,23 +1994,23 @@ ast_group_t ast_get_group(const char *s);
/*! \brief print call- and pickup groups into buffer */
char *ast_print_group(char *buf, int buflen, ast_group_t group);
-/*! \brief Convert enum channelreloadreason to text string for manager event
- \param reason Enum channelreloadreason - reason for reload (manager, cli, start etc)
-*/
+/*!
+ * \brief Convert enum channelreloadreason to text string for manager event
+ * \param reason The reason for reload (manager, cli, start etc)
+ */
const char *channelreloadreason2txt(enum channelreloadreason reason);
/*! \brief return an ast_variable list of channeltypes */
struct ast_variable *ast_channeltype_list(void);
/*!
- \brief return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument
- \param reason The integer argument, usually taken from AST_CONTROL_ macros
- \return char pointer explaining the code
+ * \brief return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument
+ * \param reason The integer argument, usually taken from AST_CONTROL_ macros
+ * \return char pointer explaining the code
*/
const char *ast_channel_reason2str(int reason);
-/*! \brief channel group info
- */
+/*! \brief channel group info */
struct ast_group_info {
struct ast_channel *chan;
char *category;
@@ -1765,6 +2019,295 @@ struct ast_group_info {
};
+/*!
+ * \since 1.6.3
+ * \brief Copy the source caller information to the destination caller.
+ *
+ * \param dest Destination caller
+ * \param src Source caller
+ *
+ * \return Nothing
+ */
+void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid *src);
+
+/*!
+ * \since 1.6.3
+ * \brief Initialize the given connected line structure.
+ *
+ * \param init Connected line structure to initialize.
+ *
+ * \return Nothing
+ */
+void ast_party_connected_line_init(struct ast_party_connected_line *init);
+
+/*!
+ * \since 1.6.3
+ * \brief Copy the source connected line information to the destination connected line.
+ *
+ * \param dest Destination connected line
+ * \param src Source connected line
+ *
+ * \return Nothing
+ */
+void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src);
+
+/*!
+ * \since 1.6.3
+ * \brief Initialize the given connected line structure using the given
+ * guide for a set update operation.
+ *
+ * \details
+ * The initialization is needed to allow a set operation to know if a
+ * value needs to be updated. Simple integers need the guide's original
+ * value in case the set operation is not trying to set a new value.
+ * String values are simply set to NULL pointers if they are not going
+ * to be updated.
+ *
+ * \param init Connected line structure to initialize.
+ * \param guide Source connected line to use as a guide in initializing.
+ *
+ * \return Nothing
+ */
+void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide);
+
+/*!
+ * \since 1.6.3
+ * \brief Set the connected line information based on another connected line source
+ *
+ * This is similar to ast_party_connected_line_copy, except that NULL values for
+ * strings in the src parameter indicate not to update the corresponding dest values.
+ *
+ * \param src The source connected line to use as a guide to set the dest
+ * \param dest The connected line one wishes to update
+ *
+ * \return Nada
+ */
+void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src);
+
+/*!
+ * \since 1.6.3
+ * \brief Collect the caller party information into a connected line structure.
+ *
+ * \param connected Collected caller information for the connected line
+ * \param cid Caller information.
+ *
+ * \return Nothing
+ *
+ * \warning This is a shallow copy.
+ * \warning DO NOT call ast_party_connected_line_free() on the filled in
+ * connected line structure!
+ */
+void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_callerid *cid);
+
+/*!
+ * \since 1.6.3
+ * \brief Destroy the connected line information contents
+ *
+ * \param doomed The connected line information to destroy.
+ *
+ * \return Nothing
+ */
+void ast_party_connected_line_free(struct ast_party_connected_line *doomed);
+
+/*!
+ * \since 1.6.3
+ * \brief Copy the source redirecting information to the destination redirecting.
+ *
+ * \param dest Destination redirecting
+ * \param src Source redirecting
+ *
+ * \return Nothing
+ */
+void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src);
+
+/*!
+ * \since 1.6.3
+ * \brief Initialize the given redirecting id structure using the given guide
+ * for a set update operation.
+ *
+ * \details
+ * The initialization is needed to allow a set operation to know if a
+ * value needs to be updated. Simple integers need the guide's original
+ * value in case the set operation is not trying to set a new value.
+ * String values are simply set to NULL pointers if they are not going
+ * to be updated.
+ *
+ * \param init Redirecting id structure to initialize.
+ * \param guide Source redirecting id to use as a guide in initializing.
+ *
+ * \return Nothing
+ */
+void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide);
+
+/*!
+ * \since 1.6.3
+ * \brief Destroy the redirecting information contents
+ *
+ * \param doomed The redirecting information to destroy.
+ *
+ * \return Nothing
+ */
+void ast_party_redirecting_free(struct ast_party_redirecting *doomed);
+
+/*!
+ * \since 1.6.3
+ * \brief Copy the caller information to the connected line information.
+ *
+ * \param dest Destination connected line information
+ * \param src Source caller information
+ *
+ * \return Nothing
+ *
+ * \note Assumes locks are already acquired
+ */
+void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_callerid *src);
+
+/*!
+ * \since 1.6.3
+ * \brief Copy the connected line information to the caller information.
+ *
+ * \param dest Destination caller information
+ * \param src Source connected line information
+ *
+ * \return Nothing
+ *
+ * \note Assumes locks are already acquired
+ */
+void ast_connected_line_copy_to_caller(struct ast_callerid *dest, const struct ast_party_connected_line *src);
+
+/*!
+ * \since 1.6.3
+ * \brief Set the connected line information in the Asterisk channel
+ *
+ * \param chan Asterisk channel to set connected line information
+ * \param connected Connected line information
+ *
+ * \return Nothing
+ *
+ * \note The channel does not need to be locked before calling this function.
+ */
+void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected);
+
+/*!
+ * \since 1.6.3
+ * \brief Build the connected line information data frame.
+ *
+ * \param data Buffer to fill with the frame data
+ * \param datalen Size of the buffer to fill
+ * \param connected Connected line information
+ *
+ * \retval -1 if error
+ * \retval Amount of data buffer used
+ */
+int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected);
+
+/*!
+ * \since 1.6.3
+ * \brief Parse connected line indication frame data
+ *
+ * \param data Buffer with the frame data to parse
+ * \param datalen Size of the buffer
+ * \param connected Extracted connected line information
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ *
+ * \note The filled in connected line structure needs to be initialized by
+ * ast_party_connected_line_set_init() before calling. If defaults are not
+ * required use ast_party_connected_line_init().
+ * \note The filled in connected line structure needs to be destroyed by
+ * ast_party_connected_line_free() when it is no longer needed.
+ */
+int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected);
+
+/*!
+ * \since 1.6.3
+ * \brief Indicate that the connected line information has changed
+ *
+ * \param chan Asterisk channel to indicate connected line information
+ * \param connected Connected line information
+ *
+ * \return Nothing
+ */
+void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected);
+
+/*!
+ * \since 1.6.3
+ * \brief Queue a connected line update frame on a channel
+ *
+ * \param chan Asterisk channel to indicate connected line information
+ * \param connected Connected line information
+ *
+ * \return Nothing
+ */
+void ast_channel_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected);
+
+/*!
+ * \since 1.6.3
+ * \brief Set the redirecting id information in the Asterisk channel
+ *
+ * \param chan Asterisk channel to set redirecting id information
+ * \param redirecting Redirecting id information
+ *
+ * \return Nothing
+ *
+ * \note The channel does not need to be locked before calling this function.
+ */
+void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
+
+/*!
+ * \since 1.6.3
+ * \brief Build the redirecting id data frame.
+ *
+ * \param data Buffer to fill with the frame data
+ * \param datalen Size of the buffer to fill
+ * \param redirecting Redirecting id information
+ *
+ * \retval -1 if error
+ * \retval Amount of data buffer used
+ */
+int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting);
+
+/*!
+ * \since 1.6.3
+ * \brief Parse redirecting indication frame data
+ *
+ * \param data Buffer with the frame data to parse
+ * \param datalen Size of the buffer
+ * \param redirecting Extracted redirecting id information
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ *
+ * \note The filled in id structure needs to be initialized by
+ * ast_party_redirecting_set_init() before calling.
+ * \note The filled in id structure needs to be destroyed by
+ * ast_party_redirecting_free() when it is no longer needed.
+ */
+int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct ast_party_redirecting *redirecting);
+
+/*!
+ * \since 1.6.3
+ * \brief Indicate that the redirecting id has changed
+ *
+ * \param chan Asterisk channel to indicate redirecting id information
+ * \param redirecting Redirecting id information
+ *
+ * \return Nothing
+ */
+void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
+
+/*!
+ * \since 1.6.3
+ * \brief Queue a redirecting update frame on a channel
+ *
+ * \param chan Asterisk channel to indicate redirecting id information
+ * \param redirecting Redirecting id information
+ *
+ * \return Nothing
+ */
+void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index cf4474e17..f7e8b20ad 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -39,53 +39,55 @@ struct ast_codec_pref {
char framing[32];
};
-/*! \page Def_Frame AST Multimedia and signalling frames
- \section Def_AstFrame What is an ast_frame ?
- A frame of data read used to communicate between
- between channels and applications.
- Frames are divided into frame types and subclasses.
-
- \par Frame types
- \arg \b VOICE: Voice data, subclass is codec (AST_FORMAT_*)
- \arg \b VIDEO: Video data, subclass is codec (AST_FORMAT_*)
- \arg \b DTMF: A DTMF digit, subclass is the digit
- \arg \b IMAGE: Image transport, mostly used in IAX
- \arg \b TEXT: Text messages and character by character (real time text)
- \arg \b HTML: URL's and web pages
- \arg \b MODEM: Modulated data encodings, such as T.38 and V.150
- \arg \b IAX: Private frame type for the IAX protocol
- \arg \b CNG: Comfort noice frames
- \arg \b CONTROL: A control frame, subclass defined as AST_CONTROL_
- \arg \b NULL: Empty, useless frame
-
- \par Files
- \arg frame.h Definitions
- \arg frame.c Function library
- \arg \ref Def_Channel Asterisk channels
- \section Def_ControlFrame Control Frames
- Control frames send signalling information between channels
- and devices. They are prefixed with AST_CONTROL_, like AST_CONTROL_FRAME_HANGUP
- \arg \b HANGUP The other end has hungup
- \arg \b RING Local ring
- \arg \b RINGING The other end is ringing
- \arg \b ANSWER The other end has answered
- \arg \b BUSY Remote end is busy
- \arg \b TAKEOFFHOOK Make it go off hook (what's "it" ? )
- \arg \b OFFHOOK Line is off hook
- \arg \b CONGESTION Congestion (circuit is busy, not available)
- \arg \b FLASH Other end sends flash hook
- \arg \b WINK Other end sends wink
- \arg \b OPTION Send low-level option
- \arg \b RADIO_KEY Key radio (see app_rpt.c)
- \arg \b RADIO_UNKEY Un-key radio (see app_rpt.c)
- \arg \b PROGRESS Other end indicates call progress
- \arg \b PROCEEDING Indicates proceeding
- \arg \b HOLD Call is placed on hold
- \arg \b UNHOLD Call is back from hold
- \arg \b VIDUPDATE Video update requested
- \arg \b SRCUPDATE The source of media has changed
-
-*/
+/*!
+ * \page Def_Frame AST Multimedia and signalling frames
+ * \section Def_AstFrame What is an ast_frame ?
+ * A frame of data read used to communicate between
+ * between channels and applications.
+ * Frames are divided into frame types and subclasses.
+ *
+ * \par Frame types
+ * \arg \b VOICE: Voice data, subclass is codec (AST_FORMAT_*)
+ * \arg \b VIDEO: Video data, subclass is codec (AST_FORMAT_*)
+ * \arg \b DTMF: A DTMF digit, subclass is the digit
+ * \arg \b IMAGE: Image transport, mostly used in IAX
+ * \arg \b TEXT: Text messages and character by character (real time text)
+ * \arg \b HTML: URL's and web pages
+ * \arg \b MODEM: Modulated data encodings, such as T.38 and V.150
+ * \arg \b IAX: Private frame type for the IAX protocol
+ * \arg \b CNG: Comfort noice frames
+ * \arg \b CONTROL:A control frame, subclass defined as AST_CONTROL_
+ * \arg \b NULL: Empty, useless frame
+ *
+ * \par Files
+ * \arg frame.h Definitions
+ * \arg frame.c Function library
+ * \arg \ref Def_Channel Asterisk channels
+ * \section Def_ControlFrame Control Frames
+ * Control frames send signalling information between channels
+ * and devices. They are prefixed with AST_CONTROL_, like AST_CONTROL_FRAME_HANGUP
+ * \arg \b HANGUP The other end has hungup
+ * \arg \b RING Local ring
+ * \arg \b RINGING The other end is ringing
+ * \arg \b ANSWER The other end has answered
+ * \arg \b BUSY Remote end is busy
+ * \arg \b TAKEOFFHOOK Make it go off hook (what's "it" ? )
+ * \arg \b OFFHOOK Line is off hook
+ * \arg \b CONGESTION Congestion (circuit is busy, not available)
+ * \arg \b FLASH Other end sends flash hook
+ * \arg \b WINK Other end sends wink
+ * \arg \b OPTION Send low-level option
+ * \arg \b RADIO_KEY Key radio (see app_rpt.c)
+ * \arg \b RADIO_UNKEY Un-key radio (see app_rpt.c)
+ * \arg \b PROGRESS Other end indicates call progress
+ * \arg \b PROCEEDING Indicates proceeding
+ * \arg \b HOLD Call is placed on hold
+ * \arg \b UNHOLD Call is back from hold
+ * \arg \b VIDUPDATE Video update requested
+ * \arg \b SRCUPDATE The source of media has changed
+ * \arg \b CONNECTED_LINE Connected line has changed
+ * \arg \b REDIRECTING Call redirecting information has changed.
+ */
/*!
* \brief Frame types
@@ -320,6 +322,8 @@ enum ast_control_frame_type {
AST_CONTROL_T38 = 19, /*!< T38 state change request/notification */
AST_CONTROL_SRCUPDATE = 20, /*!< Indicate source of media has changed */
AST_CONTROL_TRANSFER = 21, /*!< Indicate status of a transfer request */
+ AST_CONTROL_CONNECTED_LINE = 22, /*!< Indicate connected line has changed */
+ AST_CONTROL_REDIRECTING = 23 /*!< Indicate redirecting id has changed */
};
enum ast_control_t38 {
diff --git a/main/callerid.c b/main/callerid.c
index a7836904e..57119958a 100644
--- a/main/callerid.c
+++ b/main/callerid.c
@@ -922,8 +922,10 @@ int callerid_generate(unsigned char *buf, const char *number, const char *name,
return bytes;
}
-/*! \brief Clean up phone string
- * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
+/*!
+ * \brief Clean up phone string
+ * \details
+ * Remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
* Basically, remove anything that could be invalid in a pattern.
*/
void ast_shrink_phone_number(char *n)
@@ -958,11 +960,13 @@ void ast_shrink_phone_number(char *n)
n[y] = '\0';
}
-/*! \brief Checks if phone number consists of valid characters
- \param exten String that needs to be checked
- \param valid Valid characters in string
- \return 1 if valid string, 0 if string contains invalid characters
-*/
+/*!
+ * \brief Checks if phone number consists of valid characters
+ * \param exten String that needs to be checked
+ * \param valid Valid characters in string
+ * \retval 1 if valid string
+ * \retval 0 if string contains invalid characters
+ */
static int ast_is_valid_string(const char *exten, const char *valid)
{
int x;
@@ -975,34 +979,16 @@ static int ast_is_valid_string(const char *exten, const char *valid)
return 1;
}
-/*! \brief checks if string consists only of digits and * \# and +
- \return 1 if string is valid AST phone number
- \return 0 if not
-*/
int ast_isphonenumber(const char *n)
{
return ast_is_valid_string(n, "0123456789*#+");
}
-/*! \brief checks if string consists only of digits and ( ) - * \# and +
- Pre-qualifies the string for ast_shrink_phone_number()
- \return 1 if string is valid AST shrinkable phone number
- \return 0 if not
-*/
int ast_is_shrinkable_phonenumber(const char *exten)
{
return ast_is_valid_string(exten, "0123456789*#+()-.");
}
-/*!
- * \brief Destructively parse instr for caller id information
- * \return always returns 0, as the code always returns something.
- * \note XXX 'name' is not parsed consistently e.g. we have
- * input location name
- * " foo bar " <123> 123 ' foo bar ' (with spaces around)
- * " foo bar " NULL 'foo bar' (without spaces around)
- * The parsing of leading and trailing space/quotes should be more consistent.
- */
int ast_callerid_parse(char *instr, char **name, char **location)
{
char *ns, *ne, *ls, *le;
@@ -1103,68 +1089,191 @@ int ast_callerid_split(const char *buf, char *name, int namelen, char *num, int
return 0;
}
-/*! \brief Translation table for Caller ID Presentation settings */
-static struct {
- int val;
+struct ast_value_translation {
+ int value;
const char *name;
const char *description;
-} pres_types[] = {
- { AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened"},
- { AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen"},
- { AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen"},
- { AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number"},
- { AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened"},
- { AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen"},
- { AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen"},
- { AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number"},
- { AST_PRES_NUMBER_NOT_AVAILABLE, "unavailable", "Number Unavailable"},
};
-/*! \brief Convert caller ID text code to value
- used in config file parsing
- \param data text string
- \return value AST_PRES_ from callerid.h
-*/
+/*! \brief Translation table for Caller ID Presentation settings */
+static const struct ast_value_translation pres_types[] = {
+/* *INDENT-OFF* */
+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened" },
+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen" },
+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen" },
+ { AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number" },
+
+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened" },
+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen" },
+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen" },
+ { AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number" },
+
+ { AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER, "unavailable", "Number Unavailable" }, /* Default name to value conversion. */
+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED, "unavailable", "Number Unavailable" },
+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_FAILED_SCREEN, "unavailable", "Number Unavailable" },
+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_PASSED_SCREEN, "unavailable", "Number Unavailable" },
+/* *INDENT-ON* */
+};
+
+/*!
+ * \brief Convert caller ID text code to value (used in config file parsing)
+ * \param data text string from config file
+ * \retval value AST_PRES_ from callerid.h
+ * \retval -1 if not in table
+ */
int ast_parse_caller_presentation(const char *data)
{
- int i;
+ int index;
- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
- if (!strcasecmp(pres_types[i].name, data))
- return pres_types[i].val;
+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+ if (!strcasecmp(pres_types[index].name, data)) {
+ return pres_types[index].value;
+ }
}
return -1;
}
-/*! \brief Convert caller ID pres value to explanatory string
- \param data value (see callerid.h AST_PRES_ )
- \return string for human presentation
-*/
+/*!
+ * \brief Convert caller ID pres value to explanatory string
+ * \param data AST_PRES_ value from callerid.h
+ * \return string for human presentation
+ */
const char *ast_describe_caller_presentation(int data)
{
- int i;
+ int index;
- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
- if (pres_types[i].val == data)
- return pres_types[i].description;
+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+ if (pres_types[index].value == data) {
+ return pres_types[index].description;
+ }
}
return "unknown";
}
-/*! \brief Convert caller ID pres value to text code
- \param data text string
- \return string for config file
-*/
+/*!
+ * \brief Convert caller ID pres value to text code
+ * \param data AST_PRES_ value from callerid.h
+ * \return string for config file
+ */
const char *ast_named_caller_presentation(int data)
{
- int i;
+ int index;
- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
- if (pres_types[i].val == data)
- return pres_types[i].name;
+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+ if (pres_types[index].value == data) {
+ return pres_types[index].name;
+ }
}
return "unknown";
}
+
+/*! \brief Translation table for redirecting reason settings */
+static const struct ast_value_translation redirecting_reason_types[] = {
+/* *INDENT-OFF* */
+ { AST_REDIRECTING_REASON_UNKNOWN, "unknown", "Unknown" },
+ { AST_REDIRECTING_REASON_USER_BUSY, "cfb", "Call Forwarding Busy" },
+ { AST_REDIRECTING_REASON_NO_ANSWER, "cfnr", "Call Forwarding No Reply" },
+ { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable", "Callee is Unavailable" },
+ { AST_REDIRECTING_REASON_UNCONDITIONAL, "cfu", "Call Forwarding Unconditional" },
+ { AST_REDIRECTING_REASON_TIME_OF_DAY, "time_of_day", "Time of Day" },
+ { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "dnd", "Do Not Disturb" },
+ { AST_REDIRECTING_REASON_DEFLECTION, "deflection", "Call Deflection" },
+ { AST_REDIRECTING_REASON_FOLLOW_ME, "follow_me", "Follow Me" },
+ { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out_of_order", "Called DTE Out-Of-Order" },
+ { AST_REDIRECTING_REASON_AWAY, "away", "Callee is Away" },
+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", "Call Forwarding By The Called DTE" },
+/* *INDENT-ON* */
+};
+
+int ast_redirecting_reason_parse(const char *data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+ if (!strcasecmp(redirecting_reason_types[index].name, data)) {
+ return redirecting_reason_types[index].value;
+ }
+ }
+
+ return -1;
+}
+
+const char *ast_redirecting_reason_describe(int data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+ if (redirecting_reason_types[index].value == data) {
+ return redirecting_reason_types[index].description;
+ }
+ }
+
+ return "not-known";
+}
+
+const char *ast_redirecting_reason_name(int data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+ if (redirecting_reason_types[index].value == data) {
+ return redirecting_reason_types[index].name;
+ }
+ }
+
+ return "not-known";
+}
+
+/*! \brief Translation table for connected line update source settings */
+static const struct ast_value_translation connected_line_source_types[] = {
+/* *INDENT-OFF* */
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN, "unknown", "Unknown" },
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, "answer", "Normal Call Answering" },
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION, "diversion", "Call Diversion (Deprecated, use REDIRECTING)" },
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, "transfer_active", "Call Transfer(Active)" },
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, "transfer", "Call Transfer(Active)" },/* Old name must come after new name. */
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, "transfer_alerting", "Call Transfer(Alerting)" }
+/* *INDENT-ON* */
+};
+
+int ast_connected_line_source_parse(const char *data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+ if (!strcasecmp(connected_line_source_types[index].name, data)) {
+ return connected_line_source_types[index].value;
+ }
+ }
+
+ return -1;
+}
+
+const char *ast_connected_line_source_describe(int data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+ if (connected_line_source_types[index].value == data) {
+ return connected_line_source_types[index].description;
+ }
+ }
+
+ return "not-known";
+}
+
+const char *ast_connected_line_source_name(int data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+ if (connected_line_source_types[index].value == data) {
+ return connected_line_source_types[index].name;
+ }
+ }
+
+ return "not-known";
+}
diff --git a/main/channel.c b/main/channel.c
index 9b2ad405c..718677b39 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -796,6 +796,13 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
return NULL;
}
+ if (!(tmp->cid.cid_name = ast_strdup(cid_name)) || !(tmp->cid.cid_num = ast_strdup(cid_num))) {
+ ast_string_field_free_memory(tmp);
+ sched_context_destroy(tmp->sched);
+ ast_free(tmp);
+ return NULL;
+ }
+
#ifdef HAVE_EPOLL
tmp->epfd = epoll_create(25);
#endif
@@ -866,9 +873,6 @@ alertpipe_failed:
ast_string_field_build(tmp, uniqueid, "%s-%li.%d", ast_config_AST_SYSTEM_NAME,
(long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
}
-
- tmp->cid.cid_name = ast_strdup(cid_name);
- tmp->cid.cid_num = ast_strdup(cid_num);
if (!ast_strlen_zero(name_fmt)) {
/* Almost every channel is calling this function, and setting the name via the ast_string_field_build() call.
@@ -1311,6 +1315,279 @@ static void free_cid(struct ast_callerid *cid)
cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = cid->cid_rdnis = NULL;
}
+/*!
+ * \internal
+ * \brief Initialize the given party id structure.
+ *
+ * \param init Party id structure to initialize.
+ *
+ * \return Nothing
+ */
+static void ast_party_id_init(struct ast_party_id *init)
+{
+ init->number = NULL;
+ init->name = NULL;
+ init->number_type = 0; /* Unknown */
+ init->number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+}
+
+/*!
+ * \internal
+ * \brief Copy the source party id information to the destination party id.
+ *
+ * \param dest Destination party id
+ * \param src Source party id
+ *
+ * \return Nothing
+ */
+static void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
+{
+ if (dest == src) {
+ /* Don't copy to self */
+ return;
+ }
+
+ if (dest->number) {
+ ast_free(dest->number);
+ }
+ dest->number = ast_strdup(src->number);
+
+ if (dest->name) {
+ ast_free(dest->name);
+ }
+ dest->name = ast_strdup(src->name);
+
+ dest->number_type = src->number_type;
+ dest->number_presentation = src->number_presentation;
+}
+
+/*!
+ * \internal
+ * \brief Initialize the given party id structure using the given guide
+ * for a set update operation.
+ *
+ * \details
+ * The initialization is needed to allow a set operation to know if a
+ * value needs to be updated. Simple integers need the guide's original
+ * value in case the set operation is not trying to set a new value.
+ * String values are simply set to NULL pointers if they are not going
+ * to be updated.
+ *
+ * \param init Party id structure to initialize.
+ * \param guide Source party id to use as a guide in initializing.
+ *
+ * \return Nothing
+ */
+static void ast_party_id_set_init(struct ast_party_id *init, const struct ast_party_id *guide)
+{
+ init->number = NULL;
+ init->name = NULL;
+ init->number_type = guide->number_type;
+ init->number_presentation = guide->number_presentation;
+}
+
+/*!
+ * \internal
+ * \brief Set the source party id information into the destination party id.
+ *
+ * \param dest Destination party id
+ * \param src Source party id
+ *
+ * \return Nothing
+ */
+static void ast_party_id_set(struct ast_party_id *dest, const struct ast_party_id *src)
+{
+ if (dest == src) {
+ /* Don't set to self */
+ return;
+ }
+
+ if (src->name && src->name != dest->name) {
+ if (dest->name) {
+ ast_free(dest->name);
+ }
+ dest->name = ast_strdup(src->name);
+ }
+
+ if (src->number && src->number != dest->number) {
+ if (dest->number) {
+ ast_free(dest->number);
+ }
+ dest->number = ast_strdup(src->number);
+ }
+
+ dest->number_type = src->number_type;
+ dest->number_presentation = src->number_presentation;
+}
+
+/*!
+ * \internal
+ * \brief Destroy the party id contents
+ *
+ * \param doomed The party id to destroy.
+ *
+ * \return Nothing
+ */
+static void ast_party_id_free(struct ast_party_id *doomed)
+{
+ if (doomed->number) {
+ ast_free(doomed->number);
+ doomed->number = NULL;
+ }
+
+ if (doomed->name) {
+ ast_free(doomed->name);
+ doomed->name = NULL;
+ }
+}
+
+void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid *src)
+{
+ if (dest == src) {
+ /* Don't copy to self */
+ return;
+ }
+
+#if 1
+ /* Copy caller-id specific information ONLY from struct ast_callerid */
+ if (dest->cid_num)
+ {
+ ast_free(dest->cid_num);
+ }
+ dest->cid_num = ast_strdup(src->cid_num);
+
+ if (dest->cid_name)
+ {
+ ast_free(dest->cid_name);
+ }
+ dest->cid_name = ast_strdup(src->cid_name);
+
+ dest->cid_ton = src->cid_ton;
+ dest->cid_pres = src->cid_pres;
+
+
+ if (dest->cid_ani)
+ {
+ ast_free(dest->cid_ani);
+ }
+ dest->cid_ani = ast_strdup(src->cid_ani);
+
+ dest->cid_ani2 = src->cid_ani2;
+
+#else
+
+ /* The src and dest parameter types will become struct ast_party_caller ptrs. */
+ /* This is future code */
+
+ ast_party_id_copy(&dest->id, &src->id);
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+
+ dest->ani2 = src->ani2;
+#endif
+}
+
+void ast_party_connected_line_init(struct ast_party_connected_line *init)
+{
+ ast_party_id_init(&init->id);
+ init->ani = NULL;
+ init->ani2 = 0;
+ init->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
+}
+
+void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
+{
+ if (dest == src) {
+ /* Don't copy to self */
+ return;
+ }
+
+ ast_party_id_copy(&dest->id, &src->id);
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+
+ dest->ani2 = src->ani2;
+ dest->source = src->source;
+}
+
+void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
+{
+ ast_party_id_set_init(&init->id, &guide->id);
+ init->ani = NULL;
+ init->ani2 = guide->ani2;
+ init->source = guide->source;
+}
+
+void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
+{
+ ast_party_id_set(&dest->id, &src->id);
+
+ if (src->ani && src->ani != dest->ani) {
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+ }
+
+ dest->ani2 = src->ani2;
+ dest->source = src->source;
+}
+
+void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_callerid *cid)
+{
+ connected->id.number = cid->cid_num;
+ connected->id.name = cid->cid_name;
+ connected->id.number_type = cid->cid_ton;
+ connected->id.number_presentation = cid->cid_pres;
+
+ connected->ani = cid->cid_ani;
+ connected->ani2 = cid->cid_ani2;
+ connected->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
+}
+
+void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
+{
+ ast_party_id_free(&doomed->id);
+
+ if (doomed->ani) {
+ ast_free(doomed->ani);
+ doomed->ani = NULL;
+ }
+}
+
+void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
+{
+ if (dest == src) {
+ /* Don't copy to self */
+ return;
+ }
+
+ ast_party_id_copy(&dest->from, &src->from);
+ ast_party_id_copy(&dest->to, &src->to);
+ dest->count = src->count;
+ dest->reason = src->reason;
+}
+
+void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide)
+{
+ ast_party_id_set_init(&init->from, &guide->from);
+ ast_party_id_set_init(&init->to, &guide->to);
+ init->count = guide->count;
+ init->reason = guide->reason;
+}
+
+void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
+{
+ ast_party_id_free(&doomed->from);
+ ast_party_id_free(&doomed->to);
+}
+
/*! \brief Free a channel structure */
void ast_channel_free(struct ast_channel *chan)
{
@@ -1374,7 +1651,11 @@ void ast_channel_free(struct ast_channel *chan)
ast_translator_free_path(chan->writetrans);
if (chan->pbx)
ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
+
free_cid(&chan->cid);
+ ast_party_connected_line_free(&chan->connected);
+ ast_party_redirecting_free(&chan->redirecting);
+
/* Close pipes if appropriate */
if ((fd = chan->alertpipe[0]) > -1)
close(fd);
@@ -2396,6 +2677,8 @@ int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd)
case AST_CONTROL_RINGING:
case AST_CONTROL_ANSWER:
case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
/* Unimportant */
break;
default:
@@ -2994,8 +3277,10 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
case AST_CONTROL_ANSWER:
case AST_CONTROL_HANGUP:
case AST_CONTROL_T38:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
case AST_CONTROL_TRANSFER:
- return 0;
+ break;
case AST_CONTROL_CONGESTION:
case AST_CONTROL_BUSY:
@@ -3016,7 +3301,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
* in switch statements. */
enum ast_control_frame_type condition = _condition;
struct ast_tone_zone_sound *ts = NULL;
- int res = -1;
+ int res;
ast_channel_lock(chan);
@@ -3025,10 +3310,41 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
ast_channel_unlock(chan);
return -1;
}
+ switch (condition) {
+ case AST_CONTROL_CONNECTED_LINE:
+ {
+ struct ast_party_connected_line connected;
+
+ ast_party_connected_line_set_init(&connected, &chan->connected);
+ res = ast_connected_line_parse_data(data, datalen, &connected);
+ if (!res) {
+ ast_channel_set_connected_line(chan, &connected);
+ }
+ ast_party_connected_line_free(&connected);
+ }
+ break;
+
+ case AST_CONTROL_REDIRECTING:
+ {
+ struct ast_party_redirecting redirecting;
+ ast_party_redirecting_set_init(&redirecting, &chan->redirecting);
+ res = ast_redirecting_parse_data(data, datalen, &redirecting);
+ if (!res) {
+ ast_channel_set_redirecting(chan, &redirecting);
+ }
+ ast_party_redirecting_free(&redirecting);
+ }
+ break;
+
+ default:
+ break;
+ }
if (chan->tech->indicate) {
/* See if the channel driver can handle this condition. */
res = chan->tech->indicate(chan, condition, data, datalen);
+ } else {
+ res = -1;
}
ast_channel_unlock(chan);
@@ -3082,6 +3398,8 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
case AST_CONTROL_UNHOLD:
case AST_CONTROL_T38:
case AST_CONTROL_TRANSFER:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
/* Nothing left to do for these. */
res = 0;
break;
@@ -3544,6 +3862,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
struct ast_channel *chan;
int res = 0;
int last_subclass = 0;
+ struct ast_party_connected_line connected;
if (outstate)
*outstate = 0;
@@ -3574,7 +3893,13 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
if (oh->account)
ast_cdr_setaccount(chan, oh->account);
}
+
ast_set_callerid(chan, cid_num, cid_name, cid_num);
+ ast_party_connected_line_set_init(&connected, &chan->connected);
+ connected.id.number = (char *) cid_num;
+ connected.id.name = (char *) cid_name;
+ connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+ ast_channel_set_connected_line(chan, &connected);
if (ast_call(chan, data, 0)) { /* ast_call failed... */
ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
@@ -3613,6 +3938,8 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
case AST_CONTROL_UNHOLD:
case AST_CONTROL_VIDUPDATE:
case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
case -1: /* Ignore -- just stopping indications */
break;
@@ -4088,7 +4415,11 @@ int ast_do_masquerade(struct ast_channel *original)
struct ast_frame *current;
const struct ast_channel_tech *t;
void *t_pvt;
- struct ast_callerid tmpcid;
+ union {
+ struct ast_callerid cid;
+ struct ast_party_connected_line connected;
+ struct ast_party_redirecting redirecting;
+ } exchange;
struct ast_channel *clonechan = original->masq;
struct ast_cdr *cdr;
int rformat = original->readformat;
@@ -4269,11 +4600,19 @@ int ast_do_masquerade(struct ast_channel *original)
/* Stream stuff stays the same */
/* Keep the original state. The fixup code will need to work with it most likely */
- /* Just swap the whole structures, nevermind the allocations, they'll work themselves
- out. */
- tmpcid = original->cid;
+ /*
+ * Just swap the whole structures, nevermind the allocations,
+ * they'll work themselves out.
+ */
+ exchange.cid = original->cid;
original->cid = clonechan->cid;
- clonechan->cid = tmpcid;
+ clonechan->cid = exchange.cid;
+ exchange.connected = original->connected;
+ original->connected = clonechan->connected;
+ clonechan->connected = exchange.connected;
+ exchange.redirecting = original->redirecting;
+ original->redirecting = clonechan->redirecting;
+ clonechan->redirecting = exchange.redirecting;
/* Restore original timing file descriptor */
ast_channel_set_fd(original, AST_TIMING_FD, original->timingfd);
@@ -4566,8 +4905,10 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
case AST_CONTROL_HOLD:
case AST_CONTROL_UNHOLD:
case AST_CONTROL_VIDUPDATE:
- case AST_CONTROL_SRCUPDATE:
case AST_CONTROL_T38:
+ case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
if (jb_in_use) {
ast_jb_empty_and_reset(c0, c1);
@@ -5530,3 +5871,576 @@ int ast_say_digits_full(struct ast_channel *chan, int num,
return ast_say_digit_str_full(chan, buf, ints, lang, audiofd, ctrlfd);
}
+
+void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_callerid *src)
+{
+#if 1
+ /* Must manually fill in struct ast_party_id until struct ast_callerid goes away */
+ if (dest->id.number) {
+ ast_free(dest->id.number);
+ }
+ dest->id.number = ast_strdup(src->cid_num);
+
+ if (dest->id.name) {
+ ast_free(dest->id.name);
+ }
+ dest->id.name = ast_strdup(src->cid_name);
+
+ dest->id.number_type = src->cid_ton;
+ dest->id.number_presentation = src->cid_pres;
+
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->cid_ani);
+
+ dest->ani2 = src->cid_ani2;
+
+#else
+
+ /* The src parameter type will become a struct ast_party_caller ptr. */
+ /* This is future code */
+
+ ast_party_id_copy(&dest->id, &src->id);
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+
+ dest->ani2 = src->ani2;
+#endif
+}
+
+void ast_connected_line_copy_to_caller(struct ast_callerid *dest, const struct ast_party_connected_line *src)
+{
+#if 1
+ /* Must manually extract from struct ast_party_id until struct ast_callerid goes away */
+ if (dest->cid_num) {
+ ast_free(dest->cid_num);
+ }
+ dest->cid_num = ast_strdup(src->id.number);
+
+ if (dest->cid_name) {
+ ast_free(dest->cid_name);
+ }
+ dest->cid_name = ast_strdup(src->id.name);
+
+ dest->cid_ton = src->id.number_type;
+ dest->cid_pres = src->id.number_presentation;
+
+
+ if (dest->cid_ani) {
+ ast_free(dest->cid_ani);
+ }
+ dest->cid_ani = ast_strdup(src->ani);
+
+ dest->cid_ani2 = src->ani2;
+
+#else
+
+ /* The dest parameter type will become a struct ast_party_caller ptr. */
+ /* This is future code */
+
+ ast_party_id_copy(&dest->id, &src->id);
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+
+ dest->ani2 = src->ani2;
+#endif
+}
+
+void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected)
+{
+ if (&chan->connected == connected) {
+ /* Don't set to self */
+ return;
+ }
+
+ ast_channel_lock(chan);
+ ast_party_connected_line_set(&chan->connected, connected);
+ ast_channel_unlock(chan);
+}
+
+/*!
+ * \brief Element identifiers for connected line indication frame data
+ * \note Only add to the end of this enum.
+ */
+enum {
+ AST_CONNECTED_LINE_NUMBER,
+ AST_CONNECTED_LINE_NAME,
+ AST_CONNECTED_LINE_NUMBER_TYPE,
+ AST_CONNECTED_LINE_NUMBER_PRESENTATION,
+ AST_CONNECTED_LINE_SOURCE
+};
+
+int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected)
+{
+ int32_t value;
+ size_t length;
+ size_t pos = 0;
+
+ /*
+ * The size of integer values must be fixed in case the frame is
+ * shipped to another machine.
+ */
+
+ /* *************** Connected line party id *************** */
+ if (connected->id.number) {
+ length = strlen(connected->id.number);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for connected line number\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_NUMBER;
+ data[pos++] = length;
+ memcpy(data + pos, connected->id.number, length);
+ pos += length;
+ }
+
+ if (connected->id.name) {
+ length = strlen(connected->id.name);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for connected line name\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_NAME;
+ data[pos++] = length;
+ memcpy(data + pos, connected->id.name, length);
+ pos += length;
+ }
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for connected line type of number\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_NUMBER_TYPE;
+ data[pos++] = 1;
+ data[pos++] = connected->id.number_type;
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for connected line presentation\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_NUMBER_PRESENTATION;
+ data[pos++] = 1;
+ data[pos++] = connected->id.number_presentation;
+
+ /* Connected line source */
+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
+ ast_log(LOG_WARNING, "No space left for connected line source\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_SOURCE;
+ data[pos++] = sizeof(value);
+ value = htonl(connected->source);
+ memcpy(data + pos, &value, sizeof(value));
+ pos += sizeof(value);
+
+ return pos;
+}
+
+int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
+{
+ size_t pos;
+ unsigned char ie_len;
+ unsigned char ie_id;
+ int32_t value;
+
+ for (pos = 0; pos < datalen; pos += ie_len) {
+ if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) {
+ ast_log(LOG_WARNING, "Invalid connected line update\n");
+ return -1;
+ }
+ ie_id = data[pos++];
+ ie_len = data[pos++];
+ if (datalen < pos + ie_len) {
+ ast_log(LOG_WARNING, "Invalid connected line update\n");
+ return -1;
+ }
+
+ switch (ie_id) {
+ case AST_CONNECTED_LINE_NUMBER:
+ if (connected->id.number) {
+ ast_free(connected->id.number);
+ }
+ connected->id.number = ast_malloc(ie_len + 1);
+ if (connected->id.number) {
+ memcpy(connected->id.number, data + pos, ie_len);
+ connected->id.number[ie_len] = 0;
+ }
+ break;
+ case AST_CONNECTED_LINE_NAME:
+ if (connected->id.name) {
+ ast_free(connected->id.name);
+ }
+ connected->id.name = ast_malloc(ie_len + 1);
+ if (connected->id.name) {
+ memcpy(connected->id.name, data + pos, ie_len);
+ connected->id.name[ie_len] = 0;
+ }
+ break;
+ case AST_CONNECTED_LINE_NUMBER_TYPE:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid connected line type of number (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ connected->id.number_type = data[pos];
+ break;
+ case AST_CONNECTED_LINE_NUMBER_PRESENTATION:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid connected line presentation (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ connected->id.number_presentation = data[pos];
+ break;
+ case AST_CONNECTED_LINE_SOURCE:
+ if (ie_len != sizeof(value)) {
+ ast_log(LOG_WARNING, "Invalid connected line source (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ memcpy(&value, data + pos, sizeof(value));
+ connected->source = ntohl(value);
+ break;
+ default:
+ ast_log(LOG_DEBUG, "Unknown connected line element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected)
+{
+ unsigned char data[1024]; /* This should be large enough */
+ size_t datalen;
+
+ datalen = ast_connected_line_build_data(data, sizeof(data), connected);
+ if (datalen == (size_t) -1) {
+ return;
+ }
+
+ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen);
+}
+
+void ast_channel_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected)
+{
+ unsigned char data[1024]; /* This should be large enough */
+ size_t datalen;
+
+ datalen = ast_connected_line_build_data(data, sizeof(data), connected);
+ if (datalen == (size_t) -1) {
+ return;
+ }
+
+ ast_queue_control_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen);
+}
+
+void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
+{
+ if (&chan->redirecting == redirecting) {
+ /* Don't set to self */
+ return;
+ }
+
+ ast_channel_lock(chan);
+
+ ast_party_id_set(&chan->redirecting.from, &redirecting->from);
+ if (redirecting->from.number
+ && redirecting->from.number != chan->redirecting.from.number) {
+ /*
+ * Must move string to ast_channel.cid.cid_rdnis until it goes away.
+ */
+ if (chan->cid.cid_rdnis) {
+ ast_free(chan->cid.cid_rdnis);
+ }
+ chan->cid.cid_rdnis = chan->redirecting.from.number;
+ chan->redirecting.from.number = NULL;
+ }
+
+ ast_party_id_set(&chan->redirecting.to, &redirecting->to);
+ chan->redirecting.reason = redirecting->reason;
+ chan->redirecting.count = redirecting->count;
+
+ ast_channel_unlock(chan);
+}
+
+/*!
+ * \brief Element identifiers for redirecting indication frame data
+ * \note Only add to the end of this enum.
+ */
+enum {
+ AST_REDIRECTING_FROM_NUMBER,
+ AST_REDIRECTING_FROM_NAME,
+ AST_REDIRECTING_FROM_NUMBER_TYPE,
+ AST_REDIRECTING_FROM_NUMBER_PRESENTATION,
+ AST_REDIRECTING_TO_NUMBER,
+ AST_REDIRECTING_TO_NAME,
+ AST_REDIRECTING_TO_NUMBER_TYPE,
+ AST_REDIRECTING_TO_NUMBER_PRESENTATION,
+ AST_REDIRECTING_REASON,
+ AST_REDIRECTING_COUNT
+};
+
+int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting)
+{
+ int32_t value;
+ size_t length;
+ size_t pos = 0;
+
+ /*
+ * The size of integer values must be fixed in case the frame is
+ * shipped to another machine.
+ */
+
+ /* *************** Redirecting from party id *************** */
+ if (redirecting->from.number) {
+ length = strlen(redirecting->from.number);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting from number\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_NUMBER;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->from.number, length);
+ pos += length;
+ }
+
+ if (redirecting->from.name) {
+ length = strlen(redirecting->from.name);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting from name\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_NAME;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->from.name, length);
+ pos += length;
+ }
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for redirecting from type of number\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_NUMBER_TYPE;
+ data[pos++] = 1;
+ data[pos++] = redirecting->from.number_type;
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for redirecting from presentation\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_NUMBER_PRESENTATION;
+ data[pos++] = 1;
+ data[pos++] = redirecting->from.number_presentation;
+
+ /* *************** Redirecting to party id *************** */
+ if (redirecting->to.number) {
+ length = strlen(redirecting->to.number);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting to number\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_NUMBER;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->to.number, length);
+ pos += length;
+ }
+
+ if (redirecting->to.name) {
+ length = strlen(redirecting->to.name);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting to name\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_NAME;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->to.name, length);
+ pos += length;
+ }
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for redirecting to type of number\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_NUMBER_TYPE;
+ data[pos++] = 1;
+ data[pos++] = redirecting->to.number_type;
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for redirecting to presentation\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_NUMBER_PRESENTATION;
+ data[pos++] = 1;
+ data[pos++] = redirecting->to.number_presentation;
+
+ /* Redirecting reason */
+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
+ ast_log(LOG_WARNING, "No space left for redirecting reason\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_REASON;
+ data[pos++] = sizeof(value);
+ value = htonl(redirecting->reason);
+ memcpy(data + pos, &value, sizeof(value));
+ pos += sizeof(value);
+
+ /* Redirecting count */
+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
+ ast_log(LOG_WARNING, "No space left for redirecting count\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_COUNT;
+ data[pos++] = sizeof(value);
+ value = htonl(redirecting->count);
+ memcpy(data + pos, &value, sizeof(value));
+ pos += sizeof(value);
+
+ return pos;
+}
+
+int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct ast_party_redirecting *redirecting)
+{
+ size_t pos;
+ unsigned char ie_len;
+ unsigned char ie_id;
+ int32_t value;
+
+ for (pos = 0; pos < datalen; pos += ie_len) {
+ if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) {
+ ast_log(LOG_WARNING, "Invalid redirecting update\n");
+ return -1;
+ }
+ ie_id = data[pos++];
+ ie_len = data[pos++];
+ if (datalen < pos + ie_len) {
+ ast_log(LOG_WARNING, "Invalid redirecting update\n");
+ return -1;
+ }
+
+ switch (ie_id) {
+ case AST_REDIRECTING_FROM_NUMBER:
+ if (redirecting->from.number) {
+ ast_free(redirecting->from.number);
+ }
+ redirecting->from.number = ast_malloc(ie_len + 1);
+ if (redirecting->from.number) {
+ memcpy(redirecting->from.number, data + pos, ie_len);
+ redirecting->from.number[ie_len] = 0;
+ }
+ break;
+ case AST_REDIRECTING_FROM_NAME:
+ if (redirecting->from.name) {
+ ast_free(redirecting->from.name);
+ }
+ redirecting->from.name = ast_malloc(ie_len + 1);
+ if (redirecting->from.name) {
+ memcpy(redirecting->from.name, data + pos, ie_len);
+ redirecting->from.name[ie_len] = 0;
+ }
+ break;
+ case AST_REDIRECTING_FROM_NUMBER_TYPE:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid redirecting from type of number (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ redirecting->from.number_type = data[pos];
+ break;
+ case AST_REDIRECTING_FROM_NUMBER_PRESENTATION:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid redirecting from presentation (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ redirecting->from.number_presentation = data[pos];
+ break;
+ case AST_REDIRECTING_TO_NUMBER:
+ if (redirecting->to.number) {
+ ast_free(redirecting->to.number);
+ }
+ redirecting->to.number = ast_malloc(ie_len + 1);
+ if (redirecting->to.number) {
+ memcpy(redirecting->to.number, data + pos, ie_len);
+ redirecting->to.number[ie_len] = 0;
+ }
+ break;
+ case AST_REDIRECTING_TO_NAME:
+ if (redirecting->to.name) {
+ ast_free(redirecting->to.name);
+ }
+ redirecting->to.name = ast_malloc(ie_len + 1);
+ if (redirecting->to.name) {
+ memcpy(redirecting->to.name, data + pos, ie_len);
+ redirecting->to.name[ie_len] = 0;
+ }
+ break;
+ case AST_REDIRECTING_TO_NUMBER_TYPE:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid redirecting to type of number (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ redirecting->to.number_type = data[pos];
+ break;
+ case AST_REDIRECTING_TO_NUMBER_PRESENTATION:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid redirecting to presentation (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ redirecting->to.number_presentation = data[pos];
+ break;
+ case AST_REDIRECTING_REASON:
+ if (ie_len != sizeof(value)) {
+ ast_log(LOG_WARNING, "Invalid redirecting reason (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ memcpy(&value, data + pos, sizeof(value));
+ redirecting->reason = ntohl(value);
+ break;
+ case AST_REDIRECTING_COUNT:
+ if (ie_len != sizeof(value)) {
+ ast_log(LOG_WARNING, "Invalid redirecting count (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ memcpy(&value, data + pos, sizeof(value));
+ redirecting->count = ntohl(value);
+ break;
+ default:
+ ast_log(LOG_DEBUG, "Unknown redirecting element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
+{
+ unsigned char data[1024]; /* This should be large enough */
+ size_t datalen;
+
+ datalen = ast_redirecting_build_data(data, sizeof(data), redirecting);
+ if (datalen == (size_t) -1) {
+ return;
+ }
+
+ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
+}
+
+void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
+{
+ unsigned char data[1024]; /* This should be large enough */
+ size_t datalen;
+
+ datalen = ast_redirecting_build_data(data, sizeof(data), redirecting);
+ if (datalen == (size_t) -1) {
+ return;
+ }
+
+ ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
+}
+
diff --git a/main/dial.c b/main/dial.c
index e8c9ca221..d38b4829d 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -274,10 +274,12 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann
ast_channel_datastore_inherit(chan, channel->owner);
/* Copy over callerid information */
- S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num));
- S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name));
- S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+ ast_party_redirecting_copy(&channel->owner->redirecting, &chan->redirecting);
+
+ channel->owner->cid.cid_tns = chan->cid.cid_tns;
+
+ ast_connected_line_copy_from_caller(&channel->owner->connected, &chan->cid);
ast_string_field_set(channel->owner, language, chan->language);
ast_string_field_set(channel->owner, accountcode, chan->accountcode);
@@ -285,9 +287,6 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann
if (ast_strlen_zero(channel->owner->musicclass))
ast_string_field_set(channel->owner, musicclass, chan->musicclass);
- channel->owner->cid.cid_pres = chan->cid.cid_pres;
- channel->owner->cid.cid_ton = chan->cid.cid_ton;
- channel->owner->cid.cid_tns = chan->cid.cid_tns;
channel->owner->adsicpe = chan->adsicpe;
channel->owner->transfercapability = chan->transfercapability;
}
@@ -429,6 +428,14 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel
ast_verbose (VERBOSE_PREFIX_3 "%s requested a source update, passing it to %s\n", channel->owner->name, chan->name);
ast_indicate(chan, AST_CONTROL_SRCUPDATE);
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ ast_verb(3, "%s connected line has changed, passing it to %s\n", channel->owner->name, chan->name);
+ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, fr->data.ptr, fr->datalen);
+ break;
+ case AST_CONTROL_REDIRECTING:
+ ast_verb(3, "%s redirecting info has changed, passing it to %s\n", channel->owner->name, chan->name);
+ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen);
+ break;
case AST_CONTROL_PROCEEDING:
ast_verb(3, "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name);
ast_indicate(chan, AST_CONTROL_PROCEEDING);
diff --git a/main/features.c b/main/features.c
index 0b6d7f53c..8efe0dbf7 100644
--- a/main/features.c
+++ b/main/features.c
@@ -1387,6 +1387,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
struct ast_bridge_config bconfig;
struct ast_frame *f;
int l;
+ struct ast_party_connected_line connected_line = {{0,},};
struct ast_datastore *features_datastore;
struct ast_dial_features *dialfeatures = NULL;
@@ -1478,6 +1479,17 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
memset(&bconfig,0,sizeof(struct ast_bridge_config));
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
+ /* We need to get the transferer's connected line information copied
+ * at this point because he is likely to hang up during the bridge with
+ * newchan. This info will be used down below before bridging the
+ * transferee and newchan
+ *
+ * As a result, we need to be sure to free this data before returning
+ * or overwriting it.
+ */
+ ast_channel_lock(transferer);
+ ast_party_connected_line_copy(&connected_line, &transferer->connected);
+ ast_channel_unlock(transferer);
res = ast_bridge_call(transferer, newchan, &bconfig);
if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
ast_hangup(newchan);
@@ -1485,10 +1497,12 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
finishup(transferee);
transferer->_softhangup = 0;
+ ast_party_connected_line_free(&connected_line);
return AST_FEATURE_RETURN_SUCCESS;
}
if (check_compat(transferee, newchan)) {
finishup(transferee);
+ ast_party_connected_line_free(&connected_line);
return -1;
}
ast_indicate(transferee, AST_CONTROL_UNHOLD);
@@ -1499,11 +1513,13 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
|| ast_check_hangup(transferee)
|| ast_check_hangup(newchan)) {
ast_hangup(newchan);
+ ast_party_connected_line_free(&connected_line);
return -1;
}
xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
if (!xferchan) {
ast_hangup(newchan);
+ ast_party_connected_line_free(&connected_line);
return -1;
}
/* Make formats okay */
@@ -1523,6 +1539,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
ast_hangup(xferchan);
ast_hangup(newchan);
+ ast_party_connected_line_free(&connected_line);
return -1;
}
@@ -1557,6 +1574,18 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
}
+ /* Due to a limitation regarding when callerID is set on a Local channel,
+ * we use the transferer's connected line information here.
+ */
+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(xferchan, &connected_line);
+ ast_channel_lock(xferchan);
+ ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid);
+ ast_channel_unlock(xferchan);
+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(newchan, &connected_line);
+ ast_party_connected_line_free(&connected_line);
+
if (ast_stream_and_wait(newchan, xfersound, ""))
ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
bridge_call_thread_launch(tobj);
@@ -1653,11 +1682,24 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
tobj->chan = newchan;
tobj->peer = xferchan;
tobj->bconfig = *config;
-
+
if (tobj->bconfig.end_bridge_callback_data_fixup) {
tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
}
+ ast_channel_lock(newchan);
+ ast_connected_line_copy_from_caller(&connected_line, &newchan->cid);
+ ast_channel_unlock(newchan);
+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(xferchan, &connected_line);
+ ast_channel_lock(xferchan);
+ ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid);
+ ast_channel_unlock(xferchan);
+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(newchan, &connected_line);
+
+ ast_party_connected_line_free(&connected_line);
+
if (ast_stream_and_wait(newchan, xfersound, ""))
ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
bridge_call_thread_launch(tobj);
@@ -2197,6 +2239,10 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
ast_channel_inherit_variables(caller, chan);
pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
+ ast_channel_lock(chan);
+ ast_connected_line_copy_from_caller(&chan->connected, &caller->cid);
+ ast_channel_unlock(chan);
+
if (ast_call(chan, data, timeout)) {
ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
goto done;
@@ -2266,6 +2312,8 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
f = NULL;
ready=1;
break;
+ } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) {
+ ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
} else if (f->subclass != -1) {
ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
}
@@ -4444,8 +4492,19 @@ int ast_pickup_call(struct ast_channel *chan)
struct ast_channel *cur = ast_channel_search_locked(find_channel_by_group, chan);
if (cur) {
+ struct ast_party_connected_line connected_caller;
+
int res = -1;
ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
+
+ connected_caller = cur->connected;
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(chan, &connected_caller);
+
+ ast_party_connected_line_collect_caller(&connected_caller, &chan->cid);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(chan, &connected_caller);
+
res = ast_answer(chan);
if (res)
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
diff --git a/main/stun.c b/main/stun.c
index 264430718..74652f90b 100644
--- a/main/stun.c
+++ b/main/stun.c
@@ -28,7 +28,7 @@
#include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 124370 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/_private.h"
#include "asterisk/stun.h"
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index e16088d6e..789c3d01b 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -28,7 +28,7 @@
#include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 138083 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/time.h>
#include <signal.h>