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: https://origsvn.digium.com/svn/asterisk/trunk@186525 65c4cc65-6c06-0410-ace0-fbb531ad65f3
certified/1.8.6
Mark Michelson 16 years ago
parent 3525e37e63
commit 6f53ed4c67

@ -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

@ -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

@ -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;

@ -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

@ -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);

@ -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;

@ -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"))

@ -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;

@ -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;
}

@ -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)) {

File diff suppressed because it is too large Load Diff

@ -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;

File diff suppressed because it is too large Load Diff

@ -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 */

@ -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);

@ -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) */

@ -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);

@ -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]; */

@ -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);

@ -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))

@ -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"

@ -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

@ -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

@ -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 */

File diff suppressed because it is too large Load Diff

@ -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 {

@ -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";
}

File diff suppressed because it is too large Load Diff

@ -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);

@ -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);

@ -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"

@ -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>

Loading…
Cancel
Save