This commit introduces COLP/CONP and Redirecting party information into Asterisk.
authorMark Michelson <mmichelson@digium.com>
Fri, 3 Apr 2009 22:41:46 +0000 (22:41 +0000)
committerMark Michelson <mmichelson@digium.com>
Fri, 3 Apr 2009 22:41:46 +0000 (22:41 +0000)
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

32 files changed:
CHANGES
apps/app_dial.c
apps/app_directed_pickup.c
apps/app_queue.c
channels/chan_agent.c
channels/chan_dahdi.c
channels/chan_h323.c
channels/chan_iax2.c
channels/chan_local.c
channels/chan_mgcp.c
channels/chan_misdn.c
channels/chan_phone.c
channels/chan_sip.c
channels/chan_skinny.c
channels/chan_unistim.c
channels/misdn/chan_misdn_config.h
channels/misdn/isdn_lib.c
channels/misdn/isdn_lib.h
channels/misdn/isdn_lib_intern.h
channels/misdn/isdn_msg_parser.c
channels/misdn_config.c
configs/misdn.conf.sample
configs/sip.conf.sample
include/asterisk/callerid.h
include/asterisk/channel.h
include/asterisk/frame.h
main/callerid.c
main/channel.c
main/dial.c
main/features.c
main/stun.c
res/res_rtp_asterisk.c

diff --git a/CHANGES b/CHANGES
index 88ae3f5..a920502 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -7,7 +7,6 @@
 === and the other UPGRADE files for older releases.
 ===
 ======================================================================
-
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.6.2 to Asterisk 1.6.3  -------------
 ------------------------------------------------------------------------------
@@ -23,10 +22,47 @@ Applications
    present, those values are sent immediatly upon receiving a PROGRESS message
    regardless if the call has been answered or not.
 
-Functions
----------
+Dialplan Functions
+------------------
+ * Added new dialplan functions CONNECTEDLINE and REDIRECTING which permits
+   setting various connected line and redirecting party information.
  * The CHANNEL() function now supports the "name" option.
 
+Queue changes
+-------------
+  * A new option, 'I' has been added to both app_queue and app_dial.
+    By setting this option, Asterisk will not update the caller with
+    connected line changes or redirecting party changes when they occur.
+
+mISDN channel driver (chan_misdn) changes
+----------------------------------------
+  * Added display_connected parameter to misdn.conf to put a display string
+    in the CONNECT message containing the connected name and/or number if
+    the presentation setting permits it.
+  * Added display_setup parameter to misdn.conf to put a display string
+    in the SETUP message containing the caller name and/or number if the
+    presentation setting permits it.
+  * Made misdn.conf parameters localdialplan and cpndialplan take a -1 to
+    indicate the dialplan settings are to be obtained from the asterisk
+    channel.
+  * Made misdn.conf parameter callerid accept the "name" <number> format
+    used by the rest of the system.
+  * Made use the nationalprefix and internationalprefix misdn.conf
+    parameters to prefix any received number from the ISDN link if that
+    number has the corresponding Type-Of-Number.
+  * Added the following new parameters: unknownprefix, netspecificprefix,
+    subscriberprefix, and abbreviatedprefix in misdn.conf to prefix any
+    received number from the ISDN link if that number has the corresponding
+    Type-Of-Number.
+
+
+SIP channel driver (chan_sip) changes
+-------------------------------------------
+  * The sendrpid parameter has been expanded to include the options
+    'rpid' and 'pai'. Setting sendrpid to 'rpid' will cause Remote-Party-ID
+    header to be sent (equivalent to setting sendrpid=yes) and setting
+    sendrpid to 'pai' will cause P-Asserted-Identity header to be sent.
+
 Asterisk Manager Interface
 --------------------------
  * The Hangup action now accepts a Cause header which may be used to
index 96bb570..ee3953f 100644 (file)
@@ -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
index 605d11f..cfba99f 100644 (file)
@@ -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;
index 5726d4c..58b1c09 100644 (file)
@@ -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
index b15f7a0..818f619 100644 (file)
@@ -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);
index f520e32..f6d3fb9 100644 (file)
@@ -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;
index c3e074d..0445497 100644 (file)
@@ -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"))
index 860e1d6..d594498 100644 (file)
@@ -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;
index e426e10..509e69b 100644 (file)
@@ -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;
 }
 
index cad9d94..83a2e61 100644 (file)
@@ -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)) {
index 599bcef..52b8f1d 100644 (file)
@@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <signal.h>
 #include <sys/file.h>
 #include <semaphore.h>
+#include <ctype.h>
 
 #include "asterisk/channel.h"
 #include "asterisk/config.h"
@@ -88,8 +89,6 @@ struct misdn_jb{
        ast_mutex_t mutexjb;
 };
 
-
-
 /*! \brief allocates the jb-structure and initialize the elements */
 struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
 
@@ -340,10 +339,6 @@ struct chan_list {
         */
        char mohinterpret[MAX_MUSICCLASS];
 
-#if 0
-       int zero_read_cnt;      /* Not used */
-#endif
-
        /*!
         * \brief Number of outgoing audio frames dropped since last debug gripe message.
         */
@@ -401,18 +396,10 @@ struct chan_list {
         */
        struct timeval overlap_tv;
 
-#if 0
-       struct chan_list *peer;     /* Not used */
-#endif
-
        /*!
         * \brief Next channel call record in the list.
         */
        struct chan_list *next;
-#if 0
-       struct chan_list *prev;     /* Not used */
-       struct chan_list *first;    /* Not used */
-#endif
 };
 
 
@@ -423,13 +410,14 @@ void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_
 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
 
-static struct robin_list {
+struct robin_list {
        char *group;
        int port;
        int channel;
        struct robin_list *next;
        struct robin_list *prev;
-} *robin = NULL;
+};
+static struct robin_list *robin = NULL;
 
 
 static inline void free_robin_list_r(struct robin_list *r)
@@ -538,7 +526,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data);
 
 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
 
-void debug_numplan(int port, int numplan, char *type);
+void debug_numtype(int port, int numtype, char *type);
 
 int add_out_calls(int port);
 int add_in_calls(int port);
@@ -567,17 +555,545 @@ static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
        return NULL;
 }
 
-static struct chan_list * get_chan_by_ast_name(char *name)
-{
-       struct chan_list *tmp;
+static struct chan_list * get_chan_by_ast_name(char *name)
+{
+       struct chan_list *tmp;
+
+       for (tmp = cl_te; tmp; tmp = tmp->next) {
+               if (tmp->ast && strcmp(tmp->ast->name, name) == 0) {
+                       return tmp;
+               }
+       }
+
+       return NULL;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN type of number code to a string
+ *
+ * \param number_type mISDN type of number code.
+ *
+ * \return The mISDN type of number code as a string
+ */
+static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type)
+{
+       const char *str;
+
+       switch (number_type) {
+       default:
+       case NUMTYPE_UNKNOWN:
+               str = "Unknown";
+               break;
+
+       case NUMTYPE_INTERNATIONAL:
+               str = "International";
+               break;
+
+       case NUMTYPE_NATIONAL:
+               str = "National";
+               break;
+
+       case NUMTYPE_NETWORK_SPECIFIC:
+               str = "Network Specific";
+               break;
+
+       case NUMTYPE_SUBSCRIBER:
+               str = "Subscriber";
+               break;
+
+       case NUMTYPE_ABBREVIATED:
+               str = "Abbreviated";
+               break;
+       }
+
+       return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN type of number code to Asterisk type of number code
+ *
+ * \param number_type mISDN type of number code.
+ *
+ * \return Asterisk type of number code
+ */
+static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type)
+{
+       int ast_number_type;
+
+       switch (number_type) {
+       default:
+       case NUMTYPE_UNKNOWN:
+               ast_number_type = NUMTYPE_UNKNOWN << 4;
+               break;
+
+       case NUMTYPE_INTERNATIONAL:
+               ast_number_type = NUMTYPE_INTERNATIONAL << 4;
+               break;
+
+       case NUMTYPE_NATIONAL:
+               ast_number_type = NUMTYPE_NATIONAL << 4;
+               break;
+
+       case NUMTYPE_NETWORK_SPECIFIC:
+               ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4;
+               break;
+
+       case NUMTYPE_SUBSCRIBER:
+               ast_number_type = NUMTYPE_SUBSCRIBER << 4;
+               break;
+
+       case NUMTYPE_ABBREVIATED:
+               ast_number_type = NUMTYPE_ABBREVIATED << 4;
+               break;
+       }
+
+       return ast_number_type;
+}
+
+/*!
+ * \internal
+ * \brief Convert the Asterisk type of number code to mISDN type of number code
+ *
+ * \param ast_number_type Asterisk type of number code.
+ *
+ * \return mISDN type of number code
+ */
+static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type)
+{
+       enum mISDN_NUMBER_TYPE number_type;
+
+       switch ((ast_number_type >> 4) & 0x07) {
+       default:
+       case NUMTYPE_UNKNOWN:
+               number_type = NUMTYPE_UNKNOWN;
+               break;
+
+       case NUMTYPE_INTERNATIONAL:
+               number_type = NUMTYPE_INTERNATIONAL;
+               break;
+
+       case NUMTYPE_NATIONAL:
+               number_type = NUMTYPE_NATIONAL;
+               break;
+
+       case NUMTYPE_NETWORK_SPECIFIC:
+               number_type = NUMTYPE_NETWORK_SPECIFIC;
+               break;
+
+       case NUMTYPE_SUBSCRIBER:
+               number_type = NUMTYPE_SUBSCRIBER;
+               break;
+
+       case NUMTYPE_ABBREVIATED:
+               number_type = NUMTYPE_ABBREVIATED;
+               break;
+       }
+
+       return number_type;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN numbering plan code to a string
+ *
+ * \param number_plan mISDN numbering plan code.
+ *
+ * \return The mISDN numbering plan code as a string
+ */
+static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan)
+{
+       const char *str;
+
+       switch (number_plan) {
+       default:
+       case NUMPLAN_UNKNOWN:
+               str = "Unknown";
+               break;
+
+       case NUMPLAN_ISDN:
+               str = "ISDN";
+               break;
+
+       case NUMPLAN_DATA:
+               str = "Data";
+               break;
+
+       case NUMPLAN_TELEX:
+               str = "Telex";
+               break;
+
+       case NUMPLAN_NATIONAL:
+               str = "National";
+               break;
+
+       case NUMPLAN_PRIVATE:
+               str = "Private";
+               break;
+       }
+
+       return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN numbering plan code to Asterisk numbering plan code
+ *
+ * \param number_plan mISDN numbering plan code.
+ *
+ * \return Asterisk numbering plan code
+ */
+static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan)
+{
+       int ast_number_plan;
+
+       switch (number_plan) {
+       default:
+       case NUMPLAN_UNKNOWN:
+               ast_number_plan = NUMPLAN_UNKNOWN;
+               break;
+
+       case NUMPLAN_ISDN:
+               ast_number_plan = NUMPLAN_ISDN;
+               break;
+
+       case NUMPLAN_DATA:
+               ast_number_plan = NUMPLAN_DATA;
+               break;
+
+       case NUMPLAN_TELEX:
+               ast_number_plan = NUMPLAN_TELEX;
+               break;
+
+       case NUMPLAN_NATIONAL:
+               ast_number_plan = NUMPLAN_NATIONAL;
+               break;
+
+       case NUMPLAN_PRIVATE:
+               ast_number_plan = NUMPLAN_PRIVATE;
+               break;
+       }
+
+       return ast_number_plan;
+}
+
+/*!
+ * \internal
+ * \brief Convert the Asterisk numbering plan code to mISDN numbering plan code
+ *
+ * \param ast_number_plan Asterisk numbering plan code.
+ *
+ * \return mISDN numbering plan code
+ */
+static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan)
+{
+       enum mISDN_NUMBER_PLAN number_plan;
+
+       switch (ast_number_plan & 0x0F) {
+       default:
+       case NUMPLAN_UNKNOWN:
+               number_plan = NUMPLAN_UNKNOWN;
+               break;
+
+       case NUMPLAN_ISDN:
+               number_plan = NUMPLAN_ISDN;
+               break;
+
+       case NUMPLAN_DATA:
+               number_plan = NUMPLAN_DATA;
+               break;
+
+       case NUMPLAN_TELEX:
+               number_plan = NUMPLAN_TELEX;
+               break;
+
+       case NUMPLAN_NATIONAL:
+               number_plan = NUMPLAN_NATIONAL;
+               break;
+
+       case NUMPLAN_PRIVATE:
+               number_plan = NUMPLAN_PRIVATE;
+               break;
+       }
+
+       return number_plan;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN presentation code to a string
+ *
+ * \param presentation mISDN number presentation restriction code.
+ *
+ * \return The mISDN presentation code as a string
+ */
+static const char *misdn_to_str_pres(int presentation)
+{
+       const char *str;
+
+       switch (presentation) {
+       case 0:
+               str = "Allowed";
+               break;
+
+       case 1:
+               str = "Restricted";
+               break;
+
+       case 2:
+               str = "Unavailable";
+               break;
+
+       default:
+               str = "Unknown";
+               break;
+       }
+
+       return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN presentation code to Asterisk presentation code
+ *
+ * \param presentation mISDN number presentation restriction code.
+ *
+ * \return Asterisk presentation code
+ */
+static int misdn_to_ast_pres(int presentation)
+{
+       switch (presentation) {
+       default:
+       case 0:
+               presentation = AST_PRES_ALLOWED;
+               break;
+
+       case 1:
+               presentation = AST_PRES_RESTRICTED;
+               break;
+
+       case 2:
+               presentation = AST_PRES_UNAVAILABLE;
+               break;
+       }
+
+       return presentation;
+}
+
+/*!
+ * \internal
+ * \brief Convert the Asterisk presentation code to mISDN presentation code
+ *
+ * \param presentation Asterisk number presentation restriction code.
+ *
+ * \return mISDN presentation code
+ */
+static int ast_to_misdn_pres(int presentation)
+{
+       switch (presentation & AST_PRES_RESTRICTION) {
+       default:
+       case AST_PRES_ALLOWED:
+               presentation = 0;
+               break;
+
+       case AST_PRES_RESTRICTED:
+               presentation = 1;
+               break;
+
+       case AST_PRES_UNAVAILABLE:
+               presentation = 2;
+               break;
+       }
+
+       return presentation;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN screening code to a string
+ *
+ * \param screening mISDN number screening code.
+ *
+ * \return The mISDN screening code as a string
+ */
+static const char *misdn_to_str_screen(int screening)
+{
+       const char *str;
+
+       switch (screening) {
+       case 0:
+               str = "Unscreened";
+               break;
+
+       case 1:
+               str = "Passed Screen";
+               break;
+
+       case 2:
+               str = "Failed Screen";
+               break;
+
+       case 3:
+               str = "Network Number";
+               break;
+
+       default:
+               str = "Unknown";
+               break;
+       }
+
+       return str;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN screening code to Asterisk screening code
+ *
+ * \param screening mISDN number screening code.
+ *
+ * \return Asterisk screening code
+ */
+static int misdn_to_ast_screen(int screening)
+{
+       switch (screening) {
+       default:
+       case 0:
+               screening = AST_PRES_USER_NUMBER_UNSCREENED;
+               break;
+
+       case 1:
+               screening = AST_PRES_USER_NUMBER_PASSED_SCREEN;
+               break;
+
+       case 2:
+               screening = AST_PRES_USER_NUMBER_FAILED_SCREEN;
+               break;
+
+       case 3:
+               screening = AST_PRES_NETWORK_NUMBER;
+               break;
+       }
+
+       return screening;
+}
+
+/*!
+ * \internal
+ * \brief Convert the Asterisk screening code to mISDN screening code
+ *
+ * \param screening Asterisk number screening code.
+ *
+ * \return mISDN screening code
+ */
+static int ast_to_misdn_screen(int screening)
+{
+       switch (screening & AST_PRES_NUMBER_TYPE) {
+       default:
+       case AST_PRES_USER_NUMBER_UNSCREENED:
+               screening = 0;
+               break;
+
+       case AST_PRES_USER_NUMBER_PASSED_SCREEN:
+               screening = 1;
+               break;
+
+       case AST_PRES_USER_NUMBER_FAILED_SCREEN:
+               screening = 2;
+               break;
+
+       case AST_PRES_NETWORK_NUMBER:
+               screening = 3;
+               break;
+       }
+
+       return screening;
+}
+
+/*!
+ * \internal
+ * \brief Convert Asterisk redirecting reason to mISDN redirecting reason code.
+ *
+ * \param ast Asterisk redirecting reason code.
+ *
+ * \return mISDN reason code
+ */
+static enum mISDN_REDIRECTING_REASON ast_to_misdn_reason(const enum AST_REDIRECTING_REASON ast)
+{
+       unsigned index;
+
+       static const struct misdn_reasons {
+               enum AST_REDIRECTING_REASON ast;
+               enum mISDN_REDIRECTING_REASON q931;
+       } misdn_reason_table[] = {
+       /* *INDENT-OFF* */
+               { AST_REDIRECTING_REASON_UNKNOWN,        mISDN_REDIRECTING_REASON_UNKNOWN },
+               { AST_REDIRECTING_REASON_USER_BUSY,      mISDN_REDIRECTING_REASON_CALL_FWD_BUSY },
+               { AST_REDIRECTING_REASON_NO_ANSWER,      mISDN_REDIRECTING_REASON_NO_REPLY },
+               { AST_REDIRECTING_REASON_UNAVAILABLE,    mISDN_REDIRECTING_REASON_NO_REPLY },
+               { AST_REDIRECTING_REASON_UNCONDITIONAL,  mISDN_REDIRECTING_REASON_CALL_FWD },
+               { AST_REDIRECTING_REASON_TIME_OF_DAY,    mISDN_REDIRECTING_REASON_UNKNOWN },
+               { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN },
+               { AST_REDIRECTING_REASON_DEFLECTION,     mISDN_REDIRECTING_REASON_DEFLECTION },
+               { AST_REDIRECTING_REASON_FOLLOW_ME,      mISDN_REDIRECTING_REASON_UNKNOWN },
+               { AST_REDIRECTING_REASON_OUT_OF_ORDER,   mISDN_REDIRECTING_REASON_OUT_OF_ORDER },
+               { AST_REDIRECTING_REASON_AWAY,           mISDN_REDIRECTING_REASON_UNKNOWN },
+               { AST_REDIRECTING_REASON_CALL_FWD_DTE,   mISDN_REDIRECTING_REASON_CALL_FWD_DTE }
+       /* *INDENT-ON* */
+       };
+
+       for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) {
+               if (misdn_reason_table[index].ast == ast) {
+                       return misdn_reason_table[index].q931;
+               }
+       }
+       return mISDN_REDIRECTING_REASON_UNKNOWN;
+}
+
+/*!
+ * \internal
+ * \brief Convert the mISDN redirecting reason to Asterisk redirecting reason code
+ *
+ * \param q931 mISDN redirecting reason code.
+ *
+ * \return Asterisk redirecting reason code
+ */
+static enum AST_REDIRECTING_REASON misdn_to_ast_reason(const enum mISDN_REDIRECTING_REASON q931)
+{
+       enum AST_REDIRECTING_REASON ast;
+
+       switch (q931) {
+       default:
+       case mISDN_REDIRECTING_REASON_UNKNOWN:
+               ast = AST_REDIRECTING_REASON_UNKNOWN;
+               break;
+
+       case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
+               ast = AST_REDIRECTING_REASON_USER_BUSY;
+               break;
+
+       case mISDN_REDIRECTING_REASON_NO_REPLY:
+               ast = AST_REDIRECTING_REASON_NO_ANSWER;
+               break;
+
+       case mISDN_REDIRECTING_REASON_DEFLECTION:
+               ast = AST_REDIRECTING_REASON_DEFLECTION;
+               break;
+
+       case mISDN_REDIRECTING_REASON_OUT_OF_ORDER:
+               ast = AST_REDIRECTING_REASON_OUT_OF_ORDER;
+               break;
 
-       for (tmp = cl_te; tmp; tmp = tmp->next) {
-               if (tmp->ast && strcmp(tmp->ast->name, name) == 0) {
-                       return tmp;
-               }
+       case mISDN_REDIRECTING_REASON_CALL_FWD_DTE:
+               ast = AST_REDIRECTING_REASON_CALL_FWD_DTE;
+               break;
+
+       case mISDN_REDIRECTING_REASON_CALL_FWD:
+               ast = AST_REDIRECTING_REASON_UNCONDITIONAL;
+               break;
        }
 
-       return NULL;
+       return ast;
 }
 
 
@@ -590,7 +1106,7 @@ struct allowed_bearers {
 };
 
 /* *INDENT-OFF* */
-static const struct allowed_bearers allowed_bearers_array[]= {
+static const struct allowed_bearers allowed_bearers_array[] = {
        /* Name,                      Displayable Name       Bearer Capability,                    Deprecated */
        { "speech",                  "Speech",               INFO_CAPABILITY_SPEECH,               0 },
        { "3_1khz",                  "3.1KHz Audio",         INFO_CAPABILITY_AUDIO_3_1K,           0 },
@@ -609,7 +1125,7 @@ static const char *bearer2str(int cap)
                if (allowed_bearers_array[index].cap == cap) {
                        return allowed_bearers_array[index].display;
                }
-       }       /* end for */
+       }
 
        return "Unknown Bearer";
 }
@@ -682,6 +1198,95 @@ static void print_bearer(struct misdn_bchannel *bc)
        }
 }
 
+/*!
+ * \internal
+ * \brief Prefix a string to another string in place.
+ *
+ * \param str_prefix String to prefix to the main string.
+ * \param str_main String to get the prefix added to it.
+ * \param size Buffer size of the main string (Includes null terminator).
+ *
+ * \note The str_main buffer size must be greater than one.
+ *
+ * \return Nothing
+ */
+static void misdn_prefix_string(const char *str_prefix, char *str_main, size_t size)
+{
+       size_t len_over;
+       size_t len_total;
+       size_t len_main;
+       size_t len_prefix;
+
+       len_prefix = strlen(str_prefix);
+       if (!len_prefix) {
+               /* There is no prefix to prepend. */
+               return;
+       }
+       len_main = strlen(str_main);
+       len_total = len_prefix + len_main;
+       if (size <= len_total) {
+               /* We need to truncate since the buffer is too small. */
+               len_over = len_total + 1 - size;
+               if (len_over <= len_main) {
+                       len_main -= len_over;
+               } else {
+                       len_over -= len_main;
+                       len_main = 0;
+                       len_prefix -= len_over;
+               }
+       }
+       if (len_main) {
+               memmove(str_main + len_prefix, str_main, len_main);
+       }
+       memcpy(str_main, str_prefix, len_prefix);
+       str_main[len_prefix + len_main] = '\0';
+}
+
+/*!
+ * \internal
+ * \brief Add a configured prefix to the given number.
+ *
+ * \param port Logical port number
+ * \param number_type Type-of-number passed in.
+ * \param number Given number string to add prefix
+ * \param size Buffer size number string occupies.
+ *
+ * \return Nothing
+ */
+static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type, char *number, size_t size)
+{
+       enum misdn_cfg_elements type_prefix;
+       char num_prefix[MISDN_MAX_NUMBER_LEN];
+
+       /* Get prefix string. */
+       switch (number_type) {
+       case NUMTYPE_UNKNOWN:
+               type_prefix = MISDN_CFG_TON_PREFIX_UNKNOWN;
+               break;
+       case NUMTYPE_INTERNATIONAL:
+               type_prefix = MISDN_CFG_TON_PREFIX_INTERNATIONAL;
+               break;
+       case NUMTYPE_NATIONAL:
+               type_prefix = MISDN_CFG_TON_PREFIX_NATIONAL;
+               break;
+       case NUMTYPE_NETWORK_SPECIFIC:
+               type_prefix = MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC;
+               break;
+       case NUMTYPE_SUBSCRIBER:
+               type_prefix = MISDN_CFG_TON_PREFIX_SUBSCRIBER;
+               break;
+       case NUMTYPE_ABBREVIATED:
+               type_prefix = MISDN_CFG_TON_PREFIX_ABBREVIATED;
+               break;
+       default:
+               /* Type-of-number does not have a prefix that can be added. */
+               return;
+       }
+       misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix));
+
+       misdn_prefix_string(num_prefix, number, size);
+}
+
 static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
 {
        char buf[128];
@@ -691,7 +1296,8 @@ static void export_aoc_vars(int originator, struct ast_channel *ast, struct misd
        }
 
        if (originator == ORG_AST) {
-               if (!(ast = ast_bridged_channel(ast))) {
+               ast = ast_bridged_channel(ast);
+               if (!ast) {
                        return;
                }
        }
@@ -745,7 +1351,8 @@ static void export_aoc_vars(int originator, struct ast_channel *ast, struct misd
 /*************** Helpers END *************/
 
 static void sighandler(int sig)
-{}
+{
+}
 
 static void *misdn_tasks_thread_func(void *data)
 {
@@ -840,6 +1447,7 @@ static void misdn_tasks_remove(int task_id)
 static int misdn_l1_task(const void *vdata)
 {
        const int *data = vdata;
+
        misdn_lib_isdn_l1watcher(*data);
        chan_misdn_log(5, *data, "L1watcher timeout\n");
        return 1;
@@ -866,21 +1474,22 @@ static int misdn_overlap_dial_task(const void *data)
        tv_end.tv_sec += ch->overlap_dial;
        tv_now = ast_tvnow();
 
-       if ((diff = ast_tvdiff_ms(tv_end, tv_now)) > 100) {
+       diff = ast_tvdiff_ms(tv_end, tv_now);
+       if (100 < diff) {
                return diff;
        }
 
        /* if we are 100ms near the timeout, we are satisfied.. */
        stop_indicate(ch);
 
-       if (ast_strlen_zero(ch->bc->dad)) {
+       if (ast_strlen_zero(ch->bc->dialed.number)) {
                dad = "s";
-               ast_copy_string(ch->ast->exten, "s", sizeof(ch->ast->exten));
+               strcpy(ch->ast->exten, dad);
        } else {
-               dad = ch->bc->dad;
+               dad = ch->bc->dialed.number;
        }
 
-       if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) {
+       if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->caller.number)) {
                ch->state = MISDN_DIALING;
                if (pbx_start_chan(ch) < 0) {
                        chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
@@ -957,8 +1566,10 @@ static char *handle_cli_misdn_set_debug(struct ast_cli_entry *e, int cmd, struct
                level = 1;
        } else if (!strcasecmp(a->argv[3], "off")) {
                level = 0;
-       } else {
+       } else if (isdigit(a->argv[3][0])) {
                level = atoi(a->argv[3]);
+       } else {
+               return CLI_SHOWUSAGE;
        }
 
        switch (a->argc) {
@@ -1293,27 +1904,29 @@ struct state_struct {
 };
 
 static struct state_struct state_array[] = {
+/* *INDENT-OFF* */
        { MISDN_NOTHING,             "NOTHING" },             /* at beginning */
-       { MISDN_WAITING4DIGS,        "WAITING4DIGS" },        /*  when waiting for infos */
-       { MISDN_EXTCANTMATCH,        "EXTCANTMATCH" },        /*  when asterisk couldn't match our ext */
-       { MISDN_INCOMING_SETUP,      "INCOMING SETUP" },      /*  when pbx_start */
-       { MISDN_DIALING,             "DIALING" },             /*  when pbx_start */
-       { MISDN_PROGRESS,            "PROGRESS" },            /*  when pbx_start */
-       { MISDN_PROCEEDING,          "PROCEEDING" },          /*  when pbx_start */
-       { MISDN_CALLING,             "CALLING" },             /*  when misdn_call is called */
-       { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /*  when misdn_call is called */
-       { MISDN_ALERTING,            "ALERTING" },            /*  when Alerting */
-       { MISDN_BUSY,                "BUSY" },                /*  when BUSY */
-       { MISDN_CONNECTED,           "CONNECTED" },           /*  when connected */
-       { MISDN_PRECONNECTED,        "PRECONNECTED" },        /*  when connected */
-       { MISDN_DISCONNECTED,        "DISCONNECTED" },        /*  when connected */
-       { MISDN_RELEASED,            "RELEASED" },            /*  when connected */
-       { MISDN_BRIDGED,             "BRIDGED" },             /*  when bridged */
+       { MISDN_WAITING4DIGS,        "WAITING4DIGS" },        /* when waiting for infos */
+       { MISDN_EXTCANTMATCH,        "EXTCANTMATCH" },        /* when asterisk couldn't match our ext */
+       { MISDN_INCOMING_SETUP,      "INCOMING SETUP" },      /* when pbx_start */
+       { MISDN_DIALING,             "DIALING" },             /* when pbx_start */
+       { MISDN_PROGRESS,            "PROGRESS" },            /* when pbx_start */
+       { MISDN_PROCEEDING,          "PROCEEDING" },          /* when pbx_start */
+       { MISDN_CALLING,             "CALLING" },             /* when misdn_call is called */
+       { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /* when misdn_call is called */
+       { MISDN_ALERTING,            "ALERTING" },            /* when Alerting */
+       { MISDN_BUSY,                "BUSY" },                /* when BUSY */
+       { MISDN_CONNECTED,           "CONNECTED" },           /* when connected */
+       { MISDN_PRECONNECTED,        "PRECONNECTED" },        /* when connected */
+       { MISDN_DISCONNECTED,        "DISCONNECTED" },        /* when connected */
+       { MISDN_RELEASED,            "RELEASED" },            /* when connected */
+       { MISDN_BRIDGED,             "BRIDGED" },             /* when bridged */
        { MISDN_CLEANING,            "CLEANING" },            /* when hangup from * but we were connected before */
-       { MISDN_HUNGUP_FROM_MISDN,   "HUNGUP_FROM_MISDN" },   /* when DISCONNECT/RELEASE/REL_COMP  came from misdn */
-       { MISDN_HOLDED,              "HOLDED" },              /* when DISCONNECT/RELEASE/REL_COMP  came from misdn */
-       { MISDN_HOLD_DISCONNECT,     "HOLD_DISCONNECT" },     /* when DISCONNECT/RELEASE/REL_COMP  came from misdn */
+       { MISDN_HUNGUP_FROM_MISDN,   "HUNGUP_FROM_MISDN" },   /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
+       { MISDN_HOLDED,              "HOLDED" },              /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
+       { MISDN_HOLD_DISCONNECT,     "HOLD_DISCONNECT" },     /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
        { MISDN_HUNGUP_FROM_AST,     "HUNGUP_FROM_AST" },     /* when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */
+/* *INDENT-ON* */
 };
 
 static const char *misdn_get_ch_state(struct chan_list *p)
@@ -1384,18 +1997,24 @@ static char *handle_cli_misdn_reload(struct ast_cli_entry *e, int cmd, struct as
 static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel *bc)
 {
        struct ast_channel *ast = help->ast;
-       ast_cli(fd,
-               "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n",
 
-               bc->pid, bc->port, bc->channel,
+       ast_cli(fd,
+               "* Pid:%d Port:%d Ch:%d Mode:%s Orig:%s dialed:%s\n"
+               "  --> caller:\"%s\" <%s>\n"
+               "  --> redirecting:\"%s\" <%s>\n"
+               "  --> context:%s state:%s\n",
+               bc->pid,
+               bc->port,
+               bc->channel,
                bc->nt ? "NT" : "TE",
                help->originator == ORG_AST ? "*" : "I",
-               ast ? ast->exten : NULL,
-               ast ? ast->cid.cid_num : NULL,
-               bc->rad,
-               ast ? ast->context : NULL,
-               misdn_get_ch_state(help)
-               );
+               ast ? ast->exten : "",
+               (ast && ast->cid.cid_name) ? ast->cid.cid_name : "",
+               (ast && ast->cid.cid_num) ? ast->cid.cid_num : "",
+               bc->redirecting.from.name,
+               bc->redirecting.from.number,
+               ast ? ast->context : "",
+               misdn_get_ch_state(help));
        if (misdn_debug[bc->port] > 0) {
                ast_cli(fd,
                        "  --> astname: %s\n"
@@ -1418,21 +2037,18 @@ static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel
                        help->l3id,
                        help->addr,
                        bc->addr,
-                       bc ? bc->l3_id : -1,
+                       bc->l3_id,
                        bc->display,
-
                        bc->active,
                        bc_state2str(bc->bc_state),
                        bearer2str(bc->capability),
 #ifdef MISDN_1_2
                        bc->pipeline,
 #else
-                       bc->ec_enable,
+                       bc->ec_enable,
 #endif
-
                        help->norxtone, help->notxtone,
-                       bc->holded
-                       );
+                       bc->holded);
        }
 }
 
@@ -1480,15 +2096,17 @@ static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, st
                        if (help->state == MISDN_HOLDED) {
                                ast_cli(a->fd, "ITS A HOLDED BC:\n");
                                ast_cli(a->fd, " --> l3_id: %x\n"
-                                               " --> dad:%s oad:%s\n"
-                                               " --> hold_port: %d\n"
-                                               " --> hold_channel: %d\n",
-                                               help->l3id,
-                                               ast->exten,
-                                               ast->cid.cid_num,
-                                               help->hold_info.port,
-                                               help->hold_info.channel
-                                               );
+                                       " --> dialed:%s\n"
+                                       " --> caller:\"%s\" <%s>\n"
+                                       " --> hold_port: %d\n"
+                                       " --> hold_channel: %d\n",
+                                       help->l3id,
+                                       ast->exten,
+                                       ast->cid.cid_name ? ast->cid.cid_name : "",
+                                       ast->cid.cid_num ? ast->cid.cid_num : "",
+                                       help->hold_info.port,
+                                       help->hold_info.channel
+                                       );
                        } else {
                                ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num);
                        }
@@ -1693,7 +2311,7 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st
                        return 0;
                }
                tmp->bc->fac_out.Function = Fac_CD;
-               ast_copy_string((char *)tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber));
+               ast_copy_string((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber));
                misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
        } else if (strstr(a->argv[3], "CFActivate")) {
                if (a->argc < 7) {
@@ -1718,7 +2336,7 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st
        } else if (strstr(a->argv[3], "CFDeactivate")) {
 
                if (a->argc < 6) {
-                       ast_verbose("CFActivate requires 1 arg: FromNumber\n\n");
+                       ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n");
                        return 0;
                }
                port = atoi(a->argv[4]);
@@ -1728,10 +2346,10 @@ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, st
                ast_verbose("Sending CFDeactivate  Port:(%d) FromNr. (%s)\n", port, served_nr);
 
                bc->fac_out.Function = Fac_CFDeactivate;
-               bc->fac_out.u.CFDeactivate.BasicService = 0; //All Services
-               bc->fac_out.u.CFDeactivate.Procedure = 0; //Unconditional
+               bc->fac_out.u.CFDeactivate.BasicService = 0; /* All Services */
+               bc->fac_out.u.CFDeactivate.Procedure = 0; /* Unconditional */
+               ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
 
-               ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
                misdn_lib_send_event(bc, EVENT_FACILITY);
        }
 
@@ -2009,23 +2627,25 @@ static struct ast_cli_entry chan_misdn_clis[] = {
 };
 
 /*! \brief Updates caller ID information from config */
-static int update_config(struct chan_list *ch, int orig)
+static void update_config(struct chan_list *ch)
 {
        struct ast_channel *ast;
        struct misdn_bchannel *bc;
-       int port, hdlc = 0;
-       int pres, screen;
+       int port;
+       int hdlc = 0;
+       int pres;
+       int screen;
 
        if (!ch) {
                ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
-               return -1;
+               return;
        }
 
        ast = ch->ast;
        bc = ch->bc;
        if (! ast || ! bc) {
                ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
-               return -1;
+               return;
        }
 
        port = bc->port;
@@ -2033,7 +2653,6 @@ static int update_config(struct chan_list *ch, int orig)
        chan_misdn_log(7, port, "update_config: Getting Config\n");
 
        misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
-
        if (hdlc) {
                switch (bc->capability) {
                case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
@@ -2050,48 +2669,17 @@ static int update_config(struct chan_list *ch, int orig)
        chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
 
        if (pres < 0 || screen < 0) {
-               chan_misdn_log(2, port, " --> pres: %x\n", ast->cid.cid_pres);
+               chan_misdn_log(2, port, " --> pres: %x\n", ast->connected.id.number_presentation);
 
-               switch (ast->cid.cid_pres & 0x60) {
-               case AST_PRES_RESTRICTED:
-                       bc->pres = 1;
-                       chan_misdn_log(2, port, " --> PRES: Restricted (1)\n");
-                       break;
-               case AST_PRES_UNAVAILABLE:
-                       bc->pres = 2;
-                       chan_misdn_log(2, port, " --> PRES: Unavailable (2)\n");
-                       break;
-               default:
-                       bc->pres = 0;
-                       chan_misdn_log(2, port, " --> PRES: Allowed (0)\n");
-                       break;
-               }
+               bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation);
+               chan_misdn_log(2, port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
 
-               switch (ast->cid.cid_pres & 0x3) {
-               default:
-               case AST_PRES_USER_NUMBER_UNSCREENED:
-                       bc->screen = 0;
-                       chan_misdn_log(2, port, " --> SCREEN: Unscreened (0)\n");
-                       break;
-               case AST_PRES_USER_NUMBER_PASSED_SCREEN:
-                       bc->screen = 1;
-                       chan_misdn_log(2, port, " --> SCREEN: Passed Screen (1)\n");
-                       break;
-               case AST_PRES_USER_NUMBER_FAILED_SCREEN:
-                       bc->screen = 2;
-                       chan_misdn_log(2, port, " --> SCREEN: Failed Screen (2)\n");
-                       break;
-               case AST_PRES_NETWORK_NUMBER:
-                       bc->screen = 3;
-                       chan_misdn_log(2, port, " --> SCREEN: Network Nr. (3)\n");
-                       break;
-               }
+               bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number_presentation);
+               chan_misdn_log(2, port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
        } else {
-               bc->screen = screen;
-               bc->pres = pres;
+               bc->caller.screening = screen;
+               bc->caller.presentation = pres;
        }
-
-       return 0;
 }
 
 
@@ -2130,20 +2718,26 @@ static void config_jitterbuffer(struct chan_list *ch)
 }
 
 
-void debug_numplan(int port, int numplan, char *type)
+void debug_numtype(int port, int numtype, char *type)
 {
-       switch (numplan) {
-       case NUMPLAN_INTERNATIONAL:
+       switch (numtype) {
+       case NUMTYPE_UNKNOWN:
+               chan_misdn_log(2, port, " --> %s: Unknown\n", type);
+               break;
+       case NUMTYPE_INTERNATIONAL:
                chan_misdn_log(2, port, " --> %s: International\n", type);
                break;
-       case NUMPLAN_NATIONAL:
+       case NUMTYPE_NATIONAL:
                chan_misdn_log(2, port, " --> %s: National\n", type);
                break;
-       case NUMPLAN_SUBSCRIBER:
+       case NUMTYPE_NETWORK_SPECIFIC:
+               chan_misdn_log(2, port, " --> %s: Network Specific\n", type);
+               break;
+       case NUMTYPE_SUBSCRIBER:
                chan_misdn_log(2, port, " --> %s: Subscriber\n", type);
                break;
-       case NUMPLAN_UNKNOWN:
-               chan_misdn_log(2, port, " --> %s: Unknown\n", type);
+       case NUMTYPE_ABBREVIATED:
+               chan_misdn_log(2, port, " --> %s: Abbreviated\n", type);
                break;
                /* Maybe we should cut off the prefix if present ? */
        default:
@@ -2193,7 +2787,7 @@ static int update_ec_config(struct misdn_bchannel *bc)
 #endif
 
 
-static int read_config(struct chan_list *ch, int orig)
+static int read_config(struct chan_list *ch)
 {
        struct ast_channel *ast;
        struct misdn_bchannel *bc;
@@ -2234,7 +2828,6 @@ static int read_config(struct chan_list *ch, int orig)
        misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf));
 
        misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int));
-
        if (ch->ast_dsp) {
                ch->ignore_dtmf = 1;
        }
@@ -2251,7 +2844,6 @@ static int read_config(struct chan_list *ch, int orig)
        misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect));
 
        misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc));
-
        if (hdlc) {
                switch (bc->capability) {
                case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
@@ -2280,14 +2872,16 @@ static int read_config(struct chan_list *ch, int orig)
 
        misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect));
 
+       misdn_cfg_get(port, MISDN_CFG_DISPLAY_CONNECTED, &bc->display_connected, sizeof(bc->display_connected));
+       misdn_cfg_get(port, MISDN_CFG_DISPLAY_SETUP, &bc->display_setup, sizeof(bc->display_setup));
+
        misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
        misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));
-
        chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
        ast->pickupgroup = pg;
        ast->callgroup = cg;
 
-       if (orig == ORG_AST) {
+       if (ch->originator == ORG_AST) {
                char callerid[BUFFERSIZE + 1];
 
                /* ORIGINATOR Asterisk (outgoing call) */
@@ -2300,80 +2894,46 @@ static int read_config(struct chan_list *ch, int orig)
 
                misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid));
                if (!ast_strlen_zero(callerid)) {
-                       chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid);
-                       ast_copy_string(bc->oad, callerid, sizeof(bc->oad));
+                       char *cid_name = NULL;
+                       char *cid_num = NULL;
+
+                       ast_callerid_parse(callerid, &cid_name, &cid_num);
+                       if (cid_name) {
+                               ast_copy_string(bc->caller.name, cid_name, sizeof(bc->caller.name));
+                       } else {
+                               bc->caller.name[0] = '\0';
+                       }
+                       if (cid_num) {
+                               ast_copy_string(bc->caller.number, cid_num, sizeof(bc->caller.number));
+                       } else {
+                               bc->caller.number[0] = '\0';
+                       }
+                       chan_misdn_log(1, port, " --> * Setting caller to \"%s\" <%s>\n", bc->caller.name, bc->caller.number);
                }
 
-               misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(bc->dnumplan));
-               misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(bc->onumplan));
-               misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan));
-               debug_numplan(port, bc->dnumplan, "TON");
-               debug_numplan(port, bc->onumplan, "LTON");
-               debug_numplan(port, bc->cpnnumplan, "CTON");
+               misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dialed.number_type, sizeof(bc->dialed.number_type));
+               bc->dialed.number_plan = NUMPLAN_ISDN;
+               debug_numtype(port, bc->dialed.number_type, "TON");
 
                ch->overlap_dial = 0;
        } else {
                /* ORIGINATOR MISDN (incoming call) */
-               char prefix[BUFFERSIZE + 1] = "";
 
                if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
                        ch->faxdetect = (strstr(faxdetect, "nojump")) ? 2 : 1;
                }
 
-               misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan));
-               debug_numplan(port, bc->cpnnumplan, "CTON");
+               /* Add configured prefix to caller.number */
+               misdn_add_number_prefix(bc->port, bc->caller.number_type, bc->caller.number, sizeof(bc->caller.number));
 
-               switch (bc->onumplan) {
-               case NUMPLAN_INTERNATIONAL:
-                       misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix));
-                       break;
-
-               case NUMPLAN_NATIONAL:
-                       misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix));
-                       break;
-               default:
-                       break;
-               }
-
-               ast_copy_string(buf, bc->oad, sizeof(buf));
-               snprintf(bc->oad, sizeof(bc->oad), "%s%s", prefix, buf);
-
-               if (!ast_strlen_zero(bc->dad)) {
-                       ast_copy_string(bc->orig_dad, bc->dad, sizeof(bc->orig_dad));
-               }
-
-               if (ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) {
-                       ast_copy_string(bc->dad, bc->keypad, sizeof(bc->dad));
-               }
-
-               prefix[0] = 0;
-
-               switch (bc->dnumplan) {
-               case NUMPLAN_INTERNATIONAL:
-                       misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix));
-                       break;
-               case NUMPLAN_NATIONAL:
-                       misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix));
-                       break;
-               default:
-                       break;
-               }
-
-               ast_copy_string(buf, bc->dad, sizeof(buf));
-               snprintf(bc->dad, sizeof(bc->dad), "%s%s", prefix, buf);
-
-               if (strcmp(bc->dad, ast->exten)) {
-                       ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten));
+               if (ast_strlen_zero(bc->dialed.number) && !ast_strlen_zero(bc->keypad)) {
+                       ast_copy_string(bc->dialed.number, bc->keypad, sizeof(bc->dialed.number));
                }
 
-               ast_set_callerid(ast, bc->oad, NULL, bc->oad);
+               /* Add configured prefix to dialed.number */
+               misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number));
 
-               if ( !ast_strlen_zero(bc->rad) ) {
-                       if (ast->cid.cid_rdnis) {
-                               ast_free(ast->cid.cid_rdnis);
-                       }
-                       ast->cid.cid_rdnis = ast_strdup(bc->rad);
-               }
+               ast_copy_string(ast->exten, bc->dialed.number, sizeof(ast->exten));
 
                misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
                ast_mutex_init(&ch->overlap_tv_lock);
@@ -2400,6 +2960,79 @@ static int read_config(struct chan_list *ch, int orig)
        return 0;
 }
 
+/*!
+ * \internal
+ * \brief Notify peer that the connected line has changed.
+ *
+ * \param ast Current Asterisk channel
+ * \param bc Associated B channel
+ * \param originator Who originally created this channel. ORG_AST or ORG_MISDN
+ *
+ * \return Nothing
+ */
+static void misdn_update_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
+{
+       int number_type;
+
+       if (originator == ORG_MISDN) {
+               /* ORIGINATOR MISDN (incoming call) */
+
+               ast_copy_string(bc->connected.name, S_OR(ast->connected.id.name, ""), sizeof(bc->connected.name));
+               ast_copy_string(bc->connected.number, S_OR(ast->connected.id.number, ""), sizeof(bc->connected.number));
+               bc->connected.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation);
+               bc->connected.screening = ast_to_misdn_screen(ast->connected.id.number_presentation);
+
+               misdn_cfg_get(bc->port, MISDN_CFG_CPNDIALPLAN, &number_type, sizeof(number_type));
+               if (number_type < 0) {
+                       bc->connected.number_type = ast_to_misdn_ton(ast->connected.id.number_type);
+                       bc->connected.number_plan = ast_to_misdn_plan(ast->connected.id.number_type);
+               } else {
+                       /* Force us to send in CONNECT message */
+                       bc->connected.number_type = number_type;
+                       bc->connected.number_plan = NUMPLAN_ISDN;
+               }
+               debug_numtype(bc->port, bc->connected.number_type, "CTON");
+       } else {
+               /* ORIGINATOR Asterisk (outgoing call) */
+
+               ast_copy_string(bc->caller.name, S_OR(ast->connected.id.name, ""), sizeof(bc->caller.name));
+               ast_copy_string(bc->caller.number, S_OR(ast->connected.id.number, ""), sizeof(bc->caller.number));
+               bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation);
+               bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number_presentation);
+
+               misdn_cfg_get(bc->port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
+               if (number_type < 0) {
+                       bc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type);
+                       bc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number_type);
+               } else {
+                       /* Force us to send in SETUP message */
+                       bc->caller.number_type = number_type;
+                       bc->caller.number_plan = NUMPLAN_ISDN;
+               }
+               debug_numtype(bc->port, bc->caller.number_type, "LTON");
+       }
+}
+
+/*!
+ * \internal
+ * \brief Copy the redirecting info out of the Asterisk channel
+ *
+ * \param bc Associated B channel
+ * \param ast Current Asterisk channel
+ *
+ * \return Nothing
+ */
+static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct ast_channel *ast)
+{
+       ast_copy_string(bc->redirecting.from.name, S_OR(ast->redirecting.from.name, ""), sizeof(bc->redirecting.from.name));
+       ast_copy_string(bc->redirecting.from.number, S_OR(ast->cid.cid_rdnis, ""), sizeof(bc->redirecting.from.number));
+       bc->redirecting.from.presentation = ast_to_misdn_pres(ast->redirecting.from.number_presentation);
+       bc->redirecting.from.screening = ast_to_misdn_screen(ast->redirecting.from.number_presentation);
+       bc->redirecting.from.number_type = ast_to_misdn_ton(ast->redirecting.from.number_type);
+       bc->redirecting.from.number_plan = ast_to_misdn_plan(ast->redirecting.from.number_type);
+       bc->redirecting.reason = ast_to_misdn_reason(ast->redirecting.reason);
+}
+
 
 /*****************************/
 /*** AST Indications Start ***/
@@ -2411,22 +3044,17 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
        int r;
        int exceed;
        int bridging;
-       struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(ast);
+       int number_type;
+       struct chan_list *ch;
        struct misdn_bchannel *newbc;
-       char *dest_cp = ast_strdupa(dest);
+       char *dest_cp;
+
        AST_DECLARE_APP_ARGS(args,
-               AST_APP_ARG(type);
-               AST_APP_ARG(ext);
-               AST_APP_ARG(opts);
+               AST_APP_ARG(intf);      /* The interface token is discarded. */
+               AST_APP_ARG(ext);       /* extension token */
+               AST_APP_ARG(opts);      /* options token */
        );
 
-       AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
-
-       if (ast_strlen_zero(args.ext)) {
-               chan_misdn_log(0, 0, "misdn_call: No Extension given!\n");
-               return -1;
-       }
-
        if (!ast) {
                ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
                return -1;
@@ -2439,47 +3067,74 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
                return -1;
        }
 
+       ch = MISDN_ASTERISK_TECH_PVT(ast);
        if (!ch) {
-               ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
+               ast_log(LOG_WARNING, " --> ! misdn_call called on %s, chan_list *ch==NULL\n", ast->name);
                ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
                ast_setstate(ast, AST_STATE_DOWN);
                return -1;
        }
 
        newbc = ch->bc;
-
        if (!newbc) {
-               ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
+               ast_log(LOG_WARNING, " --> ! misdn_call called on %s, newbc==NULL\n", ast->name);
                ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
                ast_setstate(ast, AST_STATE_DOWN);
                return -1;
        }
 
+       /*
+        * dest is ---v
+        * Dial(mISDN/g:group_name[/extension[/options]])
+        * Dial(mISDN/port[:preselected_channel][/extension[/options]])
+        *
+        * The dial extension could be empty if you are using MISDN_KEYPAD
+        * to control ISDN provider features.
+        */
+       dest_cp = ast_strdupa(dest);
+       AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
+       if (!args.ext) {
+               args.ext = "";
+       }
+
        port = newbc->port;
 
-       if ((exceed = add_out_calls(port))) {
+       exceed = add_out_calls(port);
+       if (exceed != 0) {
                char tmp[16];
                snprintf(tmp, sizeof(tmp), "%d", exceed);
                pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
+               ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
+               ast_setstate(ast, AST_STATE_DOWN);
                return -1;
        }
 
        chan_misdn_log(1, port, "* CALL: %s\n", dest);
 
-       chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n", ast->exten, ast->name, ast->context);
+       chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast->name, ast->context);
 
-       chan_misdn_log(3, port, " --> * adding2newbc ext %s\n", ast->exten);
-       if (ast->exten) {
-               ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
-               ast_copy_string(newbc->dad, args.ext, sizeof(newbc->dad));
-       }
+       ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
+       ast_copy_string(newbc->dialed.number, args.ext, sizeof(newbc->dialed.number));
 
-       ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad));
+       if (ast_strlen_zero(newbc->caller.name) && !ast_strlen_zero(ast->connected.id.name)) {
+               ast_copy_string(newbc->caller.name, ast->connected.id.name, sizeof(newbc->caller.name));
+               chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
+       }
+       if (ast_strlen_zero(newbc->caller.number) && !ast_strlen_zero(ast->connected.id.number)) {
+               ast_copy_string(newbc->caller.number, ast->connected.id.number, sizeof(newbc->caller.number));
+               chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
+       }
 
-       chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n", ast->cid.cid_num);
-       if (ast_strlen_zero(newbc->oad) && !ast_strlen_zero(ast->cid.cid_num)) {
-               ast_copy_string(newbc->oad, ast->cid.cid_num, sizeof(newbc->oad));
+       misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
+       if (number_type < 0) {
+               newbc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type);
+               newbc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number_type);
+       } else {
+               /* Force us to send in SETUP message */
+               newbc->caller.number_type = number_type;
+               newbc->caller.number_plan = NUMPLAN_ISDN;
        }
+       debug_numtype(port, newbc->caller.number_type, "LTON");
 
        newbc->capability = ast->transfercapability;
        pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability));
@@ -2487,10 +3142,10 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
                chan_misdn_log(2, port, " --> * Call with flag Digital\n");
        }
 
-       /* update screening and presentation */
-       update_config(ch, ORG_AST);
+       /* update caller screening and presentation */
+       update_config(ch);
 
-       /* fill in some ies from channel vary */
+       /* fill in some ies from channel dialplan variables */
        import_ch(ast, newbc, ch);
 
        /* Finally The Options Override Everything */
@@ -2499,6 +3154,11 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
        } else {
                chan_misdn_log(2, port, "NO OPTS GIVEN\n");
        }
+       if (newbc->set_presentation) {
+               newbc->caller.presentation = newbc->presentation;
+       }
+
+       misdn_copy_redirecting_from_ast(newbc, ast);
 
        /*check for bridging*/
        misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
@@ -2519,7 +3179,7 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
        /** we should have l3id after sending setup **/
        ch->l3id = newbc->l3_id;
 
-       if (r == -ENOCHAN ) {
+       if (r == -ENOCHAN) {
                chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
                chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1);
                ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
@@ -2585,9 +3245,19 @@ static int misdn_answer(struct ast_channel *ast)
        p->state = MISDN_CONNECTED;
        stop_indicate(p);
 
-       if ( ast_strlen_zero(p->bc->cad) ) {
-               chan_misdn_log(2, p->bc->port, " --> empty cad using dad\n");
-               ast_copy_string(p->bc->cad, p->bc->dad, sizeof(p->bc->cad));
+       if (ast_strlen_zero(p->bc->connected.number)) {
+               chan_misdn_log(2,p->bc->port," --> empty connected number using dialed number\n");
+               ast_copy_string(p->bc->connected.number, p->bc->dialed.number, sizeof(p->bc->connected.number));
+
+               /*
+                * Use the misdn_set_opt() application to set the presentation
+                * before we answer or you can use the CONECTEDLINE() function
+                * to set everything before using the Answer() application.
+                */
+               p->bc->connected.presentation = p->bc->presentation;
+               p->bc->connected.screening = 0; /* unscreened */
+               p->bc->connected.number_type = p->bc->dialed.number_type;
+               p->bc->connected.number_plan = p->bc->dialed.number_plan;
        }
 
        misdn_lib_send_event(p->bc, EVENT_CONNECT);
@@ -2628,15 +3298,15 @@ static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int dur
                break;
        case MISDN_CALLING_ACKNOWLEDGE:
                ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad));
-               if (strlen(bc->dad) < sizeof(bc->dad) - 1) {
-                       strncat(bc->dad, buf, sizeof(bc->dad) - strlen(bc->dad) - 1);
+               if (strlen(bc->dialed.number) < sizeof(bc->dialed.number) - 1) {
+                       strncat(bc->dialed.number, buf, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
                }
-               ast_copy_string(p->ast->exten, bc->dad, sizeof(p->ast->exten));
+               ast_copy_string(p->ast->exten, bc->dialed.number, sizeof(p->ast->exten));
                misdn_lib_send_event(bc, EVENT_INFORMATION);
                break;
        default:
                /* Do not send Digits in CONNECTED State, when
-                * the other side is too mISDN. */
+                * the other side is also mISDN. */
                if (p->other_ch) {
                        return 0;
                }
@@ -2687,7 +3357,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
 
        switch (cond) {
        case AST_CONTROL_BUSY:
-               chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc->pid);
                ast_setstate(ast, AST_STATE_BUSY);
 
                p->bc->out_cause = AST_CAUSE_USER_BUSY;
@@ -2699,20 +3369,20 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
                }
                return -1;
        case AST_CONTROL_RING:
-               chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc->pid);
                return -1;
        case AST_CONTROL_RINGING:
-               chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc->pid);
                switch (p->state) {
                case MISDN_ALERTING:
-                       chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc ? p->bc->pid : -1);
+                       chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc->pid);
                        break;
                case MISDN_CONNECTED:
-                       chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc ? p->bc->pid : -1);
+                       chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc->pid);
                        return -1;
                default:
                        p->state = MISDN_ALERTING;
-                       chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
+                       chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc->pid);
                        misdn_lib_send_event( p->bc, EVENT_ALERTING);
 
                        if (p->other_ch && p->other_ch->bc) {
@@ -2727,7 +3397,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
                                }
                        }
 
-                       chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc ? p->bc->pid : -1);
+                       chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc->pid);
                        ast_setstate(ast, AST_STATE_RING);
 
                        if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio) {
@@ -2738,28 +3408,28 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
                }
                break;
        case AST_CONTROL_ANSWER:
-               chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc->pid);
                start_bc_tones(p);
                break;
        case AST_CONTROL_TAKEOFFHOOK:
-               chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc->pid);
                return -1;
        case AST_CONTROL_OFFHOOK:
-               chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc->pid);
                return -1;
        case AST_CONTROL_FLASH:
-               chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc->pid);
                break;
        case AST_CONTROL_PROGRESS:
-               chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc->pid);
                misdn_lib_send_event( p->bc, EVENT_PROGRESS);
                break;
        case AST_CONTROL_PROCEEDING:
-               chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc->pid);
                misdn_lib_send_event( p->bc, EVENT_PROCEEDING);
                break;
        case AST_CONTROL_CONGESTION:
-               chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc->pid);
 
                p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION;
                start_bc_tones(p);
@@ -2770,7 +3440,7 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
                }
                break;
        case -1 :
-               chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc->pid);
 
                stop_indicate(p);
 
@@ -2780,14 +3450,23 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
                break;
        case AST_CONTROL_HOLD:
                ast_moh_start(ast, data, p->mohinterpret);
-               chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc->pid);
                break;
        case AST_CONTROL_UNHOLD:
                ast_moh_stop(ast);
-               chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc->pid);
+               break;
+       case AST_CONTROL_CONNECTED_LINE:
+               chan_misdn_log(1, p->bc->port, "* IND :\tconnected line update pid:%d\n", p->bc->pid);
+               misdn_update_connected_line(ast, p->bc, p->originator);
+               break;
+       case AST_CONTROL_REDIRECTING:
+               chan_misdn_log(1, p->bc->port, "* IND :\tredirecting info update pid:%d\n", p->bc->pid);
+               misdn_copy_redirecting_from_ast(p->bc, ast);
                break;
        default:
-               chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc ? p->bc->pid : -1);
+               chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc->pid);
+               break;
        }
 
        return 0;
@@ -2814,8 +3493,10 @@ static int misdn_hangup(struct ast_channel *ast)
 
        if (bc) {
                const char *tmp;
+
                ast_channel_lock(ast);
-               if ((tmp = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER"))) {
+               tmp = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER");
+               if (tmp) {
                        ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
                        strcpy(bc->uu, tmp);
                        bc->uulen = strlen(bc->uu);
@@ -2875,11 +3556,17 @@ static int misdn_hangup(struct ast_channel *ast)
        }
        ast_channel_unlock(ast);
 
-       chan_misdn_log(1, bc->port, "* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n", p->bc ? p->bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(p));
+       chan_misdn_log(1, bc->port,
+               "* IND : HANGUP\tpid:%d context:%s dialed:%s caller:\"%s\" <%s> State:%s\n",
+               p->bc ? p->bc->pid : -1,
+               ast->context,
+               ast->exten,
+               ast->cid.cid_name ? ast->cid.cid_name : "",
+               ast->cid.cid_num ? ast->cid.cid_num : "",
+               misdn_get_ch_state(p));
        chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
        chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
        chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);
-       chan_misdn_log(2, bc->port, " --> state:%s\n", misdn_get_ch_state(p));
 
        switch (p->state) {
        case MISDN_INCOMING_SETUP:
@@ -3034,7 +3721,7 @@ static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame
                                                        ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
                                                }
                                        } else {
-                                               ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten);
+                                               ast_log(LOG_NOTICE, "Fax detected but no fax extension, context:%s exten:%s\n", context, ast->exten);
                                        }
                                } else {
                                        ast_debug(1, "Already in a fax extension, not redirecting\n");
@@ -3081,7 +3768,8 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
        FD_ZERO(&rrfs);
        FD_SET(tmp->pipe[0], &rrfs);
 
-       if (!(t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv))) {
+       t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv);
+       if (!t) {
                chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
                len = 160;
        }
@@ -3249,15 +3937,11 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
        return 0;
 }
 
-
-
-
-static enum ast_bridge_result  misdn_bridge (struct ast_channel *c0,
-                                     struct ast_channel *c1, int flags,
-                                     struct ast_frame **fo,
-                                     struct ast_channel **rc,
-                                     int timeoutms)
-
+static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
+       struct ast_channel *c1, int flags,
+       struct ast_frame **fo,
+       struct ast_channel **rc,
+       int timeoutms)
 {
        struct chan_list *ch1, *ch2;
        struct ast_channel *carr[2], *who;
@@ -3293,7 +3977,11 @@ static enum ast_bridge_result  misdn_bridge (struct ast_channel *c0,
 
        ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
 
-       chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad);
+       chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between \"%s\" <%s> and \"%s\" <%s>\n",
+               ch1->bc->caller.name,
+               ch1->bc->caller.number,
+               ch2->bc->caller.name,
+               ch2->bc->caller.number);
 
        if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) ) {
                ch1->ignore_dtmf = 1;
@@ -3342,7 +4030,7 @@ static enum ast_bridge_result  misdn_bridge (struct ast_channel *c0,
                }
 #endif
 
-               ast_write(who == c0 ? c1 : c0, f);
+               ast_write((who == c0) ? c1 : c0, f);
        }
 
        chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1);
@@ -3437,7 +4125,8 @@ static struct chan_list *init_chan_list(int orig)
 {
        struct chan_list *cl;
 
-       if (!(cl = ast_calloc(1, sizeof(*cl)))) {
+       cl = ast_calloc(1, sizeof(*cl));
+       if (!cl) {
                chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
                return NULL;
        }
@@ -3455,38 +4144,54 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat
 {
        struct ast_channel *tmp = NULL;
        char group[BUFFERSIZE + 1] = "";
-       char buf[128];
-       char *buf2 = ast_strdupa(data), *ext = NULL, *port_str;
-       char *tokb = NULL, *p = NULL;
-       int channel = 0, port = 0;
+       char dial_str[128];
+       char *dest_cp;
+       char *p = NULL;
+       int channel = 0;
+       int port = 0;
        struct misdn_bchannel *newbc = NULL;
        int dec = 0;
+       struct chan_list *cl;
 
-       struct chan_list *cl = init_chan_list(ORG_AST);
-
-       snprintf(buf, sizeof(buf), "%s/%s", misdn_type, (char*)data);
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(intf);      /* interface token */
+               AST_APP_ARG(ext);       /* extension token */
+               AST_APP_ARG(opts);      /* options token */
+       );
 
-       port_str = strtok_r(buf2, "/", &tokb);
+       snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data);
 
-       ext = strtok_r(NULL, "/", &tokb);
+       /*
+        * data is ---v
+        * Dial(mISDN/g:group_name[/extension[/options]])
+        * Dial(mISDN/port[:preselected_channel][/extension[/options]])
+        *
+        * The dial extension could be empty if you are using MISDN_KEYPAD
+        * to control ISDN provider features.
+        */
+       dest_cp = ast_strdupa(data);
+       AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
+       if (!args.ext) {
+               args.ext = "";
+       }
 
-       if (port_str) {
-               if (port_str[0] == 'g' && port_str[1] == ':' ) {
+       if (!ast_strlen_zero(args.intf)) {
+               if (args.intf[0] == 'g' && args.intf[1] == ':' ) {
                        /* We make a group call lets checkout which ports are in my group */
-                       port_str += 2;
-                       ast_copy_string(group, port_str, sizeof(group));
+                       args.intf += 2;
+                       ast_copy_string(group, args.intf, sizeof(group));
                        chan_misdn_log(2, 0, " --> Group Call group: %s\n", group);
-               } else if ((p = strchr(port_str, ':'))) {
+               } else if ((p = strchr(args.intf, ':'))) {
                        /* we have a preselected channel */
-                       *p = 0;
-                       channel = atoi(++p);
-                       port = atoi(port_str);
+                       *p++ = 0;
+                       channel = atoi(p);
+                       port = atoi(args.intf);
                        chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel);
                } else {
-                       port = atoi(port_str);
+                       port = atoi(args.intf);
                }
        } else {
-               ast_log(LOG_WARNING, " --> ! IND : CALL dad:%s WITHOUT PORT/Group, check extensions.conf\n", ext);
+               ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str);
                return NULL;
        }
 
@@ -3579,7 +4284,8 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat
                                        chan_misdn_log(4, port, "portup:%d\n", port_up);
 
                                        if (port_up > 0) {
-                                               if ((newbc = misdn_lib_get_free_bc(port, 0, 0, dec))) {
+                                               newbc = misdn_lib_get_free_bc(port, 0, 0, dec);
+                                               if (newbc) {
                                                        break;
                                                }
                                        }
@@ -3602,18 +4308,22 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat
                        chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel);
                }
                newbc = misdn_lib_get_free_bc(port, channel, 0, dec);
-
                if (!newbc) {
-                       ast_log(LOG_WARNING, "Could not create channel on port:%d with extensions:%s\n", port, ext);
+                       ast_log(LOG_WARNING, "Could not create channel on port:%d for Dial(%s)\n", port, dial_str);
                        return NULL;
                }
        }
 
 
        /* create ast_channel and link all the objects together */
+       cl = init_chan_list(ORG_AST);
+       if (!cl) {
+               ast_log(LOG_WARNING, "Could not create Asterisk channel for Dial(%s)\n", dial_str);
+               return NULL;
+       }
        cl->bc = newbc;
 
-       tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel);
+       tmp = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, format, port, channel);
        if (!tmp) {
                ast_log(LOG_ERROR, "Could not create Asterisk object\n");
                return NULL;
@@ -3625,7 +4335,7 @@ static struct ast_channel *misdn_request(const char *type, int format, void *dat
        cl_queue_chan(&cl_te, cl);
 
        /* fill in the config into the objects */
-       read_config(cl, ORG_AST);
+       read_config(cl);
 
        /* important */
        cl->need_hangup = 0;
@@ -3736,7 +4446,7 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state,  char
 
        tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++);
        if (tmp) {
-               chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n", exten, callerid);
+               chan_misdn_log(2, 0, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid);
 
                tmp->nativeformats = prefformat;
 
@@ -3791,7 +4501,11 @@ static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bc
                }
        }
 
-       chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
+       chan_misdn_log(6, bc->port,
+               "$$$ find_chan_by_bc: No channel found for dialed:%s caller:\"%s\" <%s>\n",
+               bc->dialed.number,
+               bc->caller.name,
+               bc->caller.number);
 
        return NULL;
 }
@@ -3805,7 +4519,7 @@ static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid)
                }
        }
 
-       chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n", pid);
+       chan_misdn_log(6, 0, "$$$ find_chan_by_pid: No channel found for pid:%d\n", pid);
 
        return NULL;
 }
@@ -3818,7 +4532,11 @@ static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchann
                return NULL;
        }
 
-       chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad);
+       chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d dialed:%s caller:\"%s\" <%s>\n",
+               bc->channel,
+               bc->dialed.number,
+               bc->caller.name,
+               bc->caller.number);
        for (; help; help = help->next) {
                chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n", help->state == MISDN_HOLDED, help->hold_info.channel);
                if ((help->state == MISDN_HOLDED) &&
@@ -3826,7 +4544,11 @@ static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchann
                        return help;
                }
        }
-       chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
+       chan_misdn_log(6, bc->port,
+               "$$$ find_holded: No channel found for dialed:%s caller:\"%s\" <%s>\n",
+               bc->dialed.number,
+               bc->caller.name,
+               bc->caller.number);
 
        return NULL;
 }
@@ -3947,12 +4669,14 @@ static void hangup_chan(struct chan_list *ch)
 }
 
 /** Isdn asks us to release channel, pendant to misdn_hangup **/
-static void release_chan(struct misdn_bchannel *bc) {
+static void release_chan(struct misdn_bchannel *bc)
+{
        struct ast_channel *ast = NULL;
        struct chan_list *ch;
 
        ast_mutex_lock(&release_lock);
-       if (!(ch = find_chan_by_bc(cl_te, bc))) {
+       ch = find_chan_by_bc(cl_te, bc);
+       if (!ch) {
                chan_misdn_log(1, bc->port, "release_chan: Ch not found!\n");
                ast_mutex_unlock(&release_lock);
                return;
@@ -3965,7 +4689,7 @@ static void release_chan(struct misdn_bchannel *bc) {
        chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id);
 
        /* releasing jitterbuffer */
-       if (ch->jb ) {
+       if (ch->jb) {
                misdn_jb_destroy(ch->jb);
                ch->jb = NULL;
        } else {
@@ -3993,7 +4717,14 @@ static void release_chan(struct misdn_bchannel *bc) {
                close(ch->pipe[1]);
 
                if (ast && MISDN_ASTERISK_TECH_PVT(ast)) {
-                       chan_misdn_log(1, bc->port, "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s\n", bc ? bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(ch));
+                       chan_misdn_log(1, bc->port,
+                               "* RELEASING CHANNEL pid:%d context:%s dialed:%s caller:\"%s\" <%s> state: %s\n",
+                               bc->pid,
+                               ast->context,
+                               ast->exten,
+                               ast->cid.cid_name ? ast->cid.cid_name : "",
+                               ast->cid.cid_num ? ast->cid.cid_num : "",
+                               misdn_get_ch_state(ch));
                        chan_misdn_log(3, bc->port, " --> * State Down\n");
                        MISDN_ASTERISK_TECH_PVT(ast) = NULL;
 
@@ -4053,9 +4784,14 @@ static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch,
                ch->state = MISDN_INCOMING_SETUP;
        }
 
-       chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, ast->cid.cid_num);
+       chan_misdn_log(1, bc->port,
+               "* Starting Ast context:%s dialed:%s caller:\"%s\" <%s> with 's' extension\n",
+               ast->context,
+               ast->exten,
+               ast->cid.cid_name ? ast->cid.cid_name : "",
+               ast->cid.cid_num ? ast->cid.cid_num : "");
 
-       strncpy(ast->exten, "s", 2);
+       strcpy(ast->exten, "s");
 
        if (pbx_start_chan(ch) < 0) {
                ast = NULL;
@@ -4183,6 +4919,7 @@ void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_
 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
 {
        char tmp[32];
+
        chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid);
        snprintf(tmp, sizeof(tmp), "%d", bc->pid);
        pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp);
@@ -4237,7 +4974,8 @@ int add_out_calls(int port)
        return 0;
 }
 
-static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
+static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
+{
        if (pbx_start_chan(ch) < 0) {
                hangup_chan(ch);
                chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
@@ -4250,10 +4988,11 @@ static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct as
        }
 }
 
-static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
+static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
+{
        ch->state = MISDN_WAITING4DIGS;
        misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
-       if (bc->nt && !bc->dad[0]) {
+       if (bc->nt && !bc->dialed.number[0]) {
                dialtone_indicate(ch);
        }
 }
@@ -4273,7 +5012,14 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        debuglevel = 5;
                }
 
-               chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch ? misdn_get_ch_state(ch) : "none");
+               chan_misdn_log(debuglevel, bc->port,
+                       "I IND :%s caller:\"%s\" <%s> dialed:%s pid:%d state:%s\n",
+                       manager_isdn_get_info(event),
+                       bc->caller.name,
+                       bc->caller.number,
+                       bc->dialed.number,
+                       bc->pid,
+                       ch ? misdn_get_ch_state(ch) : "none");
                if (debuglevel == 1) {
                        misdn_lib_log_ies(bc);
                        chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state));
@@ -4407,25 +5153,23 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad));
                        }
 
-                       strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
-                       ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
+                       strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
+                       ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
 
                        /* Check for Pickup Request first */
                        if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
                                if (ast_pickup_call(ch->ast)) {
                                        hangup_chan(ch);
                                } else {
-                                       struct ast_channel *chan = ch->ast;
                                        ch->state = MISDN_CALLING_ACKNOWLEDGE;
-                                       ast_setstate(chan, AST_STATE_DOWN);
                                        hangup_chan(ch);
                                        ch->ast = NULL;
                                        break;
                                }
                        }
 
-                       if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
-                               if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
+                       if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
+                               if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
                                        ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port);
                                        strcpy(ch->ast->exten, "i");
 
@@ -4459,7 +5203,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                break;
                        }
 
-                       if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad))  {
+                       if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number))  {
                                ch->state = MISDN_DIALING;
                                start_pbx(ch, bc, ch->ast);
                        }
@@ -4482,8 +5226,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits));
                        if (ch->state != MISDN_CONNECTED ) {
                                if (digits) {
-                                       strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
-                                       ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
+                                       strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
+                                       ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
                                        ast_cdr_update(ch->ast);
                                }
 
@@ -4494,10 +5238,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
        case EVENT_SETUP:
        {
                struct chan_list *ch = find_chan_by_bc(cl_te, bc);
-               int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad);
+               int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dialed.number);
                struct ast_channel *chan;
                int exceed;
-               int pres, screen;
                int ai;
                int im;
 
@@ -4537,10 +5280,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                ch->bc = bc;
                ch->l3id = bc->l3_id;
                ch->addr = bc->addr;
-               ch->originator = ORG_MISDN;
-
-               chan = misdn_new(ch, AST_STATE_RESERVED, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel);
 
+               chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, AST_FORMAT_ALAW, bc->port, bc->channel);
                if (!chan) {
                        misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
                        ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n");
@@ -4555,49 +5296,44 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp);
                }
 
-               read_config(ch, ORG_MISDN);
+               read_config(ch);
 
                export_ch(chan, bc, ch);
 
                ch->ast->rings = 1;
                ast_setstate(ch->ast, AST_STATE_RINGING);
 
-               switch (bc->pres) {
-               case 1:
-                       pres = AST_PRES_RESTRICTED;
-                       chan_misdn_log(2, bc->port, " --> PRES: Restricted (1)\n");
-                       break;
-               case 2:
-                       pres = AST_PRES_UNAVAILABLE;
-                       chan_misdn_log(2, bc->port, " --> PRES: Unavailable (2)\n");
-                       break;
-               default:
-                       pres = AST_PRES_ALLOWED;
-                       chan_misdn_log(2, bc->port, " --> PRES: Allowed (%d)\n", bc->pres);
-                       break;
-               }
+               /* Update asterisk channel caller information */
+               chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type);
+               chan_misdn_log(2, bc->port, " --> PLAN: %s(%d)\n", misdn_to_str_plan(bc->caller.number_plan), bc->caller.number_plan);
+               chan->cid.cid_ton = misdn_to_ast_ton(bc->caller.number_type)
+                       | misdn_to_ast_plan(bc->caller.number_plan);
 
-               switch (bc->screen) {
-               default:
-               case 0:
-                       screen = AST_PRES_USER_NUMBER_UNSCREENED;
-                       chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (%d)\n", bc->screen);
-                       break;
-               case 1:
-                       screen = AST_PRES_USER_NUMBER_PASSED_SCREEN;
-                       chan_misdn_log(2, bc->port, " --> SCREEN: Passed screen (1)\n");
-                       break;
-               case 2:
-                       screen = AST_PRES_USER_NUMBER_FAILED_SCREEN;
-                       chan_misdn_log(2, bc->port, " --> SCREEN: failed screen (2)\n");
-                       break;
-               case 3:
-                       screen = AST_PRES_NETWORK_NUMBER;
-                       chan_misdn_log(2, bc->port, " --> SCREEN: Network Number (3)\n");
-                       break;
-               }
+               chan_misdn_log(2, bc->port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
+               chan_misdn_log(2, bc->port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
+               chan->cid.cid_pres = misdn_to_ast_pres(bc->caller.presentation)
+                       | misdn_to_ast_screen(bc->caller.screening);
+
+               ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number);
+
+               if (!ast_strlen_zero(bc->redirecting.from.number)) {
+                       struct ast_party_redirecting redirecting;
+
+                       /* Add configured prefix to redirecting.from.number */
+                       misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type, bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
 
-               chan->cid.cid_pres = pres | screen;
+                       /* Update asterisk channel redirecting information */
+                       ast_party_redirecting_set_init(&redirecting, &chan->redirecting);
+                       redirecting.from.number = bc->redirecting.from.number;
+                       redirecting.from.number_type =
+                               misdn_to_ast_ton(bc->redirecting.from.number_type)
+                               | misdn_to_ast_plan(bc->redirecting.from.number_plan);
+                       redirecting.from.number_presentation =
+                               misdn_to_ast_pres(bc->redirecting.from.presentation)
+                               | misdn_to_ast_screen(bc->redirecting.from.screening);
+                       redirecting.reason = misdn_to_ast_reason(bc->redirecting.reason);
+                       ast_channel_set_redirecting(chan, &redirecting);
+               }
 
                pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
                chan->transfercapability = bc->capability;
@@ -4627,7 +5363,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                                break;
                                        }
                                }
-                       }       /* end for */
+                       }
                        if (i == ARRAY_LEN(allowed_bearers_array)) {
                                /* We did not find the bearer capability */
                                chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
@@ -4652,7 +5388,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                hangup_chan(ch);
                        } else {
                                ch->state = MISDN_CALLING_ACKNOWLEDGE;
-                               ast_setstate(chan, AST_STATE_DOWN);
                                hangup_chan(ch);
                                ch->ast = NULL;
                                break;
@@ -4669,16 +5404,16 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        break;
                }
 
-               /* check if we should jump into s when we have no dad */
+               /* check if we should jump into s when we have no dialed.number */
                misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
-               if (im && ast_strlen_zero(bc->dad)) {
+               if (im && ast_strlen_zero(bc->dialed.number)) {
                        do_immediate_setup(bc, ch, chan);
                        break;
                }
 
                chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context);
-               if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
-                       if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
+               if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
+                       if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
                                ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port);
                                strcpy(ch->ast->exten, "i");
                                misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
@@ -4722,7 +5457,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                 * the number is empty, we wait for the ISDN timeout
                 * instead of our own timer.
                 */
-               if (ch->overlap_dial && bc->nt && !bc->dad[0] ) {
+               if (ch->overlap_dial && bc->nt && !bc->dialed.number[0] ) {
                        wait_for_digits(ch, bc, chan);
                        break;
                }
@@ -4747,7 +5482,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                /* If the extension does not exist and we're not TE_PTMP we wait for more digits
                 * without interdigit timeout.
                 * */
-               if (!ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad))  {
+               if (!ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number))  {
                        wait_for_digits(ch, bc, chan);
                        break;
                }
@@ -4755,29 +5490,30 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                /*
                 * If the extension exists let's just jump into it.
                 * */
-               if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
+               if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
                        misdn_lib_send_event(bc, bc->need_more_infos ? EVENT_SETUP_ACKNOWLEDGE : EVENT_PROCEEDING);
                        ch->state = MISDN_DIALING;
                        start_pbx(ch, bc, chan);
                        break;
                }
-       }
                break;
+       }
 
        case EVENT_SETUP_ACKNOWLEDGE:
                ch->state = MISDN_CALLING_ACKNOWLEDGE;
 
-               if (bc->channel)
+               if (bc->channel) {
                        update_name(ch->ast,bc->port,bc->channel);
+               }
 
                if (!ast_strlen_zero(bc->infos_pending)) {
                        /* TX Pending Infos */
-                       strncat(bc->dad, bc->infos_pending, sizeof(bc->dad) - strlen(bc->dad) - 1);
+                       strncat(bc->dialed.number, bc->infos_pending, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
 
                        if (!ch->ast) {
                                break;
                        }
-                       ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
+                       ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
                        ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad));
                        ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending));
 
@@ -4842,29 +5578,31 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                }
                break;
        case EVENT_CONNECT:
-               {
-                       struct ast_channel *bridged;
+       {
+               struct ast_party_connected_line connected;
 
-                       /*we answer when we've got our very new L3 ID from the NT stack */
-                       misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
+               /* we answer when we've got our very new L3 ID from the NT stack */
+               misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
 
-                       if (!ch->ast) {
-                               break;
-                       }
+               if (!ch->ast) {
+                       break;
+               }
 
-                       bridged = ast_bridged_channel(ch->ast);
-                       stop_indicate(ch);
+               stop_indicate(ch);
 
-                       if (bridged && !strcasecmp(bridged->tech->type, "mISDN")) {
-                               struct chan_list *bridged_ch = MISDN_ASTERISK_TECH_PVT(bridged);
+               /* Add configured prefix to connected.number */
+               misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
+
+               /* Update the connected line information on the other channel */
+               ast_party_connected_line_init(&connected);
+               connected.id.number = bc->connected.number;
+               connected.id.number_type = misdn_to_ast_ton(bc->connected.number_type)
+                       | misdn_to_ast_plan(bc->connected.number_plan);
+               connected.id.number_presentation = misdn_to_ast_pres(bc->connected.presentation)
+                       | misdn_to_ast_screen(bc->connected.screening);
+               connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+               ast_channel_queue_connected_line_update(ch->ast, &connected);
 
-                               chan_misdn_log(1, bc->port, " --> copying cpndialplan:%d and cad:%s to the A-Channel\n", bc->cpnnumplan, bc->cad);
-                               if (bridged_ch) {
-                                       bridged_ch->bc->cpnnumplan = bc->cpnnumplan;
-                                       ast_copy_string(bridged_ch->bc->cad, bc->cad, sizeof(bridged_ch->bc->cad));
-                               }
-                       }
-               }
                ch->l3id = bc->l3_id;
                ch->addr = bc->addr;
 
@@ -4874,6 +5612,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 
                ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
                break;
+       }
        case EVENT_CONNECT_ACKNOWLEDGE:
                ch->l3id = bc->l3_id;
                ch->addr = bc->addr;
@@ -4947,8 +5686,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                stop_bc_tones(ch);
                hangup_chan(ch);
 
-               if (ch)
+               if (ch) {
                        ch->state = MISDN_CLEANING;
+               }
 
                release_chan(bc);
                break;
@@ -5003,16 +5743,16 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                } else {
                        bc->tone_cnt = 0;
                }
-       }
                break;
-
+       }
        case EVENT_BCHAN_DATA:
                if (ch->bc->AOCD_need_export) {
                        export_aoc_vars(ch->originator, ch->ast, ch->bc);
                }
                if (!misdn_cap_is_speech(ch->bc->capability)) {
                        struct ast_frame frame;
-                       /*In Data Modes we queue frames*/
+
+                       /* In Data Modes we queue frames */
                        frame.frametype = AST_FRAME_VOICE; /* we have no data frames yet */
                        frame.subclass = AST_FORMAT_ALAW;
                        frame.datalen = bc->bframe_len;
@@ -5023,8 +5763,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        frame.src = NULL;
                        frame.data.ptr = bc->bframe;
 
-                       if (ch->ast)
+                       if (ch->ast) {
                                ast_queue_frame(ch->ast, &frame);
+                       }
                } else {
                        fd_set wrfs;
                        struct timeval tv = { 0, 0 };
@@ -5099,6 +5840,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        break;
                default:
                        misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+                       break;
                }
                break;
 
@@ -5137,8 +5879,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
                        misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
                }
-       }
                break;
+       }
        case EVENT_HOLD:
        {
                int hold_allowed;
@@ -5171,8 +5913,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
                        chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
                }
-       }
                break;
+       }
        case EVENT_FACILITY:
                print_facility(&(bc->fac_in), bc);
 
@@ -5189,7 +5931,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                        ch_br = MISDN_ASTERISK_TECH_PVT(bridged);
                                        /*ch->state = MISDN_FACILITY_DEFLECTED;*/
                                        if (ch_br->bc) {
-                                               if (ast_exists_extension(bridged, ch->context, (char *)bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->oad)) {
+                                               if (ast_exists_extension(bridged, ch->context, (char *) bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->caller.number)) {
                                                        ch_br->state = MISDN_DIALING;
                                                        if (pbx_start_chan(ch_br) < 0) {
                                                                chan_misdn_log(-1, ch_br->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
@@ -5461,6 +6203,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data)
 {
        struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
        char *parse;
+
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(facility_type);
                AST_APP_ARG(arg)[99];
@@ -5473,7 +6216,7 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data)
                return -1;
        }
 
-       if (ast_strlen_zero((char *)data)) {
+       if (ast_strlen_zero((char *) data)) {
                ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
                return -1;
        }
@@ -5492,7 +6235,9 @@ static int misdn_facility_exec(struct ast_channel *chan, void *data)
                }
 
                if (strlen(args.arg[0]) >= sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)) {
-                       ast_log(LOG_WARNING, "Facility: Number argument too long (up to %d digits are allowed). Ignoring.\n", (int)sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
+                       ast_log(LOG_WARNING,
+                               "Facility: Number argument too long (up to %d digits are allowed). Ignoring.\n",
+                               (int) sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
                        return 0;
                }
                ch->bc->fac_out.Function = Fac_CD;
@@ -5516,11 +6261,11 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data)
        int port_up;
 
        AST_DECLARE_APP_ARGS(args,
-                       AST_APP_ARG(grouppar);
-                       AST_APP_ARG(timeout);
+               AST_APP_ARG(grouppar);
+               AST_APP_ARG(timeout);
        );
 
-       if (ast_strlen_zero((char *)data)) {
+       if (ast_strlen_zero((char *) data)) {
                ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n");
                return -1;
        }
@@ -5543,7 +6288,7 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data)
                ast_copy_string(group, port_str, sizeof(group));
                chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group);
 
-               for (   port = misdn_cfg_get_next_port(port);
+               for (port = misdn_cfg_get_next_port(port);
                        port > 0;
                        port = misdn_cfg_get_next_port(port)) {
                        char cfg_group[BUFFERSIZE + 1];
@@ -5554,7 +6299,6 @@ static int misdn_check_l2l1(struct ast_channel *chan, void *data)
 
                        if (!strcasecmp(cfg_group, group)) {
                                port_up = misdn_lib_port_up(port, 1);
-
                                if (!port_up) {
                                        chan_misdn_log(2, 0, " --> port '%d'\n", port);
                                        misdn_lib_get_port_up(port);
@@ -5752,12 +6496,15 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data)
                        chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
                        /* CRICH: callingpres!!! */
                        if (strstr(tok, "allowed")) {
-                               ch->bc->pres = 0;
+                               ch->bc->presentation = 0;
+                               ch->bc->set_presentation = 1;
                        } else if (strstr(tok, "restricted")) {
-                               ch->bc->pres = 1;
+                               ch->bc->presentation = 1;
+                               ch->bc->set_presentation = 1;
                        } else if (strstr(tok, "not_screened")) {
                                chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
-                               ch->bc->pres = 1;
+                               ch->bc->presentation = 1;
+                               ch->bc->set_presentation = 1;
                        }
                        break;
                case 'i' :
@@ -5975,16 +6722,10 @@ int misdn_jb_empty(struct misdn_jb *jb, char *data, int len)
        return read;
 }
 
-
-
-
 /*******************************************************/
 /*************** JITTERBUFFER  END *********************/
 /*******************************************************/
 
-
-
-
 static void chan_misdn_log(int level, int port, char *tmpl, ...)
 {
        va_list ap;
@@ -6005,7 +6746,6 @@ static void chan_misdn_log(int level, int port, char *tmpl, ...)
 
        if (level == -1) {
                ast_log(LOG_WARNING, "%s", buf);
-
        } else if (misdn_debug_only[port] ?
                        (level == 1 && misdn_debug[port]) || (level == misdn_debug[port])
                 : level <= misdn_debug[port]) {
@@ -6021,7 +6761,8 @@ static void chan_misdn_log(int level, int port, char *tmpl, ...)
 
                FILE *fp = fopen(global_tracefile, "a+");
 
-               if ((p = strchr(tmp, '\n'))) {
+               p = strchr(tmp, '\n');
+               if (p) {
                        *p = ':';
                }
 
index 82a37cc..dd1578c 100644 (file)
@@ -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;
 
index 4fb164f..10883c5 100644 (file)
@@ -942,6 +942,54 @@ static const struct cfsip_options {
        { SIP_OPT_TARGET_DIALOG,NOT_SUPPORTED,  "tdialog" },
 };
 
+/*! \brief Diversion header reasons
+ *
+ * The core defines a bunch of constants used to define
+ * redirecting reasons. This provides a translation table
+ * between those and the strings which may be present in
+ * a SIP Diversion header
+ */
+static const struct sip_reasons {
+       enum AST_REDIRECTING_REASON code;
+       char * const text;
+} sip_reason_table[] = {
+       { AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
+       { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
+       { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" },
+       { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable" },
+       { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" },
+       { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" },
+       { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" },
+       { AST_REDIRECTING_REASON_DEFLECTION, "deflection" },
+       { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
+       { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
+       { AST_REDIRECTING_REASON_AWAY, "away" },
+       { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"}
+};
+
+static enum AST_REDIRECTING_REASON sip_reason_str_to_code(const char *text)
+{
+       enum AST_REDIRECTING_REASON ast = AST_REDIRECTING_REASON_UNKNOWN;
+       int i;
+
+       for (i = 0; i < ARRAY_LEN(sip_reason_table); ++i) {
+               if (!strcasecmp(text, sip_reason_table[i].text)) {
+                       ast = sip_reason_table[i].code;
+                       break;
+               }
+       }
+
+       return ast;
+}
+
+static const char *sip_reason_code_to_str(enum AST_REDIRECTING_REASON code)
+{
+       if (code >= 0 && code < ARRAY_LEN(sip_reason_table)) {
+               return sip_reason_table[code].text;
+       }
+
+       return "unknown";
+}
 
 /*! \brief SIP Methods we support 
        \todo This string should be set dynamically. We only support REFER and SUBSCRIBE if we have
@@ -1354,7 +1402,10 @@ struct sip_auth {
 #define SIP_PROG_INBAND_NO     (1 << 25)
 #define SIP_PROG_INBAND_YES    (2 << 25)
 
-#define SIP_SENDRPID           (1 << 29)       /*!< DP: Remote Party-ID Support */
+#define SIP_SENDRPID           (3 << 29)       /*!< DP: Remote Party-ID Support */
+#define SIP_SENDRPID_NO     (0 << 29)
+#define SIP_SENDRPID_PAI    (1 << 29)   /*!< Use "P-Asserted-Identity" for rpid */
+#define SIP_SENDRPID_RPID   (2 << 29)   /*!< Use "Remote-Party-ID" for rpid */
 #define SIP_G726_NONSTANDARD   (1 << 31)       /*!< DP: Use non-standard packing for G726-32 data */
 
 /*! \brief Flags to copy from peer/user to dialog */
@@ -1373,6 +1424,9 @@ struct sip_auth {
 /* Space for addition of other realtime flags in the future */
 #define SIP_PAGE2_STATECHANGEQUEUE     (1 << 9)        /*!< D: Unsent state pending change exists */
 
+#define SIP_PAGE2_CONNECTLINEUPDATE_PEND               (1 << 10)
+#define SIP_PAGE2_RPID_IMMEDIATE                       (1 << 11)
+
 #define SIP_PAGE2_PREFERRED_CODEC      (1 << 13)       /*!< GDP: Only respond with single most preferred joint codec */
 #define SIP_PAGE2_VIDEOSUPPORT         (1 << 14)       /*!< DP: Video supported if offered? */
 #define SIP_PAGE2_TEXTSUPPORT          (1 << 15)       /*!< GDP: Global text enable */
@@ -1403,7 +1457,8 @@ struct sip_auth {
        (SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_IGNORESDPVERSION | \
        SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | \
        SIP_PAGE2_BUGGY_MWI | SIP_PAGE2_TEXTSUPPORT | SIP_PAGE2_FAX_DETECT | \
-       SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC)
+       SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC | \
+       SIP_PAGE2_RPID_IMMEDIATE)
 
 /*@}*/ 
 
@@ -1611,8 +1666,6 @@ struct sip_pvt {
                AST_STRING_FIELD(fullcontact);  /*!< The Contact: that the UA registers with us */
                        /* we only store the part in <brackets> in this field. */
                AST_STRING_FIELD(our_contact);  /*!< Our contact header */
-               AST_STRING_FIELD(rpid);         /*!< Our RPID header */
-               AST_STRING_FIELD(rpid_from);    /*!< Our RPID From header */
                AST_STRING_FIELD(url);          /*!< URL to be sent with next message to peer */
                AST_STRING_FIELD(parkinglot);           /*!< Parkinglot */
                AST_STRING_FIELD(engine);       /*!< RTP engine to use */
@@ -2237,7 +2290,7 @@ static int transmit_response_using_temp(ast_string_field callid, struct sockaddr
 static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
 static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req);
 static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req);
-static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp);
+static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid);
 static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
 static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
 static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
@@ -2258,7 +2311,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty
 static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
 static void copy_request(struct sip_request *dst, const struct sip_request *src);
 static void receive_message(struct sip_pvt *p, struct sip_request *req);
-static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req);
+static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward);
 static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only);
 
 /*--- Dialog management */
@@ -2506,11 +2559,14 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
 static int set_address_from_contact(struct sip_pvt *pvt);
 static void check_via(struct sip_pvt *p, struct sip_request *req);
 static char *get_calleridname(const char *input, char *output, size_t outputsize);
-static int get_rpid_num(const char *input, char *output, int maxlen);
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq);
+static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
 static int get_destination(struct sip_pvt *p, struct sip_request *oreq);
 static int get_msg_text(char *buf, int len, struct sip_request *req, int addnewline);
 static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
+static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
+static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen);
+static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward);
 
 /*-- TCP connection handling ---*/
 static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session);
@@ -2537,6 +2593,7 @@ static int add_header_contentLength(struct sip_request *req, int len);
 static int add_line(struct sip_request *req, const char *line);
 static int add_text(struct sip_request *req, const char *text);
 static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
+static int add_rpid(struct sip_request *req, struct sip_pvt *p);
 static int add_vidupdate(struct sip_request *req);
 static void add_route(struct sip_request *req, struct sip_route *route);
 static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
@@ -2545,7 +2602,6 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st
 static void set_destination(struct sip_pvt *p, char *uri);
 static void append_date(struct sip_request *req);
 static void build_contact(struct sip_pvt *p);
-static void build_rpid(struct sip_pvt *p);
 
 /*------Request handling functions */
 static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock);
@@ -4808,6 +4864,8 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
        ast_string_field_set(dialog, tohost, peer->tohost);
        ast_string_field_set(dialog, fullcontact, peer->fullcontact);
        ast_string_field_set(dialog, context, peer->context);
+       ast_string_field_set(dialog, cid_num, peer->cid_num);
+       ast_string_field_set(dialog, cid_name, peer->cid_name);
        ast_string_field_set(dialog, parkinglot, peer->parkinglot);
        ast_string_field_set(dialog, engine, peer->engine);
        ref_proxy(dialog, obproxy_get(dialog, peer));
@@ -5072,11 +5130,13 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
                p->t38.jointcapability = p->t38.capability;
                ast_debug(2, "Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
 
+               sip_pvt_lock(p);
                xmitres = transmit_invite(p, SIP_INVITE, 1, 2);
+               sip_pvt_unlock(p);
                if (xmitres == XMIT_ERROR)
                        return -1;
                p->invitestate = INV_CALLING;
-       
+
                /* Initialize auto-congest time */
                AST_SCHED_REPLACE_UNREF(p->initid, sched, p->timer_b, auto_congest, p, 
                                                                dialog_unref(_data, "dialog ptr dec when SCHED_REPLACE del op succeeded"), 
@@ -5810,7 +5870,7 @@ static int sip_answer(struct ast_channel *ast)
                        change_t38_state(p, T38_ENABLED);
                }
                ast_rtp_instance_new_source(p->rtp);
-               res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE);
+               res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE, TRUE);
                ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
        }
        sip_pvt_unlock(p);
@@ -5846,8 +5906,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
                                    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
                                        ast_rtp_instance_new_source(p->rtp);
                                        p->invitestate = INV_EARLY_MEDIA;
-                                       transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
-                                       ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);  
+                                       transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
+                                       ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
                                } else if (p->t38.state == T38_ENABLED && !p->t38.direct) {
                                        change_t38_state(p, T38_DISABLED);
                                        transmit_reinvite_with_sdp(p, FALSE, FALSE);
@@ -5868,8 +5928,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
                                    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
                                    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
                                        p->invitestate = INV_EARLY_MEDIA;
-                                       transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
-                                       ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);  
+                                       transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
+                                       ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
                                }
                                p->lastrtptx = time(NULL);
                                res = ast_rtp_instance_write(p->vrtp, frame);
@@ -5889,8 +5949,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
                                            !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
                                            !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
                                                p->invitestate = INV_EARLY_MEDIA;
-                                               transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
-                                               ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);  
+                                               transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
+                                               ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
                                        }
                                        p->lastrtptx = time(NULL);
                                        res = ast_rtp_instance_write(p->trtp, frame);
@@ -6109,8 +6169,8 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
                    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
                    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
                        p->invitestate = INV_EARLY_MEDIA;
-                       transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
-                       ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);  
+                       transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
+                       ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
                        break;
                }
                res = -1;
@@ -6168,6 +6228,12 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
        case AST_CONTROL_SRCUPDATE:
                ast_rtp_instance_new_source(p->rtp);
                break;
+       case AST_CONTROL_CONNECTED_LINE:
+               update_connectedline(p, data, datalen);
+               break;
+       case AST_CONTROL_REDIRECTING:
+               update_redirecting(p, data, datalen);
+               break;
        case -1:
                res = -1;
                break;
@@ -8709,9 +8775,6 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, in
        if (!ast_strlen_zero(global_useragent))
                add_header(req, "User-Agent", global_useragent);
 
-       if (!ast_strlen_zero(p->rpid))
-               add_header(req, "Remote-Party-ID", p->rpid);
-
        if (!ast_strlen_zero(p->url)) {
                add_header(req, "Access-URL", p->url);
                ast_string_field_set(p, url, NULL);
@@ -8749,6 +8812,14 @@ static int __transmit_response(struct sip_pvt *p, const char *msg, const struct
                return -1;
        }
        respprep(&resp, p, msg, req);
+
+       if (ast_test_flag(&p->flags[0], SIP_SENDRPID)
+                       && ast_test_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND)
+                       && (!strncmp(msg, "180", 3) || !strncmp(msg, "183", 3))) {
+               ast_clear_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND);
+               add_rpid(&resp, p);
+       }
+
        add_header_contentLength(&resp, 0);
        /* If we are cancelling an incoming invite for some reason, add information
                about the reason why we are doing this in clear text */
@@ -8968,6 +9039,89 @@ static int add_digit(struct sip_request *req, char digit, unsigned int duration,
        return 0;
 }
 
+/*!
+ * \pre if p->owner exists, it must be locked
+ * \brief Add Remote-Party-ID header to SIP message 
+ */
+static int add_rpid(struct sip_request *req, struct sip_pvt *p)
+{
+       struct ast_str *tmp = ast_str_alloca(256);
+       char *lid_num = NULL;
+       char *lid_name = NULL;
+       int lid_pres;
+       const char *fromdomain;
+       const char *privacy = NULL;
+       const char *screen = NULL;
+       const char *anonymous_string = "\"Anonymous\" <anonymous@anonymous.invalid>";
+
+       if (!ast_test_flag(&p->flags[0], SIP_SENDRPID)) {
+               return 0;
+       }
+
+       if (p->owner && p->owner->connected.id.number)
+               lid_num = p->owner->connected.id.number;
+       if (p->owner && p->owner->connected.id.name)
+               lid_name = p->owner->connected.id.name;
+       lid_pres = (p->owner) ? p->owner->connected.id.number_presentation : AST_PRES_NUMBER_NOT_AVAILABLE;
+
+       if (ast_strlen_zero(lid_num))
+               return 0;
+       if (ast_strlen_zero(lid_name))
+               lid_name = lid_num;
+       fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr));
+
+       if (ast_test_flag(&p->flags[0], SIP_SENDRPID_PAI)) {
+               if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) {
+                       ast_str_set(&tmp, -1, "%s", anonymous_string);
+               } else {
+                       ast_str_set(&tmp, -1, "\"%s\" <sip:%s@%s>", lid_name, lid_num, fromdomain);
+               }
+               add_header(req, "P-Asserted-Identity", ast_str_buffer(tmp));
+       } else {
+               ast_str_set(&tmp, -1, "\"%s\" <sip:%s@%s>;party=%s", lid_name, lid_num, fromdomain, ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "calling" : "called");
+
+               switch (lid_pres) {
+               case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
+               case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
+                       privacy = "off";
+                       screen = "no";
+                       break;
+               case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
+               case AST_PRES_ALLOWED_NETWORK_NUMBER:
+                       privacy = "off";
+                       screen = "yes";
+                       break;
+               case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
+               case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
+                       privacy = "full";
+                       screen = "no";
+                       break;
+               case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
+               case AST_PRES_PROHIB_NETWORK_NUMBER:
+                       privacy = "full";
+                       screen = "yes";
+                       break;
+               case AST_PRES_NUMBER_NOT_AVAILABLE:
+                       break;
+               default:
+                       if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) {
+                               privacy = "full";
+                       }
+                       else
+                               privacy = "off";
+                       screen = "no";
+                       break;
+               }
+
+               if (!ast_strlen_zero(privacy) && !ast_strlen_zero(screen)) {
+                       ast_str_append(&tmp, -1, ";privacy=%s;screen=%s", privacy, screen);
+               }
+
+               add_header(req, "Remote-Party-ID", ast_str_buffer(tmp));
+       }
+       return 0;
+}
+
 /*! \brief add XML encoded media control with update 
        \note XML: The only way to turn 0 bits of information into a few hundred. (markster) */
 static int add_vidupdate(struct sip_request *req)
@@ -9581,7 +9735,7 @@ static void copy_request(struct sip_request *dst, const struct sip_request *src)
 /*! \brief Used for 200 OK and 183 early media 
        \return Will return XMIT_ERROR for network errors.
 */
-static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp)
+static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid)
 {
        struct sip_request resp;
        int seqno;
@@ -9590,6 +9744,9 @@ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const
                return -1;
        }
        respprep(&resp, p, msg, req);
+       if (rpid == TRUE) {
+               add_rpid(&resp, p);
+       }
        if (p->rtp) {
                if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
                        ast_debug(1, "Setting framing from config on incoming call\n");
@@ -9739,85 +9896,6 @@ static void build_contact(struct sip_pvt *p)
        }
 }
 
-/*! \brief Build the Remote Party-ID & From using callingpres options */
-static void build_rpid(struct sip_pvt *p)
-{
-       int send_pres_tags = TRUE;
-       const char *privacy=NULL;
-       const char *screen=NULL;
-       char buf[256];
-       const char *clid = default_callerid;
-       const char *clin = NULL;
-       const char *fromdomain;
-
-       if (!ast_strlen_zero(p->rpid) || !ast_strlen_zero(p->rpid_from))  
-               return;
-
-       if (p->owner && p->owner->cid.cid_num)
-               clid = p->owner->cid.cid_num;
-       if (p->owner && p->owner->cid.cid_name)
-               clin = p->owner->cid.cid_name;
-       if (ast_strlen_zero(clin))
-               clin = clid;
-
-       switch (p->callingpres) {
-       case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
-               privacy = "off";
-               screen = "no";
-               break;
-       case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
-               privacy = "off";
-               screen = "yes";
-               break;
-       case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
-               privacy = "off";
-               screen = "no";
-               break;
-       case AST_PRES_ALLOWED_NETWORK_NUMBER:
-               privacy = "off";
-               screen = "yes";
-               break;
-       case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
-               privacy = "full";
-               screen = "no";
-               break;
-       case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
-               privacy = "full";
-               screen = "yes";
-               break;
-       case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
-               privacy = "full";
-               screen = "no";
-               break;
-       case AST_PRES_PROHIB_NETWORK_NUMBER:
-               privacy = "full";
-               screen = "yes";
-               break;
-       case AST_PRES_NUMBER_NOT_AVAILABLE:
-               send_pres_tags = FALSE;
-               break;
-       default:
-               ast_log(LOG_WARNING, "Unsupported callingpres (%d)\n", p->callingpres);
-               if ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)
-                       privacy = "full";
-               else
-                       privacy = "off";
-               screen = "no";
-               break;
-       }
-       
-       fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr));
-
-       snprintf(buf, sizeof(buf), "\"%s\" <sip:%s@%s>", clin, clid, fromdomain);
-       if (send_pres_tags)
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";privacy=%s;screen=%s", privacy, screen);
-       ast_string_field_set(p, rpid, buf);
-
-       ast_string_field_build(p, rpid_from, "\"%s\" <sip:%s@%s>;tag=%s", clin,
-                              S_OR(p->fromuser, clid),
-                              fromdomain, p->tag);
-}
-
 /*! \brief Initiate new SIP request to peer/user */
 static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod)
 {
@@ -9853,15 +9931,9 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
 
        snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text);
 
-       if (p->owner) {
-               l = p->owner->cid.cid_num;
-               n = p->owner->cid.cid_name;
-       }
-       /* if we are not sending RPID and user wants his callerid restricted */
-       if (!ast_test_flag(&p->flags[0], SIP_SENDRPID) &&
-           ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)) {
-               l = CALLERID_UNKNOWN;
-               n = l;
+       if (p->owner && (p->owner->connected.id.number_presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
+               l = p->owner->connected.id.number; 
+               n = p->owner->connected.id.name;
        }
        if (ast_strlen_zero(l))
                l = default_callerid;
@@ -9950,12 +10022,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
        /* SLD: FIXME?: do Route: here too?  I think not cos this is the first request.
         * OTOH, then we won't have anything in p->route anyway */
 
-       /* Build Remote Party-ID and From */
-       if (ast_test_flag(&p->flags[0], SIP_SENDRPID) && (sipmethod == SIP_INVITE)) {
-               build_rpid(p);
-               add_header(req, "From", p->rpid_from);
-       } else 
-               add_header(req, "From", from);
+       add_header(req, "From", from);
        add_header(req, "To", to);
        ast_string_field_set(p, exten, l);
        build_contact(p);
@@ -9964,8 +10031,44 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
        add_header(req, "CSeq", tmp_n);
        if (!ast_strlen_zero(global_useragent))
                add_header(req, "User-Agent", global_useragent);
-       if (!ast_strlen_zero(p->rpid))
-               add_header(req, "Remote-Party-ID", p->rpid);
+}
+
+/*! \brief Add "Diversion" header to outgoing message
+ *
+ * We need to add a Diversion header if the owner channel of
+ * this dialog has redirecting information associated with it.
+ *
+ * \param req The request/response to which we will add the header
+ * \param pvt The sip_pvt which represents the call-leg
+ * \param apr Redirecting data used to make the diversion header
+ */
+static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt)
+{
+       const char *diverting_number;
+       const char *diverting_name;
+       const char *reason;
+       char header_text[256];
+
+       if (!pvt->owner) {
+               return;
+       }
+
+       diverting_number = pvt->owner->cid.cid_rdnis;
+       diverting_name = pvt->owner->redirecting.from.name;
+       reason = sip_reason_code_to_str(pvt->owner->redirecting.reason);
+
+       if (ast_strlen_zero(diverting_number)) {
+               return;
+       }
+
+       /* We at least have a number to place in the Diversion header, which is enough */
+       if (ast_strlen_zero(diverting_name)) {
+               snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason);
+       } else {
+               snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s", diverting_name, diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason);
+       }
+
+       add_header(req, "Diversion", header_text);
 }
 
 /*! \brief Build REFER/INVITE/OPTIONS/SUBSCRIBE message and transmit it 
@@ -10086,6 +10189,11 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
 
                ast_channel_unlock(chan);
        }
+       if ((sipmethod == SIP_INVITE || sipmethod == SIP_UPDATE) && ast_test_flag(&p->flags[0], SIP_SENDRPID))
+               add_rpid(&req, p);
+       if (sipmethod == SIP_INVITE) {
+               add_diversion_header(&req, p);
+       }
        if (sdp) {
                if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
                        ast_udptl_offered_from_local(p->udptl, 1);
@@ -10568,6 +10676,80 @@ static char mandescr_sipnotify[] =
 "  *Variable: <name>=<value>  At least one variable pair must be specified.\n"
 "  ActionID: <id>             Action ID for this transaction. Will be returned.\n";
 
+/*! \brief Send a provisional response indicating that a call was redirected
+ */
+static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen)
+{
+       struct sip_request resp;
+
+       if (p->owner->_state == AST_STATE_UP || ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+               return;
+       }
+
+       if (!ast_strlen_zero(p->owner->redirecting.to.number)) {
+               ast_string_field_set(p, exten, p->owner->redirecting.to.number);
+               build_contact(p);
+       }
+       respprep(&resp, p, "181 Call is being forwarded", &p->initreq);
+       add_diversion_header(&resp, p);
+       send_response(p, &resp, XMIT_UNRELIABLE, 0);
+}
+
+/*! \brief Notify peer that the connected line has changed */
+static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen)
+{
+
+       if (!ast_test_flag(&p->flags[0], SIP_SENDRPID))
+               return;
+       if (ast_strlen_zero(p->owner->connected.id.number))
+               return;
+
+       append_history(p, "ConnectedLine", "%s party is now %s <%s>", ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "Calling" : "Called", p->owner->connected.id.name, p->owner->connected.id.number);
+
+       if (p->owner->_state == AST_STATE_UP || ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+               struct sip_request req;
+
+               if (p->invitestate == INV_CONFIRMED || p->invitestate == INV_TERMINATED) {
+                       reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1);
+
+                       add_header(&req, "Allow", ALLOWED_METHODS);
+                       add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+                       add_rpid(&req, p);
+                       add_sdp(&req, p, FALSE, TRUE, FALSE);
+
+                       initialize_initreq(p, &req);
+                       p->lastinvite = p->ocseq;
+                       ast_set_flag(&p->flags[0], SIP_OUTGOING);
+                       send_request(p, &req, XMIT_CRITICAL, p->ocseq);
+               } else {
+                       reqprep(&req, p, SIP_UPDATE, 0, 1);
+                       add_rpid(&req, p);
+                       add_header_contentLength(&req, 0);
+                       send_request(p, &req, XMIT_CRITICAL, p->ocseq);
+               }
+       } else {
+               if (ast_test_flag(&p->flags[1], SIP_PAGE2_RPID_IMMEDIATE)) {
+                       struct sip_request resp;
+                       if ((p->owner->_state == AST_STATE_RING) && !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT)) {
+                               respprep(&resp, p, "180 Ringing", &p->initreq);
+                               add_rpid(&resp, p);
+                               send_response(p, &resp, XMIT_UNRELIABLE, 0);
+                               ast_set_flag(&p->flags[0], SIP_RINGING);
+                       } else if (p->owner->_state == AST_STATE_RINGING) {
+                               respprep(&resp, p, "183 Session Progress", &p->initreq);
+                               add_rpid(&resp, p);
+                               send_response(p, &resp, XMIT_UNRELIABLE, 0);
+                               ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
+                       } else {
+                               ast_log(LOG_DEBUG, "Unable able to send update to '%s' in state '%s'\n", p->owner->name, ast_state2str(p->owner->_state));
+                       }
+               } else {
+                       ast_set_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND);
+               }
+       }
+}
+
 static const struct _map_x_s regstatestrings[] = {
        { REG_STATE_FAILED,     "Failed" },
        { REG_STATE_UNREGISTERED, "Unregistered"},
@@ -10595,7 +10777,7 @@ static const char *regstate2str(enum sipregistrystate regstate)
 static int sip_reregister(const void *data) 
 {
        /* if we are here, we know that we need to reregister. */
-       struct sip_registry *r= (struct sip_registry *) data;
+       struct sip_registry *r = (struct sip_registry *) data;
 
        /* if we couldn't get a reference to the registry object, punt */
        if (!r)
@@ -12260,23 +12442,199 @@ static void sip_set_redirstr(struct sip_pvt *p, char *reason) {
        }
 }
 
+/*! \brief Parse the parts of the P-Asserted-Identity header
+ * on an incoming packet. Returns 1 if a valid header is found
+ * and it is different from the current caller id.
+ */
+static int get_pai(struct sip_pvt *p, struct sip_request *req)
+{
+       char pai[256];
+       char privacy[64];
+       char *cid_num = "";
+       char *cid_name = "";
+       int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+       char *start = NULL, *end = NULL;
+
+       ast_copy_string(pai, get_header(req, "P-Asserted-Identity"), sizeof(pai));
+
+       if (ast_strlen_zero(pai)) {
+               return 0;
+       }
+
+       start = pai;
+       if (*start == '"') {
+               *start++ = '\0';
+               end = strchr(start, '"');
+               if (!end)
+                       return 0;
+               *end++ = '\0';
+               cid_name = start;
+               start = ast_skip_blanks(end);
+       }
+
+       if (*start != '<')
+               return 0;
+       *start++ = '\0';
+       end = strchr(start, '@');
+       if (!end)
+               return 0;
+       *end++ = '\0';
+       if (!strncasecmp(start, "anonymous@anonymous.invalid", 27)) {
+               callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+               /*XXX Assume no change in cid_num. Perhaps it should be 
+                * blanked?
+                */
+               cid_num = (char *)p->cid_num;
+       } else if (!strncasecmp(start, "sip:", 4)) {
+               cid_num = start + 4;
+               if (ast_is_shrinkable_phonenumber(cid_num))
+                       ast_shrink_phone_number(cid_num);
+               start = end;
+
+               end = strchr(start, '>');
+               if (!end)
+                       return 0;
+               *end = '\0';
+       } else {
+               return 0;
+       }
+
+       ast_copy_string(privacy, get_header(req, "Privacy"), sizeof(privacy));
+       if (!ast_strlen_zero(privacy) && strncmp(privacy, "id", 2)) {
+               callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+       }
+
+       /* Only return true if the supplied caller id is different */
+       if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres)
+               return 0;
+
+       ast_string_field_set(p, cid_num, cid_num);
+       ast_string_field_set(p, cid_name, cid_name);
+       p->callingpres = callingpres;
+
+       if (p->owner) {
+               ast_set_callerid(p->owner, cid_num, cid_name, NULL);
+               p->owner->cid.cid_pres = callingpres;
+       }
+
+       return 1;
+}
+
+/*! \brief Get name, number and presentation from remote party id header, 
+ *  returns true if a valid header was found and it was different from the
+ *  current caller id.
+ */
+static int get_rpid(struct sip_pvt *p, struct sip_request *oreq)
+{
+       char tmp[256];
+       struct sip_request *req;
+       char *cid_num = "";
+       char *cid_name = "";
+       int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+       char *privacy = "";
+       char *screen = "";
+       char *start, *end;
+
+       if (!ast_test_flag(&p->flags[0], SIP_TRUSTRPID))
+               return 0;
+       req = oreq;
+       if (!req)
+               req = &p->initreq;
+       ast_copy_string(tmp, get_header(req, "Remote-Party-ID"), sizeof(tmp));
+       if (ast_strlen_zero(tmp)) {
+               return get_pai(p, req);
+       }
+
+       start = tmp;
+       if (*start == '"') {
+               *start++ = '\0';
+               end = strchr(start, '"');
+               if (!end)
+                       return 0;
+               *end++ = '\0';
+               cid_name = start;
+               start = ast_skip_blanks(end);
+       }
+
+       if (*start != '<')
+               return 0;
+       *start++ = '\0';
+       end = strchr(start, '@');
+       if (!end)
+               return 0;
+       *end++ = '\0';
+       if (strncasecmp(start, "sip:", 4))
+               return 0;
+       cid_num = start + 4;
+       if (ast_is_shrinkable_phonenumber(cid_num))
+               ast_shrink_phone_number(cid_num);
+       start = end;
+
+       end = strchr(start, '>');
+       if (!end)
+               return 0;
+       *end++ = '\0';
+       if (*end) {
+               start = end;
+               if (*start != ';')
+                       return 0;
+               *start++ = '\0';
+               while (!ast_strlen_zero(start)) {
+                       end = strchr(start, ';');
+                       if (end)
+                               *end++ = '\0';
+                       if (!strncasecmp(start, "privacy=", 8))
+                               privacy = start + 8;
+                       else if (!strncasecmp(start, "screen=", 7))
+                               screen = start + 7;
+                       start = end;
+               }
+
+               if (!strcasecmp(privacy, "full")) {
+                       if (!strcasecmp(screen, "yes"))
+                               callingpres = AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
+                       else if (!strcasecmp(screen, "no"))
+                               callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+               } else {
+                       if (!strcasecmp(screen, "yes"))
+                               callingpres = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
+                       else if (!strcasecmp(screen, "no"))
+                               callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+               }
+       }
+
+       /* Only return true if the supplied caller id is different */
+       if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres)
+               return 0;
+
+       ast_string_field_set(p, cid_num, cid_num);
+       ast_string_field_set(p, cid_name, cid_name);
+       p->callingpres = callingpres;
+
+       if (p->owner) {
+               ast_set_callerid(p->owner, cid_num, cid_name, NULL);
+               p->owner->cid.cid_pres = callingpres;
+       }
+
+       return 1;
+}
+
 /*! \brief Get referring dnis */
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq)
+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason)
 {
-       char tmp[256], *exten, *rexten, *rdomain;
-       char *params, *reason = NULL;
+       char tmp[256], *exten, *rexten, *rdomain, *rname = NULL;
+       char *params, *reason_param = NULL;
        struct sip_request *req;
-       
+
        req = oreq ? oreq : &p->initreq;
 
        ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp));
        if (ast_strlen_zero(tmp))
-               return 0;
+               return -1;
 
-       /*! \todo This function does not take user-parameters into consideration.
-               First look for @, then start looking for ; to find uri-parameters.
-       */
-       params = strchr(tmp, ';');
+       if ((params = strchr(tmp, '>'))) {
+               params = strchr(params, ';');
+       }
 
        exten = get_in_brackets(tmp);
        if (!strncasecmp(exten, "sip:", 4)) {
@@ -12295,16 +12653,16 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq)
                while (*params == ';' || *params == ' ')
                        params++;
                /* Check if we have a reason parameter */
-               if ((reason = strcasestr(params, "reason="))) {
-                       reason+=7;
+               if ((reason_param = strcasestr(params, "reason="))) {
+                       reason_param+=7;
                        /* Remove enclosing double-quotes */
-                       if (*reason == '"') 
-                               ast_strip_quoted(reason, "\"", "\"");
-                       if (!ast_strlen_zero(reason)) {
-                               sip_set_redirstr(p, reason);
+                       if (*reason_param == '"')
+                               ast_strip_quoted(reason_param, "\"", "\"");
+                       if (!ast_strlen_zero(reason_param)) {
+                               sip_set_redirstr(p, reason_param);
                                if (p->owner) {
                                        pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause);
-                                       pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason);
+                                       pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason_param);
                                }
                        }
                }
@@ -12312,13 +12670,32 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq)
 
        rdomain = exten;
        rexten = strsep(&rdomain, "@"); /* trim anything after @ */
-       if (p->owner) 
+       if (p->owner)
                pbx_builtin_setvar_helper(p->owner, "__SIPRDNISDOMAIN", rdomain);
 
        if (sip_debug_test_pvt(p))
-               ast_verbose("RDNIS for this call is is %s (reason %s)\n", exten, reason ? reason : "");
+               ast_verbose("RDNIS for this call is %s (reason %s)\n", exten, reason ? reason_param : "");
+
+       /*ast_string_field_set(p, rdnis, rexten);*/
+
+       if (*tmp == '\"') {
+               char *end_quote;
+               rname = tmp + 1;
+               end_quote = strchr(rname, '\"');
+               *end_quote = '\0';
+       }
 
-       ast_string_field_set(p, rdnis, rexten);
+       if (number) {
+               *number = ast_strdup(rexten);
+       }
+
+       if (name && rname) {
+               *name = ast_strdup(rname);
+       }
+
+       if (reason && !ast_strlen_zero(reason_param)) {
+               *reason = sip_reason_str_to_code(reason_param);
+       }
 
        return 0;
 }
@@ -12931,58 +13308,12 @@ static char *get_calleridname(const char *input, char *output, size_t outputsize
        return output;
 }
 
-/*! \brief  Get caller id number from Remote-Party-ID header field 
- *     Returns true if number should be restricted (privacy setting found)
- *     output is set to NULL if no number found
- */
-static int get_rpid_num(const char *input, char *output, int maxlen)
-{
-       char *start;
-       char *end;
-
-       start = strchr(input, ':');
-       if (!start) {
-               output[0] = '\0';
-               return 0;
-       }
-       start++;
-
-       /* we found "number" */
-       ast_copy_string(output, start, maxlen);
-       output[maxlen-1] = '\0';
-
-       end = strchr(output, '@');
-       if (end)
-               *end = '\0';
-       else
-               output[0] = '\0';
-       if (strstr(input, "privacy=full") || strstr(input, "privacy=uri"))
-               return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
-
-       return 0;
-}
-
-
-/*! \brief helper function for check_{user|peer}_ok() */
-static void replace_cid(struct sip_pvt *p, const char *rpid_num, const char *calleridname)
-{
-       /* replace callerid if rpid found, and not restricted */
-       if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
-               char *tmp = ast_strdupa(rpid_num); /* XXX the copy can be done later */
-               if (!ast_strlen_zero(calleridname))
-                       ast_string_field_set(p, cid_name, calleridname);
-               if (ast_is_shrinkable_phonenumber(tmp))
-                       ast_shrink_phone_number(tmp);
-               ast_string_field_set(p, cid_num, tmp);
-       }
-}
 
 /*! \brief Validate device authentication */
 static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
        struct sip_request *req, int sipmethod, struct sockaddr_in *sin,
        struct sip_peer **authpeer,
-       enum xmittype reliable,
-       char *rpid_num, char *calleridname, char *uri2)
+       enum xmittype reliable, char *calleridname, char *uri2)
 {
        enum check_auth_result res;
        int debug=sip_debug_test_addr(sin);
@@ -13030,7 +13361,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
        if (p->sipoptions)
                peer->sipoptions = p->sipoptions;
 
-       replace_cid(p, rpid_num, calleridname);
        do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE));
 
        ast_string_field_set(p, peersecret, peer->secret);
@@ -13083,14 +13413,18 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
                        /* XXX this takes the name from the caller... can we override ? */
                        ast_string_field_set(p, authname, peer->username);
                }
-               if (!ast_strlen_zero(peer->cid_num)) {
-                       char *tmp = ast_strdupa(peer->cid_num);
-                       if (ast_is_shrinkable_phonenumber(tmp))
-                               ast_shrink_phone_number(tmp);
-                       ast_string_field_set(p, cid_num, tmp);
+               if (!get_rpid(p, req)) {
+                       if (!ast_strlen_zero(peer->cid_num)) {
+                               char *tmp = ast_strdupa(peer->cid_num);
+                               if (ast_is_shrinkable_phonenumber(tmp))
+                                       ast_shrink_phone_number(tmp);
+                               ast_string_field_set(p, cid_num, tmp);
+                       }
+                       if (!ast_strlen_zero(peer->cid_name))
+                               ast_string_field_set(p, cid_name, peer->cid_name);
+                       if (peer->callingpres)
+                               p->callingpres = peer->callingpres;
                }
-               if (!ast_strlen_zero(peer->cid_name)) 
-                       ast_string_field_set(p, cid_name, peer->cid_name);
                ast_string_field_set(p, fullcontact, peer->fullcontact);
                if (!ast_strlen_zero(peer->context))
                        ast_string_field_set(p, context, peer->context);
@@ -13140,8 +13474,6 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
        char *dummy;    /* dummy return value for parse_uri */
        char *domain;   /* dummy return value for parse_uri */
        char *of, *of2;
-       char rpid_num[50];
-       const char *rpid;
        enum check_auth_result res;
        char calleridname[50];
        char *uri2 = ast_strdupa(uri);
@@ -13157,11 +13489,6 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
        if (calleridname[0])
                ast_string_field_set(p, cid_name, calleridname);
 
-       rpid = get_header(req, "Remote-Party-ID");
-       memset(rpid_num, 0, sizeof(rpid_num));
-       if (!ast_strlen_zero(rpid)) 
-               p->callingpres = get_rpid_num(rpid, rpid_num, sizeof(rpid_num));
-
        of = get_in_brackets(from);
        if (ast_strlen_zero(p->exten)) {
                char *t = uri2;
@@ -13235,13 +13562,13 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
        }
 
        res = check_peer_ok(p, of, req, sipmethod, sin,
-                       authpeer, reliable, rpid_num, calleridname, uri2);
+                       authpeer, reliable, calleridname, uri2);
        if (res != AUTH_DONT_KNOW)
                return res;
 
        /* Finally, apply the guest policy */
        if (sip_cfg.allowguest) {
-               replace_cid(p, rpid_num, calleridname);
+               get_rpid(p, req);
                if (!dialog_initialize_rtp(p)) {
                        res = AUTH_SUCCESSFUL;
                } else {
@@ -16483,29 +16810,150 @@ static struct ast_custom_function sipchaninfo_function = {
        .read = function_sipchaninfo_read,
 };
 
+static int read_to_parts(struct sip_pvt *p, struct sip_request *req, char **name, char **number)
+{
+
+       char to_header[256];
+       char *to_name = NULL;
+       char *to_number = NULL;
+       char *separator;
+
+       ast_copy_string(to_header, get_header(req, "To"), sizeof(to_header));
+
+       /* Let's get that number first! */
+       to_number = get_in_brackets(to_header);
+
+       if (!strncasecmp(to_number, "sip:", 4)) {
+               to_number += 4;
+       } else if (!strncasecmp(to_number, "sips:", 5)) {
+               to_number += 5;
+       } else {
+               ast_log(LOG_WARNING, "Not a SIP URI? (%s)!\n", to_number);
+               return -1;
+       }
+
+       /* Remove the host and such since we just want the number */
+       if ((separator = strchr(to_number, '@'))) {
+               *separator = '\0';
+       }
+
+       /* We have the number. Let's get the name now. */
+
+       if (*to_header == '\"') {
+               to_name = to_header + 1;
+               if (!(separator = (char *)find_closing_quote(to_name, NULL))) {
+                       ast_log(LOG_NOTICE, "No closing quote in name section of To: header (%s)\n", to_header);
+                       return -1;
+               }
+               *separator = '\0';
+       }
+
+       if (number) {
+               *number = ast_strdup(to_number);
+       }
+       if (name && !ast_strlen_zero(to_name)) {
+               *name = ast_strdup(to_name);
+       }
+
+       return 0;
+}
+
+/*! \brief update redirecting information for a channel based on headers
+ *
+ */
+static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward)
+{
+       char *redirecting_from_name = NULL;
+       char *redirecting_from_number = NULL;
+       char *redirecting_to_name = NULL;
+       char *redirecting_to_number = NULL;
+       int reason = AST_REDIRECTING_REASON_UNCONDITIONAL;
+       int is_response = req->method == SIP_RESPONSE;
+       int res = 0;
+
+       res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason);
+       if (res == -1) {
+               if (is_response) {
+                       read_to_parts(p, req, &redirecting_from_name, &redirecting_from_number);
+               } else {
+                       return;
+               }
+       }
+
+       /* At this point, all redirecting "from" info should be filled in appropriately
+        * on to the "to" info
+        */
+
+       if (is_response) {
+               parse_moved_contact(p, req, &redirecting_to_name, &redirecting_to_number, set_call_forward);
+       } else {
+               read_to_parts(p, req, &redirecting_to_name, &redirecting_to_number);
+       }
+
+       if (!ast_strlen_zero(redirecting_from_number)) {
+               if (redirecting->from.number) {
+                       ast_free(redirecting->from.number);
+               }
+               ast_debug(3, "Got redirecting from number %s\n", redirecting_from_number);
+               redirecting->from.number = redirecting_from_number;
+       }
+       if (!ast_strlen_zero(redirecting_from_name)) {
+               if (redirecting->from.name) {
+                       ast_free(redirecting->from.name);
+               }
+               ast_debug(3, "Got redirecting from name %s\n", redirecting_from_name);
+               redirecting->from.name = redirecting_from_name;
+       }
+       if (!ast_strlen_zero(redirecting_to_number)) {
+               if (redirecting->to.number) {
+                       ast_free(redirecting->to.number);
+               }
+               ast_debug(3, "Got redirecting to number %s\n", redirecting_to_number);
+               redirecting->to.number = redirecting_to_number;
+       }
+       if (!ast_strlen_zero(redirecting_to_name)) {
+               if (redirecting->to.name) {
+                       ast_free(redirecting->to.name);
+               }
+               ast_debug(3, "Got redirecting to name %s\n", redirecting_from_number);
+               redirecting->to.name = redirecting_to_name;
+       }
+       redirecting->reason = reason;
+}
+
 /*! \brief Parse 302 Moved temporalily response 
        \todo XXX Doesn't redirect over TLS on sips: uri's.
                If we get a redirect to a SIPS: uri, this needs to be going back to the
                dialplan (this is a request for a secure signalling path).
                Note that transport=tls is deprecated, but we need to support it on incoming requests.
 */
-static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
+static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward)
 {
-       char tmp[SIPBUFSIZE];
-       char *s, *e, *t, *trans;
+       char contact[SIPBUFSIZE];
+       char *contact_name = NULL;
+       char *contact_number = NULL;
+       char *separator, *trans;
        char *domain;
        enum sip_transport transport = SIP_TRANSPORT_UDP;
 
-       ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp));
-       if ((t = strchr(tmp, ',')))
-               *t = '\0';
+       ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact));
+       if ((separator = strchr(contact, ',')))
+               *separator = '\0';
 
-       s = get_in_brackets(tmp);
-       if ((trans = strcasestr(s, ";transport="))) do {
+       /* ooh, a name */
+       if (*contact == '"') {
+               contact_name = contact + 1;
+               if ((separator = strchr(contact_name, '"'))) {
+                       *separator++ = '\0';
+               }
+       }
+
+       contact_number = get_in_brackets(contact);
+       if ((trans = strcasestr(contact_number, ";transport="))) {
                trans += 11;
 
-               if ((e = strchr(trans, ';')))
-                       *e = '\0';
+               if ((separator = strchr(trans, ';')))
+                       *separator = '\0';
 
                if (!strncasecmp(trans, "tcp", 3))
                        transport = SIP_TRANSPORT_TCP;
@@ -16513,12 +16961,12 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
                        transport = SIP_TRANSPORT_TLS;
                else {
                        if (strncasecmp(trans, "udp", 3))
-                               ast_debug(1, "received contact with an invalid transport, '%s'\n", s);
+                               ast_debug(1, "received contact with an invalid transport, '%s'\n", contact_number);
                        /* This will assume UDP for all unknown transports */
                        transport = SIP_TRANSPORT_UDP;
                }
-       } while(0);
-       s = remove_uri_parameters(s);
+       }
+       contact_number = remove_uri_parameters(contact_number);
 
        if (p->socket.tcptls_session) {
                ao2_ref(p->socket.tcptls_session, -1);
@@ -16528,51 +16976,70 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
        p->socket.fd = -1;
        p->socket.type = transport;
 
-       if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
+       if (set_call_forward && ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
                char *host = NULL;
-               if (!strncasecmp(s, "sip:", 4))
-                       s += 4;
-               else if (!strncasecmp(s, "sips:", 5))
-                       s += 5;
-               e = strchr(s, '/');
-               if (e)
-                       *e = '\0';
-               if ((host = strchr(s, '@'))) {
+               if (!strncasecmp(contact_number, "sip:", 4))
+                       contact_number += 4;
+               else if (!strncasecmp(contact_number, "sips:", 5))
+                       contact_number += 5;
+               separator = strchr(contact_number, '/');
+               if (separator)
+                       *separator = '\0';
+               if ((host = strchr(contact_number, '@'))) {
                        *host++ = '\0';
-                       ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", s, get_transport(transport), host);
+                       ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", contact_number, get_transport(transport), host);
                        if (p->owner)
-                               ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", s, get_transport(transport), host);
+                               ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", contact_number, get_transport(transport), host);
                } else {
-                       ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), s);
+                       ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), contact_number);
                        if (p->owner)
-                               ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), s);
+                               ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), contact_number);
                }
        } else {
-               e = strchr(tmp, '@');
-               if (e) {
-                       *e++ = '\0';
-                       domain = e;
+               separator = strchr(contact, '@');
+               if (separator) {
+                       *separator++ = '\0';
+                       domain = separator;
                } else {
                        /* No username part */
-                       domain = tmp;
-               }
-               e = strchr(tmp, '/');   /* WHEN do we hae a forward slash in the URI? */
-               if (e)
-                       *e = '\0';
-
-               if (!strncasecmp(s, "sip:", 4))
-                       s += 4;
-               else if (!strncasecmp(s, "sips:", 5))
-                       s += 5;
-               e = strchr(s, ';');     /* And username ; parameters? */
-               if (e)
-                       *e = '\0';      
-               ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", s, domain);
-               if (p->owner) {
-                       pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain);
-                       ast_string_field_set(p->owner, call_forward, s);
+                       domain = contact;
+               }
+               separator = strchr(contact, '/');       /* WHEN do we hae a forward slash in the URI? */
+               if (separator)
+                       *separator = '\0';
+
+               if (!strncasecmp(contact_number, "sip:", 4))
+                       contact_number += 4;
+               else if (!strncasecmp(contact_number, "sips:", 5))
+                       contact_number += 5;
+               separator = strchr(contact_number, ';');        /* And username ; parameters? */
+               if (separator)
+                       *separator = '\0';
+               if (set_call_forward) {
+                       ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", contact_number, domain);
+                       if (p->owner) {
+                               pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain);
+                               ast_string_field_set(p->owner, call_forward, contact_number);
+                       }
                }
        }
+
+       /* We've gotten the number for the contact, now get the name */
+
+       if (*contact == '\"') {
+               contact_name = contact + 1;
+               if (!(separator = (char *)find_closing_quote(contact_name, NULL))) {
+                       ast_log(LOG_NOTICE, "No closing quote on name in Contact header? %s\n", contact);
+               }
+               *separator = '\0';
+       }
+
+       if (name && !ast_strlen_zero(contact_name)) {
+               *name = ast_strdup(contact_name);
+       }
+       if (number) {
+               *number = ast_strdup(contact_number);
+       }
 }
 
 /*! \brief Check pending actions on SIP call */
@@ -16635,6 +17102,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
        int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
        char *p_hdrval;
        int rtn;
+       struct ast_party_connected_line connected;
 
        if (reinvite)
                ast_debug(4, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid);
@@ -16653,7 +17121,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
        /* RFC3261 says we must treat every 1xx response (but not 100)
           that we don't recognize as if it was 183.
        */
-       if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 182 && resp != 183)
+       if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 181 && resp != 182 && resp != 183)
                resp = 183;
 
        /* Any response between 100 and 199 is PROCEEDING */
@@ -16681,6 +17149,14 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p))
                        ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
                if (!req->ignore && p->owner) {
+                       if (get_rpid(p, req)) {
+                               ast_party_connected_line_init(&connected);
+                               connected.id.number = (char *) p->cid_num;
+                               connected.id.name = (char *) p->cid_name;
+                               connected.id.number_presentation = p->callingpres;
+                               connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+                               ast_channel_queue_connected_line_update(p->owner, &connected);
+                       }
                        ast_queue_control(p->owner, AST_CONTROL_RINGING);
                        if (p->owner->_state != AST_STATE_UP) {
                                ast_setstate(p->owner, AST_STATE_RINGING);
@@ -16698,10 +17174,32 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                check_pendings(p);
                break;
 
+       case 181:       /* Call Is Being Forwarded */
+               if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
+                       ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
+               if (!req->ignore && p->owner) {
+                       struct ast_party_redirecting redirecting = {{0,},};
+                       change_redirecting_information(p, req, &redirecting, FALSE);
+                       ast_channel_queue_redirecting_update(p->owner, &redirecting);
+               }
+               check_pendings(p);
+               break;
+
        case 183:       /* Session progress */
                if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
                        ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
                /* Ignore 183 Session progress without SDP */
+               if (!req->ignore && p->owner) {
+                       if (get_rpid(p, req)) {
+                               /* Queue a connected line update */
+                               ast_party_connected_line_init(&connected);
+                               connected.id.number = (char *) p->cid_num;
+                               connected.id.name = (char *) p->cid_name;
+                               connected.id.number_presentation = p->callingpres;
+                               connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+                               ast_channel_queue_connected_line_update(p->owner, &connected);
+                       }
+               }
                if (find_sdp(req)) {
                        if (p->invitestate != INV_CANCELLED)
                                p->invitestate = INV_EARLY_MEDIA;
@@ -16723,7 +17221,17 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                                if (!reinvite)
                                        /* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */
                                        /* For re-invites, we try to recover */
-                                       ast_set_flag(&p->flags[0], SIP_PENDINGBYE);     
+                                       ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
+               }
+
+               if (!req->ignore && p->owner && get_rpid(p, req)) {
+                       /* Queue a connected line update */
+                       ast_party_connected_line_init(&connected);
+                       connected.id.number = (char *) p->cid_num;
+                       connected.id.name = (char *) p->cid_name;
+                       connected.id.number_presentation = p->callingpres;
+                       connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+                       ast_channel_queue_connected_line_update(p->owner, &connected);
                }
 
                /* Parse contact header for continued conversation */
@@ -16747,6 +17255,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
 
                if (!req->ignore && p->owner) {
                        if (!reinvite) {
+                               struct ast_party_connected_line connected;
+                               ast_party_connected_line_collect_caller(&connected, &p->owner->cid);
+                               ast_channel_queue_connected_line_update(p->owner, &connected);
                                ast_queue_control(p->owner, AST_CONTROL_ANSWER);
                                if (sip_cfg.callevents)
                                        manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
@@ -17402,6 +17913,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                case 183:       /* 183 Session Progress */
                case 180:       /* 180 Ringing */
                case 182:       /* 182 Queued */
+               case 181:       /* 181 Call Is Being Forwarded */
                        if (sipmethod == SIP_INVITE)
                                handle_response_invite(p, resp, rest, req, seqno);
                        break;
@@ -17569,7 +18081,11 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                case 301: /* Moved permanently */
                                case 302: /* Moved temporarily */
                                case 305: /* Use Proxy */
-                                       parse_moved_contact(p, req);
+                                       {
+                                       struct ast_party_redirecting redirecting = {{0,},};
+                                       change_redirecting_information(p, req, &redirecting, TRUE);
+                                       ast_channel_set_redirecting(p->owner, &redirecting);
+                                       }
                                        /* Fall through */
                                case 486: /* Busy here */
                                case 600: /* Busy everywhere */
@@ -18265,7 +18781,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, in
                /* We should answer something here. If we are here, the
                        call we are replacing exists, so an accepted 
                        can't harm */
-               transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE);
+               transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE);
                /* Do something more clever here */
                ast_channel_unlock(c);
                sip_pvt_unlock(p->refer->refer_call);
@@ -18299,7 +18815,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, in
           Targetcall is not touched by the masq */
 
        /* Answer the incoming call and set channel to UP state */
-       transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE);
+       transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE);
                
        ast_setstate(c, AST_STATE_UP);
        
@@ -18699,10 +19215,11 @@ static int sip_t38_abort(const void *data)
        return 0;
 }
 
-/*! \brief Handle incoming INVITE request
-\note  If the INVITE has a Replaces header, it is part of an
+/*!
+ * \brief Handle incoming INVITE request
+ * \note If the INVITE has a Replaces header, it is part of an
  *     attended transfer. If so, we do not go through the dial
- *     plan but tries to find the active call and masquerade
+ *     plan but try to find the active call and masquerade
  *     into it 
  */
 static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int *nounlock)
@@ -18973,6 +19490,16 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        parse_ok_contact(p, req);
                } else {        /* Re-invite on existing call */
                        ast_clear_flag(&p->flags[0], SIP_OUTGOING);     /* This is now an inbound dialog */
+                       if (get_rpid(p, req)) {
+                               struct ast_party_connected_line connected;
+
+                               ast_party_connected_line_init(&connected);
+                               connected.id.number = (char *) p->cid_num;
+                               connected.id.name = (char *) p->cid_name;
+                               connected.id.number_presentation = p->callingpres;
+                               connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+                               ast_channel_queue_connected_line_update(p->owner, &connected);
+                       }
                        /* Handle SDP here if we already have an owner */
                        if (find_sdp(req)) {
                                if (process_sdp(p, req, SDP_T38_INITIATE)) {
@@ -18995,6 +19522,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
        if (!p->lastinvite && !req->ignore && !p->owner) {
                /* This is a new invite */
                /* Handle authentication if this is our first invite */
+               struct ast_party_redirecting redirecting = {{0,},};
                res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin);
                if (res == AUTH_CHALLENGE_SENT) {
                        p->invitestate = INV_COMPLETED;         /* Needs to restart in another INVITE transaction */
@@ -19052,7 +19580,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        return 0;
                }
                gotdest = get_destination(p, NULL);     /* Get destination right away */
-               get_rdnis(p, NULL);                     /* Get redirect information */
+               change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */
                extract_uri(p, req);                    /* Get the Contact URI */
                build_contact(p);                       /* Build our contact header */
 
@@ -19096,9 +19624,11 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        if (c) {
                                /* Pre-lock the call */
                                ast_channel_lock(c);
+                               ast_channel_set_redirecting(c, &redirecting);
                        }
                }
        } else {
+               struct ast_party_redirecting redirecting = {{0,},};
                if (sipdebug) {
                        if (!req->ignore)
                                ast_debug(2, "Got a SIP re-invite for call %s\n", p->callid);
@@ -19108,6 +19638,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                if (!req->ignore)
                        reinvite = 1;
                c = p->owner;
+               change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */
+               if (c) {
+                       ast_channel_set_redirecting(c, &redirecting);
+               }
        }
 
        /* Session-Timers */
@@ -19318,7 +19852,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                                        c->hangupcause = AST_CAUSE_CALL_REJECTED;
                                } else {
                                        sip_pvt_unlock(p);
-                                       ast_setstate(c, AST_STATE_DOWN);
                                        c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
                                }
                                p->invitestate = INV_COMPLETED;
@@ -19348,7 +19881,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        } else if (p->t38.state == T38_DISABLED) {
                                /* If this is not a re-invite or something to ignore - it's critical */
                                ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
-                               transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ?  XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE:TRUE); 
+                               transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ?  XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE : TRUE, FALSE);
                        }
 
                        p->invitestate = INV_TERMINATED;
@@ -19466,6 +19999,8 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *
                else
                        ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
        } else {
+               struct ast_party_connected_line connected_caller;
+
                /* Transfer succeeded! */
                const char *xfersound = pbx_builtin_getvar_helper(target.chan1, "ATTENDED_TRANSFER_COMPLETE_SOUND");
 
@@ -19480,6 +20015,45 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *
                        ast_debug(1, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name);
                        ast_channel_unlock(targetcall_pvt->owner);
                }
+
+               if (target.chan2) {
+                       if (current->chan2) {
+                               /* Tell each of the other channels to whom they are now connected */
+                               ast_channel_lock(current->chan2);
+                               ast_connected_line_copy_from_caller(&connected_caller, &current->chan2->cid);
+                               ast_channel_unlock(current->chan2);
+                               connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+                               ast_channel_update_connected_line(target.chan2, &connected_caller);
+                               ast_channel_lock(target.chan2);
+                               ast_connected_line_copy_from_caller(&connected_caller, &target.chan2->cid);
+                               ast_channel_unlock(target.chan2);
+                               connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+                               ast_channel_update_connected_line(current->chan2, &connected_caller);
+                               ast_party_connected_line_free(&connected_caller);
+                       }
+               } else {
+                       /* Notify the first other party that they are connected to someone else assuming that target.chan1
+                          has progressed far enough through the dialplan to have it's called party information set. */
+                       if (current->chan2) {
+                               ast_channel_lock(target.chan1);
+                               ast_party_connected_line_copy(&connected_caller, &target.chan1->connected);
+                               ast_channel_unlock(target.chan1);
+                               connected_caller = target.chan1->connected;
+                               connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+                               ast_channel_update_connected_line(current->chan2, &connected_caller);
+                               ast_party_connected_line_free(&connected_caller);
+                       }
+
+                       /* We can't indicate to the called channel directly so we force the masquerade to complete
+                          and queue and update to be read and passed-through */
+                       ast_channel_lock(target.chan1);
+                       ast_do_masquerade(target.chan1);
+                       ast_channel_unlock(target.chan1);
+
+                       ast_party_connected_line_collect_caller(&connected_caller, &target.chan1->cid);
+                       connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+                       ast_channel_queue_connected_line_update(target.chan1, &connected_caller);
+               }
        }
        if (targetcall_pvt)
                ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt");
@@ -20553,10 +21127,10 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so
                 */
                int ret = 0;
 
-               if (p->ocseq < seqno && seqno != p->lastnoninvite) {
+               if (p->ocseq < seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) {
                        ast_debug(1, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
                        ret = -1;
-               } else if (p->ocseq != seqno && seqno != p->lastnoninvite) {
+               } else if (p->ocseq != seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) {
                        /* ignore means "don't do anything with it" but still have to 
                         * respond appropriately.
                         * But in this case this is a response already, so we really
@@ -22130,7 +22704,16 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
                ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID);
        } else if (!strcasecmp(v->name, "sendrpid")) {
                ast_set_flag(&mask[0], SIP_SENDRPID);
-               ast_set2_flag(&flags[0], ast_true(v->value), SIP_SENDRPID);
+               if (!strcasecmp(v->value, "pai")) {
+                       ast_set_flag(&flags[0], SIP_SENDRPID_PAI);
+               } else if (!strcasecmp(v->value, "rpid")) {
+                       ast_set_flag(&flags[0], SIP_SENDRPID_RPID);
+               } else if (ast_true(v->value)) {
+                       ast_set_flag(&flags[0], SIP_SENDRPID_RPID);
+               }
+       } else if (!strcasecmp(v->name, "rpid_immediate")) {
+               ast_set_flag(&mask[1], SIP_PAGE2_RPID_IMMEDIATE);
+               ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RPID_IMMEDIATE);
        } else if (!strcasecmp(v->name, "g726nonstandard")) {
                ast_set_flag(&mask[0], SIP_G726_NONSTANDARD);
                ast_set2_flag(&flags[0], ast_true(v->value), SIP_G726_NONSTANDARD);
index f4104a8..588680e 100644 (file)
@@ -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);