Index: channels/chan_phone.c =================================================================== --- channels/chan_phone.c (revision 114099) +++ channels/chan_phone.c (working copy) @@ -303,13 +303,13 @@ snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min); } /* the standard format of ast->callerid is: "name" , but not always complete */ - if (ast_strlen_zero(ast->cid.cid_name)) + if (ast_strlen_zero(ast->lid.lid_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->lid.lid_name, sizeof(cid.name)); - if (ast->cid.cid_num) - ast_copy_string(cid.number, ast->cid.cid_num, sizeof(cid.number)); + if (ast->lid.lid_num) + ast_copy_string(cid.number, ast->lid.lid_num, sizeof(cid.number)); p = ast->tech_pvt; Index: channels/chan_h323.c =================================================================== --- channels/chan_h323.c (revision 114099) +++ channels/chan_h323.c (working copy) @@ -608,18 +608,18 @@ /* 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->lid.lid_num) + ast_copy_string(pvt->options.cid_num, c->lid.lid_num, 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->lid.lid_name) + ast_copy_string(pvt->options.cid_name, c->lid.lid_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)); + if (c->lid.lid_rdnis) { + ast_copy_string(pvt->options.cid_rdnis, c->lid.lid_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->lid.lid_pres; + pvt->options.type_of_number = c->lid.lid_ton; if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) { if (!strcasecmp(addr, "UNKNOWN")) Index: channels/chan_zap.c =================================================================== --- channels/chan_zap.c (revision 114099) +++ channels/chan_zap.c (working copy) @@ -2150,7 +2150,7 @@ } 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->lid.lid_name, ast->lid.lid_num, AST_LAW(p)); p->cidpos = 0; send_callerid(p); } @@ -2191,12 +2191,12 @@ } 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->lid.lid_num) + ast_copy_string(p->callwait_num, ast->lid.lid_num, 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->lid.lid_name) + ast_copy_string(p->callwait_name, ast->lid.lid_name, sizeof(p->callwait_name)); else p->callwait_name[0] = '\0'; /* Call waiting tone instead */ @@ -2209,8 +2209,8 @@ 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->lid.lid_name; + l = ast->lid.lid_num; if (l) ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num)); else @@ -2276,14 +2276,14 @@ switch (mysig) { case SIG_FEATD: - l = ast->cid.cid_num; + l = ast->lid.lid_num; 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->lid.lid_num; if (l) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c); else @@ -2392,7 +2392,7 @@ c = dest; if (!p->hidecallerid) { - l = ast->cid.cid_num; + l = ast->lid.lid_num; } else { l = NULL; } @@ -2441,10 +2441,10 @@ } } 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->lid.lid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED), + p->use_callingpres ? cid_pres2ss7screen(ast->lid.lid_pres) : SS7_SCREENING_USER_PROVIDED ); - isup_set_oli(p->ss7call, ast->cid.cid_ani2); + isup_set_oli(p->ss7call, ast->lid.lid_ani2); isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc); /* Set the charge number if it is set */ @@ -2510,9 +2510,9 @@ n = NULL; if (!p->hidecallerid) { - l = ast->cid.cid_num; + l = ast->lid.lid_num; if (!p->hidecalleridname) { - n = ast->cid.cid_name; + n = ast->lid.lid_name; } } @@ -2718,7 +2718,7 @@ } } 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->lid.lid_pres : (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; @@ -2732,7 +2732,7 @@ redirect_reason = PRI_REDIR_UNCONDITIONAL; } else redirect_reason = PRI_REDIR_UNCONDITIONAL; - pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason); + pri_sr_set_redirecting(sr, ast->lid.lid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason); #ifdef SUPPORT_USERUSER /* User-user info */ Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 114099) +++ channels/chan_sip.c (working copy) @@ -219,8 +219,6 @@ #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif -#define CALLERID_UNKNOWN "Unknown" - #define DEFAULT_MAXMS 2000 /*!< Qualification: Must be faster than 2 seconds by default */ #define DEFAULT_QUALIFYFREQ 60 * 1000 /*!< Qualification: How often to check for the host to be up */ #define DEFAULT_FREQ_NOTOK 10 * 1000 /*!< Qualification: How often to check, if the host is down... */ @@ -1203,8 +1201,6 @@ AST_STRING_FIELD(fullcontact); /*!< The Contact: that the UA registers with us */ /* we only store the part in 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 */ ); struct sip_socket socket; /*!< The socket used for this dialog */ @@ -1832,6 +1828,7 @@ static const char *dtmfmode2str(int mode) attribute_const; static int str2dtmfmode(const char *str) attribute_unused; static const char *insecure2str(int mode) attribute_const; +static const char *callingpres2str(int callingpres) attribute_const; static void cleanup_stale_contexts(char *new, char *old); static void print_codec_to_cli(int fd, struct ast_codec_pref *pref); static const char *domain_mode_to_text(const enum domain_mode mode); @@ -1944,11 +1941,12 @@ 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_rpid(struct sip_pvt *p, struct sip_request *oreq); static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq); 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); 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); /*--- Constructing requests and responses */ static void initialize_initreq(struct sip_pvt *p, struct sip_request *req); @@ -1978,7 +1976,6 @@ 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); @@ -4004,6 +4001,8 @@ 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); dialog->outboundproxy = obproxy_get(dialog, peer); dialog->callgroup = peer->callgroup; dialog->pickupgroup = peer->pickupgroup; @@ -4225,7 +4224,6 @@ if (res == -1) return res; - p->callingpres = ast->cid.cid_pres; p->jointcapability = ast_translate_available_formats(p->capability, p->prefcodec); p->jointnoncodeccapability = p->noncodeccapability; @@ -5221,6 +5219,9 @@ case AST_CONTROL_SRCUPDATE: ast_rtp_new_source(p->rtp); break; + case AST_CONTROL_CONNECTEDLINE: + update_connectedline(p, data, datalen); + break; case -1: res = -1; break; @@ -7462,9 +7463,6 @@ 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); @@ -8504,85 +8502,6 @@ ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ntohs(p->socket.port), get_transport(p->socket.type)); } -/*! \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\" ", 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\" ;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) { @@ -8617,16 +8536,10 @@ 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 (p->owner && (p->owner->lid.lid_pres & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) { + l = p->owner->lid.lid_num; + n = p->owner->lid.lid_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 (ast_strlen_zero(l)) l = default_callerid; if (ast_strlen_zero(n)) @@ -8713,12 +8626,7 @@ /* 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); @@ -8727,8 +8635,6 @@ 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 Build REFER/INVITE/OPTIONS message and transmit it @@ -8829,6 +8735,28 @@ ast_channel_unlock(chan); } + if ((sipmethod == SIP_INVITE || sipmethod == SIP_UPDATE) && ast_test_flag(&p->flags[0], SIP_SENDRPID)) { + char buf[256]; + const char *cid_num = default_callerid; + const char *cid_name = NULL; + int cid_pres; + const char *fromdomain; + + if (p->owner && p->owner->lid.lid_num) + cid_num = p->owner->lid.lid_num; + if (p->owner && p->owner->lid.lid_name) + cid_name = p->owner->lid.lid_name; + cid_pres = (p->owner) ? p->owner->lid.lid_pres : AST_PRES_NUMBER_NOT_AVAILABLE; + if (ast_strlen_zero(cid_name)) + cid_name = cid_num; + + fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)); + + snprintf(buf, sizeof(buf), "\"%s\" ;party=calling", cid_name, cid_num, fromdomain); + if (cid_pres != AST_PRES_NUMBER_NOT_AVAILABLE) + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";%s", callingpres2str(cid_pres)); + add_header(&req, "Remote-Party-ID", buf); + } if (sdp) { if (p->udptl && (p->t38.state == T38_LOCAL_DIRECT || p->t38.state == T38_LOCAL_REINVITE)) { ast_udptl_offered_from_local(p->udptl, 1); @@ -9102,6 +9030,71 @@ return send_request(p, &req, XMIT_RELIABLE, p->ocseq); } +/*! \brief Notify peer that the callerid has been updated */ +static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen) +{ + char lid_num[80], lid_name[80]; + int lid_pres; + char buf[256]; + const char *fromdomain; + + if (ast_parse_connectedline_data((unsigned char *) data, datalen, lid_num, sizeof(lid_num), lid_name, sizeof(lid_name), &lid_pres)) + return; + ast_set_connectedline(p->owner, lid_num, lid_name, lid_pres); + + if (!ast_test_flag(&p->flags[0], SIP_SENDRPID)) + return; + if (ast_strlen_zero(p->owner->lid.lid_num)) + return; + + fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)); + + snprintf(buf, sizeof(buf), "\"%s\" ;party=%s", p->owner->lid.lid_name, p->owner->lid.lid_num, fromdomain, ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "calling" : "called"); + if (p->owner->lid.lid_pres != AST_PRES_NUMBER_NOT_AVAILABLE) + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";%s", callingpres2str(lid_pres)); + + append_history(p, "ConnectedLine", "%s party is now %s <%s>", ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "Calling" : "Called", p->owner->lid.lid_name, p->owner->lid.lid_num); + + 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_header(&req, "Remote-Party-ID", buf); + add_sdp(&req, p, 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_header(&req, "Remote-Party-ID", buf); + add_header_contentLength(&req, 0); + send_request(p, &req, XMIT_CRITICAL, p->ocseq); + } + } else { + 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_header(&resp, "Remote-Party-ID", buf); + 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_header(&resp, "Remote-Party-ID", buf); + 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)); + } + } +} + static const struct _map_x_s regstatestrings[] = { { REG_STATE_FAILED, "Failed" }, { REG_STATE_UNREGISTERED, "Unregistered"}, @@ -10559,6 +10552,104 @@ } } +/*! \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 0; + + 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 (privacy && !strcasecmp(privacy, "full")) { + if (screen && !strcasecmp(screen, "yes")) + callingpres = AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; + else + callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; + } else { + if (screen && !strcasecmp(screen, "yes")) + callingpres = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; + else + 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) { @@ -11188,37 +11279,6 @@ 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; -} - /*! * duplicate a list of channel variables, \return the copy. */ @@ -11235,25 +11295,10 @@ return res; } -/*! \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 user authentication */ static enum check_auth_result check_user_ok(struct sip_pvt *p, char *of, struct sip_request *req, int sipmethod, struct sockaddr_in *sin, - enum xmittype reliable, - char *rpid_num, char *calleridname, char *uri2) + enum xmittype reliable, char *calleridname, char *uri2) { enum check_auth_result res; struct sip_user *user = find_user(of, 1); @@ -11286,8 +11331,7 @@ p->autoframing = user->autoframing; } - replace_cid(p, rpid_num, calleridname); - do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE) ); + do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE)); if (!(res = check_auth(p, req, user->name, user->secret, user->md5secret, sipmethod, uri2, reliable, req->ignore))) { sip_cancel_destroy(p); @@ -11302,14 +11346,18 @@ ast_set_flag(&p->flags[0], SIP_CALL_LIMIT); if (!ast_strlen_zero(user->context)) ast_string_field_set(p, context, user->context); - if (!ast_strlen_zero(user->cid_num)) { - char *tmp = ast_strdupa(user->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(user->cid_num)) { + char *tmp = ast_strdupa(user->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(user->cid_name)) + ast_string_field_set(p, cid_name, user->cid_name); + if (user->callingpres) + p->callingpres = user->callingpres; } - if (!ast_strlen_zero(user->cid_name)) - ast_string_field_set(p, cid_name, user->cid_name); ast_string_field_set(p, username, user->name); ast_string_field_set(p, peername, user->name); ast_string_field_set(p, peersecret, user->secret); @@ -11323,9 +11371,6 @@ p->amaflags = user->amaflags; p->callgroup = user->callgroup; p->pickupgroup = user->pickupgroup; - if (user->callingpres) /* User callingpres setting will override RPID header */ - p->callingpres = user->callingpres; - /* Set default codec settings for this call */ p->capability = user->capability; /* User codec choice */ p->jointcapability = user->capability; /* Our codecs */ @@ -11359,8 +11404,7 @@ 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); @@ -11398,7 +11442,6 @@ 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); @@ -11406,8 +11449,6 @@ ast_string_field_set(p, subscribecontext, peer->subscribecontext); ast_string_field_set(p, mohinterpret, peer->mohinterpret); ast_string_field_set(p, mohsuggest, peer->mohsuggest); - if (peer->callingpres) /* Peer calling pres setting will override RPID */ - p->callingpres = peer->callingpres; if (peer->maxms && peer->lastms) p->timer_t1 = peer->lastms < global_t1min ? global_t1min : peer->lastms; else @@ -11445,14 +11486,18 @@ /* 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); @@ -11504,8 +11549,6 @@ 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); @@ -11521,11 +11564,6 @@ 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; @@ -11600,19 +11638,19 @@ /* If we are looking for a peer, don't check the user objects (or realtime) */ res = check_user_ok(p, of, req, sipmethod, sin, - reliable, rpid_num, calleridname, uri2); + reliable, calleridname, uri2); if (res != AUTH_DONT_KNOW) return res; } 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 (global_allowguest) { - replace_cid(p, rpid_num, calleridname); + get_rpid(p, req); res = AUTH_SUCCESSFUL; } else if (global_alwaysauthreject) res = AUTH_FAKE_AUTH; /* reject with fake authorization request */ @@ -12264,6 +12302,36 @@ return map_x_s(insecurestr, mode, ""); } +/*! \brief Convert caller presentation into SIP privacy and screen tags */ +static const char *callingpres2str(int callingpres) +{ + switch (callingpres) { + case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: + return "privacy=off;screen=no"; + case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: + return "privacy=off;screen=yes"; + case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: + return "privacy=off;screen=no"; + case AST_PRES_ALLOWED_NETWORK_NUMBER: + return "privacy=off;screen=yes"; + case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED: + return "privacy=full;screen=no"; + case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: + return "privacy=full;screen=yes"; + case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: + return "privacy=full;screen=no"; + case AST_PRES_PROHIB_NETWORK_NUMBER: + return "privacy=full;screen=yes"; + case AST_PRES_NUMBER_NOT_AVAILABLE: + return ""; + default: + if ((callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) + return "privacy=full;screen=no"; + else + return "privacy=off;screen=no"; + } +} + /*! \brief Destroy disused contexts between reloads Only used in reload_config so the code for regcontext doesn't get ugly */ @@ -14620,6 +14688,9 @@ 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_queue_connectedline_update(p->owner, p->cid_num, p->cid_name, p->callingpres); + } ast_queue_control(p->owner, AST_CONTROL_RINGING); if (p->owner->_state != AST_STATE_UP) { ast_setstate(p->owner, AST_STATE_RINGING); @@ -14641,6 +14712,12 @@ 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 id update */ + ast_queue_connectedline_update(p->owner, p->cid_num, p->cid_name, p->callingpres); + } + } if (find_sdp(req)) { if (p->invitestate != INV_CANCELLED) p->invitestate = INV_EARLY_MEDIA; @@ -16388,6 +16465,8 @@ 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)) + ast_queue_connectedline_update(p->owner, p->cid_num, p->cid_name, p->callingpres); /* Handle SDP here if we already have an owner */ if (find_sdp(req)) { if (process_sdp(p, req, SDP_T38_INITIATE)) { @@ -16954,6 +17033,25 @@ ast_debug(1, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name); ast_channel_unlock(targetcall_pvt->owner); } + + if (target.chan2) { + /* Tell each of the other channels to whom they are now connected */ + ast_connectedline_update(target.chan2, current->chan2->cid.cid_num, current->chan2->cid.cid_name, current->chan2->cid.cid_pres); + ast_connectedline_update(current->chan2, target.chan2->cid.cid_num, target.chan2->cid.cid_name, target.chan2->cid.cid_pres); + } 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_connectedline_update(current->chan2, target.chan1->lid.lid_num, target.chan1->lid.lid_name, target.chan1->lid.lid_pres); + + /* 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_queue_connectedline_update(target.chan1, target.chan1->cid.cid_num, target.chan1->cid.cid_name, target.chan1->cid.cid_pres); + } } return 1; } @@ -17937,10 +18035,10 @@ */ 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 Index: channels/chan_agent.c =================================================================== --- channels/chan_agent.c (revision 114099) +++ channels/chan_agent.c (working copy) @@ -637,8 +637,7 @@ 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_set_connectedline(p->chan, ast->lid.lid_num, ast->lid.lid_name, ast->lid.lid_pres); ast_channel_inherit_variables(ast, p->chan); res = ast_call(p->chan, p->loginchan, 0); CLEANUP(ast,p); Index: channels/chan_iax2.c =================================================================== --- channels/chan_iax2.c (revision 114099) +++ channels/chan_iax2.c (working copy) @@ -280,6 +280,8 @@ IAX_DELAYPBXSTART = (1 << 25), /*!< Don't start a PBX on the channel until the peer sends us a response, so that we've achieved a three-way handshake with them before sending voice or anything else*/ + IAX_SENDCONNECTEDLINE = (1 << 26), /*!< Allow sending of connected line ID updates */ + IAX_RECVCONNECTEDLINE = (1 << 27), /*!< Allow receiving of connected line ID updates */ }; static int global_rtautoclear = 120; @@ -3153,6 +3155,8 @@ 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]; @@ -3196,7 +3200,7 @@ 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); + ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); cai->maxtime = peer->maxms; cai->capability = peer->capability; cai->encmethods = peer->encmethods; @@ -3214,6 +3218,8 @@ 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)) { @@ -3411,8 +3417,8 @@ if (pds.port) sin.sin_port = htons(atoi(pds.port)); - l = c->cid.cid_num; - n = c->cid.cid_name; + l = c->lid.lid_num; + n = c->lid.lid_name; /* Now build request */ memset(&ied, 0, sizeof(ied)); @@ -3429,28 +3435,28 @@ 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->lid.lid_pres); } else { if (n) - iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres); + iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->lid.lid_pres); 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_short(&ied, IAX_IE_CALLINGTNS, c->cid.cid_tns); + iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->lid.lid_ton); + iax_ie_append_short(&ied, IAX_IE_CALLINGTNS, c->lid.lid_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->lid.lid_ani) + iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->lid.lid_ani); if (!ast_strlen_zero(c->language)) iax_ie_append_str(&ied, IAX_IE_LANGUAGE, c->language); if (!ast_strlen_zero(c->cid.cid_dnid)) - iax_ie_append_str(&ied, IAX_IE_DNID, c->cid.cid_dnid); + iax_ie_append_str(&ied, IAX_IE_DNID, c->lid.lid_dnid); if (!ast_strlen_zero(c->cid.cid_rdnis)) - iax_ie_append_str(&ied, IAX_IE_RDNIS, c->cid.cid_rdnis); + iax_ie_append_str(&ied, IAX_IE_RDNIS, c->lid.lid_rdnis); if (pds.context) iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, pds.context); @@ -3816,6 +3822,8 @@ unsigned short callno = PTR_TO_CALLNO(c->tech_pvt); struct chan_iax2_pvt *pvt; int res = 0; + char cid_num[80], cid_name[80]; + int cid_pres; if (iaxdebug) ast_debug(1, "Indicating condition %d\n", condition); @@ -3835,6 +3843,14 @@ ast_moh_stop(c); goto done; } + break; + case AST_CONTROL_CONNECTEDLINE: + if (ast_parse_connectedline_data((unsigned char *) data, datalen, cid_num, sizeof(cid_num), cid_name, sizeof(cid_name), &cid_pres) == -1) + goto done; + ast_set_connectedline(c, cid_num, cid_name, cid_pres); + if (!ast_test_flag(pvt, IAX_SENDCONNECTEDLINE)) + goto done; + break; } res = send_command(pvt, AST_FRAME_CONTROL, condition, 0, data, datalen, -1); @@ -5743,7 +5759,7 @@ 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; @@ -7768,6 +7784,9 @@ char caller_pref_buf[128]; struct ast_codec_pref pref; char *using_prefs = "mine"; + char cid_num[80]; + char cid_name[80]; + int cid_pres; /* allocate an iax_frame with 4096 bytes of data buffer */ fr = alloca(sizeof(*fr) + 4096); @@ -9198,6 +9217,21 @@ ast_mutex_unlock(&iaxsl[fr->callno]); return 1; } + /* Don't allow incoming callerid updates unless we are configured to */ + if (f.frametype == AST_FRAME_CONTROL && f.subclass == AST_CONTROL_CONNECTEDLINE) { + if (!ast_test_flag(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) { + ast_mutex_unlock(&iaxsl[fr->callno]); + return 1; + } + if (!ast_parse_connectedline_data((unsigned char *) f.data, f.datalen, cid_num, sizeof(cid_num), cid_name, sizeof(cid_name), &cid_pres)) { + ast_string_field_set(iaxs[fr->callno], cid_num, cid_num); + ast_string_field_set(iaxs[fr->callno], cid_name, cid_name); + iaxs[fr->callno]->calling_pres = cid_pres; + + ast_set_callerid(iaxs[fr->callno]->owner, cid_num, cid_name, NULL); + iaxs[fr->callno]->owner->cid.cid_pres = cid_pres; + } + } /* Common things */ f.src = "IAX2"; f.mallocd = 0; @@ -9701,7 +9735,7 @@ } /* 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) @@ -10211,6 +10245,20 @@ 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); + ast_set_flag(peer, 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); + ast_clear_flag(peer, IAX_RECVCONNECTEDLINE); + } }/* else if (strcasecmp(v->name,"type")) */ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ v = v->next; @@ -10438,6 +10486,20 @@ 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); + ast_set_flag(user, 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); + ast_clear_flag(user, IAX_RECVCONNECTEDLINE); + } }/* else if (strcasecmp(v->name,"type")) */ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ v = v->next; Index: channels/chan_skinny.c =================================================================== --- channels/chan_skinny.c (revision 114099) +++ channels/chan_skinny.c (working copy) @@ -2236,6 +2236,50 @@ 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->parent; + struct skinnysession *s = d->session; + char lid_name[80], lid_num[80]; + int lid_pres; + + if (ast_parse_connectedline_data((unsigned char *) data, datalen, lid_num, sizeof(lid_num), lid_name, sizeof(lid_name), &lid_pres)) + return; + ast_set_connectedline(c, lid_num, lid_name, lid_pres); + + if (ast_strlen_zero(c->cid.cid_num) || ast_strlen_zero(c->lid.lid_num)) + return; + + if (sub->owner->_state == AST_STATE_UP) { + transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid); + transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid); + if (sub->outgoing) + transmit_callinfo(s, c->lid.lid_name, c->lid.lid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1); + else + transmit_callinfo(s, l->cid_name, l->cid_num, c->lid.lid_name, c->lid.lid_num, l->instance, sub->callid, 2); + } else { + if (sub->outgoing) { + transmit_callstate(s, l->instance, SKINNY_RINGIN, sub->callid); + transmit_displaypromptstatus(s, "Ring-In", 0, l->instance, sub->callid); + transmit_callinfo(s, c->lid.lid_name, c->lid.lid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1); + } else { + if (!sub->ringing) { + transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid); + transmit_displaypromptstatus(s, "Ring-Out", 0, l->instance, sub->callid); + sub->ringing = 1; + } else { + transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid); + transmit_displaypromptstatus(s, "Call Progress", 0, l->instance, sub->callid); + sub->progress = 1; + } + + transmit_callinfo(s, l->cid_name, l->cid_num, c->lid.lid_name, c->lid.lid_num, l->instance, sub->callid, 2); + } + } +} + static int has_voicemail(struct skinny_line *l) { return ast_app_has_voicemail(l->mailbox, NULL); @@ -3195,6 +3239,8 @@ l->hidecallerid ? "" : l->cid_num, l->hidecallerid ? "" : l->cid_name, c->cid.cid_ani ? NULL : l->cid_num); + c->lid.lid_num = ast_strdup(c->exten); + c->lid.lid_name = NULL; ast_setstate(c, AST_STATE_RING); if (!sub->rtp) { start_rtp(sub); @@ -3350,7 +3396,7 @@ transmit_callstate(s, l->instance, SKINNY_RINGIN, sub->callid); transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGIN); transmit_displaypromptstatus(s, "Ring-In", 0, l->instance, sub->callid); - transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1); + transmit_callinfo(s, ast->lid.lid_name, ast->lid.lid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1); transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); transmit_ringer_mode(s, SKINNY_RING_INSIDE); @@ -3429,7 +3475,7 @@ /* order matters here... for some reason, transmit_callinfo must be before transmit_callstate, or you won't get keypad messages in some situations. */ - transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2); + transmit_callinfo(s, ast->lid.lid_name, ast->lid.lid_num, exten, exten, l->instance, sub->callid, 2); transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid); transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED); transmit_dialednumber(s, exten, l->instance, sub->callid); @@ -3621,6 +3667,8 @@ return "Hold"; case AST_CONTROL_UNHOLD: return "Unhold"; + case AST_CONTROL_CONNECTEDLINE: + return "Connected Line ID"; case -1: return "Stop tone"; default: @@ -3659,7 +3707,7 @@ transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid); transmit_dialednumber(s, exten, l->instance, sub->callid); transmit_displaypromptstatus(s, "Ring Out", 0, l->instance, sub->callid); - transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */ + transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, S_OR(ast->lid.lid_name, exten), S_OR(ast->lid.lid_num, exten), l->instance, sub->callid, 2); /* 2 = outgoing from phone */ sub->ringing = 1; if (!d->earlyrtp) { break; @@ -3700,7 +3748,7 @@ } transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid); transmit_displaypromptstatus(s, "Call Progress", 0, l->instance, sub->callid); - transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */ + transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, S_OR(ast->lid.lid_name, exten), S_OR(ast->lid.lid_num, exten), l->instance, sub->callid, 2); /* 2 = outgoing from phone */ sub->progress = 1; if (!d->earlyrtp) { break; @@ -3721,6 +3769,9 @@ case AST_CONTROL_SRCUPDATE: ast_rtp_new_source(sub->rtp); break; + case AST_CONTROL_CONNECTEDLINE: + update_connectedline(sub, data, datalen); + break; default: ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind); return -1; /* Tell asterisk to provide inband signalling */ Index: channels/chan_mgcp.c =================================================================== --- channels/chan_mgcp.c (revision 114099) +++ channels/chan_mgcp.c (working copy) @@ -916,7 +916,7 @@ 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->lid.lid_num, ast->lid.lid_name); ast_setstate(ast, AST_STATE_RINGING); if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) { Index: channels/chan_unistim.c =================================================================== --- channels/chan_unistim.c (revision 114099) +++ channels/chan_unistim.c (working copy) @@ -3666,16 +3666,16 @@ Sendicon(TEXT_LINE0, FAV_ICON_NONE, session); if (sub->owner) { - if (sub->owner->cid.cid_num) { - send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->cid.cid_num); - change_callerid(session, 0, sub->owner->cid.cid_num); + if (sub->owner->lid.lid_num) { + send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->lid.lid_num); + change_callerid(session, 0, sub->owner->lid.lid_num); } else { send_text(TEXT_LINE1, TEXT_NORMAL, session, DEFAULTCALLERID); change_callerid(session, 0, DEFAULTCALLERID); } - if (sub->owner->cid.cid_name) { - send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->cid.cid_name); - change_callerid(session, 1, sub->owner->cid.cid_name); + if (sub->owner->lid.lid_name) { + send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->lid.lid_name); + change_callerid(session, 1, sub->owner->lid.lid_name); } else { send_text(TEXT_LINE0, TEXT_NORMAL, session, DEFAULTCALLERNAME); change_callerid(session, 1, DEFAULTCALLERNAME); Index: channels/chan_local.c =================================================================== --- channels/chan_local.c (revision 114099) +++ channels/chan_local.c (working copy) @@ -495,11 +495,18 @@ * Note that cid_num and cid_name aren't passed in the ast_channel_alloc * call, so it's done here instead. */ - 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_num = ast_strdup(p->owner->lid.lid_num); + p->chan->cid.cid_name = ast_strdup(p->owner->lid.lid_name); + p->chan->cid.cid_ani = ast_strdup(p->owner->lid.lid_ani); + p->chan->cid.cid_rdnis = ast_strdup(p->owner->lid.lid_rdnis); + + p->chan->cid.cid_pres = p->owner->lid.lid_pres; + p->chan->cid.cid_ton = p->owner->lid.lid_ton; + p->chan->cid.cid_tns = p->owner->lid.lid_tns; + p->chan->cid.cid_ani2 = p->owner->lid.lid_ani2; + + ast_set_connectedline(p->chan, p->owner->cid.cid_num, p->owner->cid.cid_name, p->owner->cid.cid_pres); + ast_string_field_set(p->chan, language, p->owner->language); ast_string_field_set(p->chan, accountcode, p->owner->accountcode); p->chan->cdrflags = p->owner->cdrflags; Index: channels/iax2-parser.c =================================================================== --- channels/iax2-parser.c (revision 114099) +++ channels/iax2-parser.c (working copy) @@ -468,7 +468,10 @@ "PROCDNG", "HOLD ", "UNHOLD ", - "VIDUPDT", }; + "VIDUPDT", + "T38", + "SRCUPDT", + "CONLINE", }; struct ast_iax2_full_hdr *fh; char retries[20]; char class2[20]; Index: apps/app_dial.c =================================================================== --- apps/app_dial.c (revision 114099) +++ apps/app_dial.c (working copy) @@ -112,10 +112,7 @@ " string is sent to the calling party. Both parameters can be used\n" " alone.\n" " e - execute the 'h' extension for peer after the call ends\n" -" f - Force the callerid of the *calling* channel to be set as the\n" -" extension associated with the channel using a dialplan 'hint'.\n" -" For example, some PSTNs do not allow CallerID to be set to anything\n" -" other than the number assigned to the caller.\n" +" f(x) - Force the outgoing callerid to 'x'.\n" " F(context^exten^pri) - When the caller hangs up, transfer the called party\n" " to the specified context and extension and continue execution.\n" " g - Proceed with dialplan execution at the current extension if the\n" @@ -129,6 +126,8 @@ " H - Allow the calling party to hang up by hitting the '*' DTMF digit.\n" " i - Asterisk will ignore any forwarding requests it may receive on this\n" " dial attempt.\n" +" I - Asterisk will ignore any connected line update requests it may receive\n" +" on this dial attempt.\n" " k - Allow the called party to enable parking of the call by sending\n" " the DTMF sequence defined for call parking in features.conf.\n" " K - Allow the calling party to enable parking of the call by sending\n" @@ -168,9 +167,6 @@ " directory.\n" " N - This option is a modifier for the screen/privacy mode. It specifies\n" " that if callerID is present, do not screen the call.\n" -" o - Specify that the CallerID that was present on the *calling* channel\n" -" be set as the CallerID on the *called* channel. This was the\n" -" behavior of Asterisk 1.0 and earlier.\n" " O([x]) - \"Operator Services\" mode (Zaptel channel to Zaptel channel\n" " only, if specified on non-Zaptel interface, it will be ignored).\n" " When the destination answers (presumably an operator services\n" @@ -239,16 +235,17 @@ OPT_RESETCDR = (1 << 1), OPT_DTMF_EXIT = (1 << 2), OPT_SENDDTMF = (1 << 3), - OPT_FORCECLID = (1 << 4), + OPT_FORCE_CALLERID = (1 << 4), OPT_GO_ON = (1 << 5), OPT_CALLEE_HANGUP = (1 << 6), OPT_CALLER_HANGUP = (1 << 7), + OPT_PEER_H = (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), @@ -269,9 +266,10 @@ #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, @@ -285,6 +283,7 @@ OPT_ARG_PRIVACY, OPT_ARG_DURATION_STOP, OPT_ARG_OPERMODE, + OPT_ARG_FORCE_CALLERID, /* note: this entry _MUST_ be the last one in the enum */ OPT_ARG_ARRAY_SIZE, }; @@ -296,7 +295,7 @@ AST_APP_OPTION('d', OPT_DTMF_EXIT), AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF), AST_APP_OPTION('e', OPT_PEER_H), - AST_APP_OPTION('f', OPT_FORCECLID), + AST_APP_OPTION_ARG('f', OPT_FORCE_CALLERID, OPT_ARG_FORCE_CALLERID), AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON), AST_APP_OPTION('g', OPT_GO_ON), AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO), @@ -311,8 +310,7 @@ 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('o', OPT_ORIGINAL_CLID), + AST_APP_OPTION('N', OPT_SCREEN_NOCALLERID), AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE), AST_APP_OPTION('p', OPT_SCREENING), AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY), @@ -428,15 +426,6 @@ 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); - const char *exten = S_OR(chan->macroexten, chan->exten); - - return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : ""; -} - static void senddialevent(struct ast_channel *src, struct ast_channel *dst, const char *dialstring) { manager_event(EVENT_FLAG_CALL, "Dial", @@ -512,28 +501,20 @@ ast_clear_flag64(o, DIAL_STILLGOING); handle_cause(cause, num); } else { - char *new_cid_num, *new_cid_name; - struct ast_channel *src; - ast_rtp_make_compatible(c, in, single); - 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 */ - } else { - new_cid_num = ast_strdup(in->cid.cid_num); - new_cid_name = ast_strdup(in->cid.cid_name); - src = in; - } - 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); - 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_num, ast_strdup(in->cid.cid_num)); + S_REPLACE(c->cid.cid_name, ast_strdup(in->cid.cid_name)); + 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))); + + c->cid.cid_pres = in->cid.cid_pres; + c->cid.cid_ton = in->cid.cid_ton; + c->cid.cid_tns = in->cid.cid_tns; + c->cid.cid_ani2 = in->cid.cid_ani2; + + ast_set_connectedline(c, in->lid.lid_num, in->lid.lid_name, in->lid.lid_pres); + 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); @@ -542,11 +523,6 @@ 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); - } /* Hangup the original channel now, in case we needed it */ ast_hangup(original); } @@ -572,16 +548,21 @@ 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 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_connectedline_update(in, outgoing->chan->cid.cid_num, outgoing->chan->cid.cid_name, outgoing->chan->cid.cid_pres); } #ifdef HAVE_EPOLL @@ -628,6 +609,8 @@ 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) && !ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) + ast_connectedline_update(in, c->cid.cid_num, c->cid.cid_name, c->cid.cid_pres); peer = c; ast_copy_flags64(peerflags, o, OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | @@ -666,6 +649,8 @@ /* 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) && !ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) + ast_connectedline_update(in, c->cid.cid_num, c->cid.cid_name, c->cid.cid_pres); peer = c; ast_copy_flags64(peerflags, o, OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | @@ -726,6 +711,14 @@ 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_CONNECTEDLINE: + if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { + ast_verb(3, "Connected line ID update to %s prevented.\n", in->name); + } else if (single) { + ast_verb(3, "%s connected line ID has changed, passing it to %s\n", c->name, in->name); + ast_indicate_data(in, AST_CONTROL_CONNECTEDLINE, f->data, 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)) @@ -832,7 +825,8 @@ ((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_CONNECTEDLINE))) { 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, f->datalen); } @@ -1141,11 +1135,11 @@ 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); } @@ -1229,7 +1223,7 @@ struct cause_args num = { chan, 0, 0, 0 }; int cause; char numsubst[256]; - char cidname[AST_MAX_EXTENSION] = ""; + char *cid_num = NULL, *cid_name = NULL; struct ast_bridge_config config = { { 0, } }; unsigned int calldurationlimit = 0; @@ -1306,6 +1300,8 @@ goto done; } + if (ast_test_flag64(&opts, OPT_FORCE_CALLERID) && !ast_strlen_zero(opt_args[OPT_ARG_FORCE_CALLERID])) + ast_callerid_parse(opt_args[OPT_ARG_FORCE_CALLERID], &cid_name, &cid_num); if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr) ast_cdr_reset(chan->cdr, NULL); if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY])) @@ -1329,7 +1325,7 @@ outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"); } - 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_CALLER_HANGUP | OPT_IGNORE_FORWARDING); /* Create datastore for channel dial features for caller */ if (!(ds_caller_features = ast_channel_datastore_alloc(&dial_features_info, NULL))) { @@ -1381,7 +1377,7 @@ OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | OPT_CALLER_PARK | OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | - OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID); + OPT_RINGBACK | OPT_MUSICBACK); ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML); } ast_copy_string(numsubst, number, sizeof(numsubst)); @@ -1471,22 +1467,39 @@ tc->data = "(Outgoing Line)"; tc->whentohangup = 0; - 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 (ast_strlen_zero(tc->cid.cid_num)) { + if (!ast_strlen_zero(chan->lid.lid_num)) { + ast_set_callerid(tc, chan->lid.lid_num, chan->lid.lid_name, chan->lid.lid_ani); + tc->lid.lid_pres = chan->cid.cid_pres; + } 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); + } + + if (ast_test_flag64(peerflags, OPT_FORCE_CALLERID)) + ast_set_connectedline(tc, cid_num, cid_name, AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN); + else { + S_REPLACE(tc->lid.lid_num, ast_strdup(chan->cid.cid_num)); + S_REPLACE(tc->lid.lid_name, ast_strdup(chan->cid.cid_name)); + S_REPLACE(tc->lid.lid_ani, ast_strdup(chan->cid.cid_ani)); + S_REPLACE(tc->lid.lid_rdnis, ast_strdup(chan->cid.cid_rdnis)); + + tc->lid.lid_pres = chan->cid.cid_pres; + tc->lid.lid_ton = chan->cid.cid_ton; + tc->lid.lid_tns = chan->cid.cid_tns; + tc->lid.lid_ani2 = chan->cid.cid_ani2; + } + /* Copy language from incoming to outgoing */ ast_string_field_set(tc, language, chan->language); 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; @@ -1546,8 +1559,6 @@ } else { senddialevent(chan, tc, numsubst); ast_verb(3, "Called %s\n", numsubst); - 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); } /* 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: apps/app_queue.c =================================================================== --- apps/app_queue.c (revision 114099) +++ apps/app_queue.c (working copy) @@ -2171,16 +2171,39 @@ tmp->chan->appl = "AppQueue"; tmp->chan->data = "(Outgoing Line)"; tmp->chan->whentohangup = 0; - 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 (ast_strlen_zero(tmp->chan->cid.cid_num)) { + if (!ast_strlen_zero(qe->chan->lid.lid_num)) { + ast_set_callerid(tmp->chan, qe->chan->lid.lid_num, qe->chan->lid.lid_name, qe->chan->lid.lid_ani); + tmp->chan->cid.cid_pres = qe->chan->lid.lid_pres; + } 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); + } + } + + if (tmp->chan->lid.lid_num) + ast_free(tmp->chan->lid.lid_num); + tmp->chan->lid.lid_num = ast_strdup(qe->chan->cid.cid_num); + + if (tmp->chan->lid.lid_name) + ast_free(tmp->chan->lid.lid_name); + tmp->chan->lid.lid_name = ast_strdup(qe->chan->cid.cid_name); + + if (tmp->chan->lid.lid_ani) + ast_free(tmp->chan->lid.lid_ani); + tmp->chan->lid.lid_ani = ast_strdup(qe->chan->cid.cid_ani); + + if (tmp->chan->lid.lid_rdnis) + ast_free(tmp->chan->lid.lid_rdnis); + tmp->chan->lid.lid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis); + + tmp->chan->lid.lid_pres = qe->chan->cid.cid_pres; + tmp->chan->lid.lid_ton = qe->chan->cid.cid_ton; + tmp->chan->lid.lid_tns = qe->chan->cid.cid_tns; + tmp->chan->lid.lid_ani2 = qe->chan->cid.cid_ani2; + /* Inherit specially named variables from parent channel */ ast_channel_inherit_variables(qe->chan, tmp->chan); @@ -2542,6 +2565,7 @@ } else { 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); @@ -2550,17 +2574,21 @@ 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 (o->chan->cid.cid_ani) + ast_free(o->chan->cid.cid_ani); + o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); - 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); - } 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_pres = in->cid.cid_pres; + o->chan->cid.cid_ton = in->cid.cid_ton; + o->chan->cid.cid_tns = in->cid.cid_tns; + o->chan->cid.cid_ani2 = in->cid.cid_ani2; + + ast_set_connectedline(o->chan, in->lid.lid_num, in->lid.lid_name, in->lid.lid_pres); + 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); Index: funcs/func_connectedline.c =================================================================== --- funcs/func_connectedline.c (revision 0) +++ funcs/func_connectedline.c (revision 0) @@ -0,0 +1,131 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2007, Gareth Palmer + * + * Gareth Palmer + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Connected Line ID dialplan function + * + * \ingroup functions + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 00001 $") + +#include +#include +#include +#include + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/options.h" +#include "asterisk/callerid.h" + +static int connectedline_read(struct ast_channel *chan, const char *cmd, char *data, + char *buf, size_t len) +{ + if (!chan) + return -1; + + if (!strncasecmp("all", data, 3)) { + snprintf(buf, len, "\"%s\" <%s>", + S_OR(chan->lid.lid_name, ""), + S_OR(chan->lid.lid_num, "")); + } else if (!strncasecmp("name", data, 4)) { + if (chan->lid.lid_name) { + ast_copy_string(buf, chan->lid.lid_name, len); + } + } else if (!strncasecmp("num", data, 3)) { + if (chan->lid.lid_num) { + ast_copy_string(buf, chan->lid.lid_num, len); + } + } else if (!strncasecmp("pres", data, 4)) { + ast_copy_string(buf, ast_named_caller_presentation(chan->lid.lid_pres), len); + } else { + ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data); + } + + return 0; +} + +static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data, + const char *value) +{ + if (!value || !chan) + return -1; + + if (!strncasecmp("all", data, 3)) { + char name[256]; + char num[256]; + + if (!ast_callerid_split(value, name, sizeof(name), num, sizeof(num))) + ast_connectedline_update(chan, num, name, chan->lid.lid_pres); + } else if (!strncasecmp("name", data, 4)) { + ast_connectedline_update(chan, chan->lid.lid_num, value, chan->lid.lid_pres); + } else if (!strncasecmp("num", data, 3)) { + ast_connectedline_update(chan, value, chan->lid.lid_name, chan->lid.lid_pres); + } else if (!strncasecmp("pres", data, 4)) { + char *tmp; + int pres; + + tmp = ast_strdupa(value); + ast_trim_blanks(tmp); + + if ((tmp[0] >= '0') && (tmp[0] <= '9')) + pres = atoi(tmp); + else + pres = ast_parse_caller_presentation(tmp); + + if (pres < 0) + ast_log(LOG_ERROR, "Unknown called number presentation '%s', value unchanged\n", tmp); + else + ast_connectedline_update(chan, chan->lid.lid_num, chan->lid.lid_name, pres); + } else { + ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data); + } + + return 0; +} + +static struct ast_custom_function connectedline_function = { + .name = "CONNECTEDLINE", + .synopsis = "Gets or sets Connected Line ID data on the channel.", + .syntax = "CONNECTEDLINE(datatype)", + .desc = + "Gets or sets Connected Line ID data on the channel. The allowable\n" + "datatypes are \"all\", \"name\", \"num\" and \"pres\"\n", + .read = connectedline_read, + .write = connectedline_write, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&connectedline_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&connectedline_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Connected Line ID dialplan function"); Index: include/asterisk/channel.h =================================================================== --- include/asterisk/channel.h (revision 114099) +++ include/asterisk/channel.h (working copy) @@ -244,6 +244,23 @@ int cid_tns; /*!< Callerid Transit Network Select */ }; +/* \brief Structure for all kinds of connected line ID indentifications. + * \note All string fields here are malloc'ed, so they need to be + * freed when the structure is deleted. + * Also, NULL and "" must be considered equivalent. + */ +struct ast_connectedline { + char *lid_dnid; /*!< Malloc'd Dialed Number Identifier */ + char *lid_num; /*!< Malloc'd Line Number */ + char *lid_name; /*!< Malloc'd Line Name */ + char *lid_ani; /*!< Malloc'd ANI */ + char *lid_rdnis; /*!< Malloc'd RDNIS */ + int lid_pres; /*!< Line presentation/screening */ + int lid_ani2; /*!< Line ANI 2 (Info digits) */ + int lid_ton; /*!< Line Type of Number */ + int lid_tns; /*!< Line Transit Network Select */ +}; + /*! \brief Structure to describe a channel "technology", ie a channel driver See for examples: @@ -476,6 +493,7 @@ enum ast_channel_state _state; /*!< State of line -- Don't write directly, use ast_setstate() */ int rings; /*!< Number of rings so far */ struct ast_callerid cid; /*!< Caller ID, name, presentation etc */ + struct ast_connectedline lid; /*!< Connected Line ID, name, presentation etc */ char dtmfq[AST_MAX_EXTENSION]; /*!< Any/all queued DTMF characters */ struct ast_frame dtmff; /*!< DTMF frame */ @@ -1641,7 +1659,35 @@ AST_LIST_ENTRY(ast_group_info) list; }; +/*! + * \brief Set connected line ID number, name and presentation + * + * \note The channel does not need to be locked before calling this function. + */ +void ast_set_connectedline(struct ast_channel *chan, const char *lid_num, const char *lid_name, int lid_pres); +/*! \brief Element types for connected line ID control frames */ +enum { + AST_CONNECTEDLINE_NUMBER = 0, + AST_CONNECTEDLINE_NAME = 1, + AST_CONNECTEDLINE_PRESENTATION = 2, +}; + +/*! + * \brief Indicate that the connected line ID has changed + */ +void ast_connectedline_update(struct ast_channel *chan, const char *cid_num, const char *cid_name, int cid_pres); + +/* + * \brief Queue a connected line ID indication frame on a channel + */ +void ast_queue_connectedline_update(struct ast_channel *chan, const char *cid_num, const char *cid_name, int cid_pres); + +/*! + * \brief Parse connected line ID indication frame data + */ +int ast_parse_connectedline_data(unsigned char *data, size_t datalen, char *cid_num, int numlen, char *cid_name, int namelen, int *cid_pres); + #if defined(__cplusplus) || defined(c_plusplus) } #endif Index: include/asterisk/frame.h =================================================================== --- include/asterisk/frame.h (revision 114099) +++ include/asterisk/frame.h (working copy) @@ -84,6 +84,7 @@ \arg \b UNHOLD Call is back from hold \arg \b VIDUPDATE Video update requested \arg \b SRCUPDATE The source of media has changed + \arg \b CONNECTEDLINE Connected line ID has changed */ @@ -295,6 +296,7 @@ AST_CONTROL_VIDUPDATE = 18, /*!< Indicate video frame update */ AST_CONTROL_T38 = 19, /*!< T38 state change request/notification */ AST_CONTROL_SRCUPDATE = 20, /*!< Indicate source of media has changed */ + AST_CONTROL_CONNECTEDLINE = 21 /*!< Indicate connected line id has change */ }; enum ast_control_t38 { Index: main/channel.c =================================================================== --- main/channel.c (revision 114099) +++ main/channel.c (working copy) @@ -1237,6 +1237,21 @@ cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = cid->cid_rdnis = NULL; } +static void free_lid(struct ast_connectedline *lid) +{ + if (lid->lid_dnid) + ast_free(lid->lid_dnid); + if (lid->lid_num) + ast_free(lid->lid_num); + if (lid->lid_name) + ast_free(lid->lid_name); + if (lid->lid_ani) + ast_free(lid->lid_ani); + if (lid->lid_rdnis) + ast_free(lid->lid_rdnis); + lid->lid_dnid = lid->lid_num = lid->lid_name = lid->lid_ani = lid->lid_rdnis = NULL; +} + /*! \brief Free a channel structure */ void ast_channel_free(struct ast_channel *chan) { @@ -1298,6 +1313,7 @@ if (chan->pbx) ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name); free_cid(&chan->cid); + free_lid(&chan->lid); /* Close pipes if appropriate */ if ((fd = chan->alertpipe[0]) > -1) close(fd); @@ -2777,6 +2793,13 @@ /* Do nothing.... */ } else if (condition == AST_CONTROL_SRCUPDATE) { /* Do nothing... */ + } else if (condition == AST_CONTROL_CONNECTEDLINE) { + char lid_num[80], lid_name[80]; + int lid_pres; + + if (!ast_parse_connectedline_data((unsigned char *) data, datalen, lid_num, sizeof(lid_num), lid_name, sizeof(lid_name), &lid_pres)) + ast_set_connectedline(chan, lid_num, lid_name, lid_pres); + res = 0; } else { /* not handled */ ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name); @@ -3257,10 +3280,10 @@ if (oh->account) ast_cdr_setaccount(chan, oh->account); } + ast_set_callerid(chan, cid_num, cid_name, cid_num); + ast_set_connectedline(chan, cid_num, cid_name, AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED); - - if (!chan->cdr) { /* up till now, this insertion hasn't been done. Therefore, to keep from throwing off the basic order of the universe, we will try to keep this cdr from getting posted. */ @@ -3305,6 +3328,7 @@ case AST_CONTROL_UNHOLD: case AST_CONTROL_VIDUPDATE: case AST_CONTROL_SRCUPDATE: + case AST_CONTROL_CONNECTEDLINE: case -1: /* Ignore -- just stopping indications */ break; @@ -4196,6 +4220,7 @@ case AST_CONTROL_UNHOLD: case AST_CONTROL_VIDUPDATE: case AST_CONTROL_SRCUPDATE: + case AST_CONTROL_CONNECTEDLINE: ast_indicate_data(other, f->subclass, f->data, f->datalen); break; default: @@ -5090,3 +5115,146 @@ return ast_say_digit_str_full(chan, buf, ints, lang, audiofd, ctrlfd); } + +void ast_set_connectedline(struct ast_channel *chan, const char *lid_num, const char *lid_name, int lid_pres) +{ + ast_channel_lock(chan); + + if (lid_num) { + if (chan->lid.lid_num) + ast_free(chan->lid.lid_num); + chan->lid.lid_num = ast_strdup(lid_num); + } + if (lid_name) { + if (chan->lid.lid_name) + ast_free(chan->lid.lid_name); + chan->lid.lid_name = ast_strdup(lid_name); + } + chan->lid.lid_pres = lid_pres; + + ast_channel_unlock(chan); +} + +static int ast_build_connectedline_data(unsigned char *data, size_t datalen, const char *lid_num, const char *lid_name, int lid_pres) +{ + int numlen, namelen, pos = 0; + + lid_pres = htonl(lid_pres); + + if (lid_num && (numlen = strlen(lid_num)) > 0) { + if (pos + (sizeof(data[0]) * 2) + numlen > datalen) { + ast_log(LOG_WARNING, "No space left for connected line number\n"); + return -1; + } + data[pos++] = AST_CONNECTEDLINE_NUMBER; + data[pos++] = numlen; + memcpy(data + pos, lid_num, numlen); + pos += numlen; + } + + if (lid_name && (namelen = strlen(lid_name)) > 0) { + if (pos + (sizeof(data[0]) * 2) + namelen > datalen) { + ast_log(LOG_WARNING, "No space left for connected line name\n"); + return -1; + } + data[pos++] = AST_CONNECTEDLINE_NAME; + data[pos++] = namelen; + memcpy(data + pos, lid_name, namelen); + pos += namelen; + } + + if (pos + (sizeof(data[0]) * 2) + sizeof(lid_pres) > datalen) { + ast_log(LOG_WARNING, "No space left for connected line presentation"); + return -1; + } + data[pos++] = AST_CONNECTEDLINE_PRESENTATION; + data[pos++] = sizeof(lid_pres); + memcpy(data + pos, &lid_pres, sizeof(lid_pres)); + pos += sizeof(lid_pres); + + return pos; +} + +void ast_connectedline_update(struct ast_channel *chan, const char *lid_num, const char *lid_name, int lid_pres) +{ + unsigned char data[1024]; + size_t datalen; + + if ((datalen = ast_build_connectedline_data(data, sizeof(data), lid_num, lid_name, lid_pres)) == -1) + return; + + ast_indicate_data(chan, AST_CONTROL_CONNECTEDLINE, (void *) data, datalen); +} + +void ast_queue_connectedline_update(struct ast_channel *chan, const char *lid_num, const char *lid_name, int lid_pres) +{ + unsigned char data[1024]; + size_t datalen; + + if ((datalen = ast_build_connectedline_data(data, sizeof(data), lid_num, lid_name, lid_pres)) == -1) + return; + + ast_queue_control_data(chan, AST_CONTROL_CONNECTEDLINE, (void *) data, datalen); +} + +int ast_parse_connectedline_data(unsigned char *data, size_t datalen, char *lid_num, int numlen, char *lid_name, int namelen, int *lid_pres) { + int pos; + unsigned char id, idlen; + + if (numlen > 0) + lid_num[0] = '\0'; + if (namelen > 0) + lid_name[0] = '\0'; + if (lid_pres) + *lid_pres = 0; + + for (pos = 0; pos < datalen; pos += idlen) { + if (pos + sizeof(id) + sizeof(idlen) > datalen) { + ast_log(LOG_WARNING, "Invalid connected line ID update\n"); + return -1; + } + id = data[pos++], idlen = data[pos++]; + if (pos + idlen > datalen) { + ast_log(LOG_WARNING, "Invalid connected line ID update\n"); + return -1; + } + + switch (id) { + case AST_CONNECTEDLINE_NUMBER: + if (lid_num && numlen > 0) { + if (idlen >= (numlen - 1)) { + ast_log(LOG_WARNING, "Connected line number too large (%d)\n", idlen); + break; + } + memcpy(lid_num, data + pos, idlen); + lid_num[idlen] = '\0'; + } + break; + case AST_CONNECTEDLINE_NAME: + if (lid_name && namelen > 0) { + if (idlen >= (namelen - 1)) { + ast_log(LOG_WARNING, "Connected line name too large (%d)\n", idlen); + break; + } + memcpy(lid_name, data + pos, idlen); + lid_name[idlen] = '\0'; + } + break; + case AST_CONNECTEDLINE_PRESENTATION: + if (lid_pres) { + if (idlen != sizeof(*lid_pres)) { + ast_log(LOG_WARNING, "Invalid connected line presentation (%d)\n", idlen); + break; + } + memcpy(lid_pres, data + pos, sizeof(lid_pres)); + *lid_pres = ntohl(*lid_pres); + } + break; + default: + ast_log(LOG_DEBUG, "Unknown connected line ID element: %d (%d)\n", id, idlen); + break; + } + } + + return 0; +} Index: main/features.c =================================================================== --- main/features.c (revision 114099) +++ main/features.c (working copy) @@ -3257,6 +3257,8 @@ } if (cur) { ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); + ast_connectedline_update(chan, cur->lid.lid_num, cur->lid.lid_name, cur->lid.lid_pres); + ast_queue_connectedline_update(chan, chan->cid.cid_num, chan->cid.cid_name, chan->cid.cid_pres); res = ast_answer(chan); if (res) ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); Index: main/rtp.c =================================================================== --- main/rtp.c (revision 114099) +++ main/rtp.c (working copy) @@ -3387,7 +3387,8 @@ (fr->subclass == AST_CONTROL_UNHOLD) || (fr->subclass == AST_CONTROL_VIDUPDATE) || (fr->subclass == AST_CONTROL_T38) || - (fr->subclass == AST_CONTROL_SRCUPDATE)) { + (fr->subclass == AST_CONTROL_SRCUPDATE) || + (fr->subclass == AST_CONTROL_CONNECTEDLINE)) { if (fr->subclass == AST_CONTROL_HOLD) { /* If we someone went on hold we want the other side to reinvite back to us */ if (who == c0) @@ -3627,7 +3628,8 @@ (fr->subclass == AST_CONTROL_UNHOLD) || (fr->subclass == AST_CONTROL_VIDUPDATE) || (fr->subclass == AST_CONTROL_T38) || - (fr->subclass == AST_CONTROL_SRCUPDATE)) { + (fr->subclass == AST_CONTROL_SRCUPDATE) || + (fr->subclass == AST_CONTROL_CONNECTEDLINE)) { /* If we are going on hold, then break callback mode and P2P bridging */ if (fr->subclass == AST_CONTROL_HOLD) { if (p0_callback) Index: main/dial.c =================================================================== --- main/dial.c (revision 114099) +++ main/dial.c (working copy) @@ -273,10 +273,10 @@ ast_channel_inherit_variables(chan, channel->owner); /* Copy over callerid information */ - S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num)); - S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name)); - S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani)); - S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis)); + S_REPLACE(channel->owner->lid.lid_num, ast_strdup(chan->cid.cid_num)); + S_REPLACE(channel->owner->lid.lid_name, ast_strdup(chan->cid.cid_name)); + S_REPLACE(channel->owner->lid.lid_ani, ast_strdup(chan->cid.cid_ani)); + S_REPLACE(channel->owner->lid.lid_rdnis, ast_strdup(chan->cid.cid_rdnis)); ast_string_field_set(channel->owner, language, chan->language); ast_string_field_set(channel->owner, accountcode, chan->accountcode); @@ -284,9 +284,10 @@ if (ast_strlen_zero(channel->owner->musicclass)) ast_string_field_set(channel->owner, musicclass, chan->musicclass); - channel->owner->cid.cid_pres = chan->cid.cid_pres; - channel->owner->cid.cid_ton = chan->cid.cid_ton; - channel->owner->cid.cid_tns = chan->cid.cid_tns; + channel->owner->lid.lid_pres = chan->cid.cid_pres; + channel->owner->lid.lid_ton = chan->cid.cid_ton; + channel->owner->lid.lid_tns = chan->cid.cid_tns; + channel->owner->lid.lid_ani2 = chan->cid.cid_ani2; channel->owner->adsicpe = chan->adsicpe; channel->owner->transfercapability = chan->transfercapability; } @@ -428,6 +429,10 @@ ast_verbose (VERBOSE_PREFIX_3 "%s requested a source update, passing it to %s\n", channel->owner->name, chan->name); ast_indicate(chan, AST_CONTROL_SRCUPDATE); break; + case AST_CONTROL_CONNECTEDLINE: + ast_verb(3, "%s connected line ID has changed, passing it to %s\n", channel->owner->name, chan->name); + ast_indicate_data(chan, AST_CONTROL_CONNECTEDLINE, fr->data, fr->datalen); + break; case AST_CONTROL_PROCEEDING: ast_verb(3, "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name); ast_indicate(chan, AST_CONTROL_PROCEEDING);