diff options
Diffstat (limited to 'main/channel.c')
-rw-r--r-- | main/channel.c | 1943 |
1 files changed, 1227 insertions, 716 deletions
diff --git a/main/channel.c b/main/channel.c index ba420fbb9..51cbd553b 100644 --- a/main/channel.c +++ b/main/channel.c @@ -72,9 +72,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include <sys/epoll.h> #endif +#if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) #if defined(HAVE_PRI) #include "libpri.h" #endif /* defined(HAVE_PRI) */ +#endif /* defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) */ struct ast_epoll_data { struct ast_channel *chan; @@ -139,6 +141,7 @@ static AST_RWLIST_HEAD_STATIC(backends, chanlist); #define NUM_CHANNEL_BUCKETS 1567 #endif +#if 0 /* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */ #define DATA_EXPORT_CALLERID(MEMBER) \ MEMBER(ast_callerid, cid_dnid, AST_DATA_STRING) \ MEMBER(ast_callerid, cid_num, AST_DATA_STRING) \ @@ -149,6 +152,7 @@ static AST_RWLIST_HEAD_STATIC(backends, chanlist); MEMBER(ast_callerid, cid_tag, AST_DATA_STRING) AST_DATA_STRUCTURE(ast_callerid, DATA_EXPORT_CALLERID); +#endif #define DATA_EXPORT_CHANNEL(MEMBER) \ MEMBER(ast_channel, blockproc, AST_DATA_STRING) \ @@ -283,6 +287,7 @@ static void channel_data_add_flags(struct ast_data *tree, ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS)); } +#if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) static const char *party_number_ton2str(int ton) { #if defined(HAVE_PRI) @@ -306,7 +311,9 @@ static const char *party_number_ton2str(int ton) #endif /* defined(HAVE_PRI) */ return "Unknown"; } +#endif /* defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) */ +#if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) static const char *party_number_plan2str(int plan) { #if defined(HAVE_PRI) @@ -330,14 +337,22 @@ static const char *party_number_plan2str(int plan) #endif /* defined(HAVE_PRI) */ return "Unknown"; } +#endif /* defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) */ int ast_channel_data_add_structure(struct ast_data *tree, struct ast_channel *chan, int add_bridged) { struct ast_channel *bc; - struct ast_data *data_bridged, *data_cdr, *data_flags, *data_zones; - struct ast_data *data_callerid, *enum_node, *data_softhangup; + struct ast_data *data_bridged; + struct ast_data *data_cdr; + struct ast_data *data_flags; + struct ast_data *data_zones; + struct ast_data *enum_node; + struct ast_data *data_softhangup; +#if 0 /* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */ + struct ast_data *data_callerid; char value_str[100]; +#endif if (!tree) { return -1; @@ -417,6 +432,7 @@ int ast_channel_data_add_structure(struct ast_data *tree, ast_data_add_uint(tree, "timetohangup", chan->whentohangup.tv_sec); +#if 0 /* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */ /* callerid */ data_callerid = ast_data_add_node(tree, "callerid"); if (!data_callerid) { @@ -433,6 +449,7 @@ int ast_channel_data_add_structure(struct ast_data *tree, party_number_ton2str(chan->cid.cid_ton), party_number_plan2str(chan->cid.cid_ton)); ast_data_add_str(enum_node, "text", value_str); +#endif /* tone zone */ if (chan->zone) { @@ -1090,13 +1107,22 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char return ast_channel_unref(tmp); } + ast_party_dialed_init(&tmp->dialed); + ast_party_caller_init(&tmp->caller); + ast_party_connected_line_init(&tmp->connected); + ast_party_redirecting_init(&tmp->redirecting); + if (cid_name) { - if (!(tmp->cid.cid_name = ast_strdup(cid_name))) { + tmp->caller.id.name.valid = 1; + tmp->caller.id.name.str = ast_strdup(cid_name); + if (!tmp->caller.id.name.str) { return ast_channel_unref(tmp); } } if (cid_num) { - if (!(tmp->cid.cid_num = ast_strdup(cid_num))) { + tmp->caller.id.number.valid = 1; + tmp->caller.id.number.str = ast_strdup(cid_num); + if (!tmp->caller.id.number.str) { return ast_channel_unref(tmp); } } @@ -1762,23 +1788,6 @@ int ast_safe_sleep(struct ast_channel *chan, int ms) return ast_safe_sleep_conditional(chan, ms, NULL, NULL); } -static void free_cid(struct ast_callerid *cid) -{ - if (cid->cid_dnid) - ast_free(cid->cid_dnid); - if (cid->cid_num) - ast_free(cid->cid_num); - if (cid->cid_name) - ast_free(cid->cid_name); - if (cid->cid_ani) - ast_free(cid->cid_ani); - if (cid->cid_tag) - ast_free(cid->cid_tag); - cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = NULL; - ast_party_subaddress_free(&cid->subaddress); - ast_party_subaddress_free(&cid->dialed_subaddress); -} - struct ast_channel *ast_channel_release(struct ast_channel *chan) { /* Safe, even if already unlinked. */ @@ -1786,6 +1795,112 @@ struct ast_channel *ast_channel_release(struct ast_channel *chan) return ast_channel_unref(chan); } +void ast_party_name_init(struct ast_party_name *init) +{ + init->str = NULL; + init->char_set = AST_PARTY_CHAR_SET_ISO8859_1; + init->presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + init->valid = 0; +} + +void ast_party_name_copy(struct ast_party_name *dest, const struct ast_party_name *src) +{ + if (dest == src) { + /* Don't copy to self */ + return; + } + + ast_free(dest->str); + dest->str = ast_strdup(src->str); + dest->char_set = src->char_set; + dest->presentation = src->presentation; + dest->valid = src->valid; +} + +void ast_party_name_set_init(struct ast_party_name *init, const struct ast_party_name *guide) +{ + init->str = NULL; + init->char_set = guide->char_set; + init->presentation = guide->presentation; + init->valid = guide->valid; +} + +void ast_party_name_set(struct ast_party_name *dest, const struct ast_party_name *src) +{ + if (dest == src) { + /* Don't set to self */ + return; + } + + if (src->str && src->str != dest->str) { + ast_free(dest->str); + dest->str = ast_strdup(src->str); + } + + dest->char_set = src->char_set; + dest->presentation = src->presentation; + dest->valid = src->valid; +} + +void ast_party_name_free(struct ast_party_name *doomed) +{ + ast_free(doomed->str); + doomed->str = NULL; +} + +void ast_party_number_init(struct ast_party_number *init) +{ + init->str = NULL; + init->plan = 0;/* Unknown */ + init->presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + init->valid = 0; +} + +void ast_party_number_copy(struct ast_party_number *dest, const struct ast_party_number *src) +{ + if (dest == src) { + /* Don't copy to self */ + return; + } + + ast_free(dest->str); + dest->str = ast_strdup(src->str); + dest->plan = src->plan; + dest->presentation = src->presentation; + dest->valid = src->valid; +} + +void ast_party_number_set_init(struct ast_party_number *init, const struct ast_party_number *guide) +{ + init->str = NULL; + init->plan = guide->plan; + init->presentation = guide->presentation; + init->valid = guide->valid; +} + +void ast_party_number_set(struct ast_party_number *dest, const struct ast_party_number *src) +{ + if (dest == src) { + /* Don't set to self */ + return; + } + + if (src->str && src->str != dest->str) { + ast_free(dest->str); + dest->str = ast_strdup(src->str); + } + + dest->plan = src->plan; + dest->presentation = src->presentation; + dest->valid = src->valid; +} + +void ast_party_number_free(struct ast_party_number *doomed) +{ + ast_free(doomed->str); + doomed->str = NULL; +} + void ast_party_subaddress_init(struct ast_party_subaddress *init) { init->str = NULL; @@ -1801,9 +1916,7 @@ void ast_party_subaddress_copy(struct ast_party_subaddress *dest, const struct a return; } - if (dest->str) { - ast_free(dest->str); - } + ast_free(dest->str); dest->str = ast_strdup(src->str); dest->type = src->type; dest->odd_even_indicator = src->odd_even_indicator; @@ -1826,9 +1939,7 @@ void ast_party_subaddress_set(struct ast_party_subaddress *dest, const struct as } if (src->str && src->str != dest->str) { - if (dest->str) { - ast_free(dest->str); - } + ast_free(dest->str); dest->str = ast_strdup(src->str); } @@ -1839,207 +1950,236 @@ void ast_party_subaddress_set(struct ast_party_subaddress *dest, const struct as void ast_party_subaddress_free(struct ast_party_subaddress *doomed) { - if (doomed->str) { - ast_free(doomed->str); - doomed->str = NULL; - } + ast_free(doomed->str); + doomed->str = NULL; } void ast_party_id_init(struct ast_party_id *init) { - init->number = NULL; - init->name = NULL; - init->tag = NULL; - init->number_type = 0; /* Unknown */ - init->number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + ast_party_name_init(&init->name); + ast_party_number_init(&init->number); ast_party_subaddress_init(&init->subaddress); + init->tag = NULL; } -/*! - * \internal - * \brief Copy the source party id information to the destination party id. - * - * \param dest Destination party id - * \param src Source party id - * - * \return Nothing - */ -static void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src) +void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src) { if (dest == src) { /* Don't copy to self */ return; } - if (dest->number) { - ast_free(dest->number); - } - dest->number = ast_strdup(src->number); - - if (dest->name) { - ast_free(dest->name); - } - dest->name = ast_strdup(src->name); + ast_party_name_copy(&dest->name, &src->name); + ast_party_number_copy(&dest->number, &src->number); + ast_party_subaddress_copy(&dest->subaddress, &src->subaddress); - if (dest->tag) { - ast_free(dest->tag); - } + ast_free(dest->tag); dest->tag = ast_strdup(src->tag); - - dest->number_type = src->number_type; - dest->number_presentation = src->number_presentation; - ast_party_subaddress_copy(&dest->subaddress, &src->subaddress); } -/*! - * \internal - * \brief Initialize the given party id structure using the given guide - * for a set update operation. - * - * \details - * The initialization is needed to allow a set operation to know if a - * value needs to be updated. Simple integers need the guide's original - * value in case the set operation is not trying to set a new value. - * String values are simply set to NULL pointers if they are not going - * to be updated. - * - * \param init Party id structure to initialize. - * \param guide Source party id to use as a guide in initializing. - * - * \return Nothing - */ -static void ast_party_id_set_init(struct ast_party_id *init, const struct ast_party_id *guide) +void ast_party_id_set_init(struct ast_party_id *init, const struct ast_party_id *guide) { - init->number = NULL; - init->name = NULL; - init->tag = NULL; - init->number_type = guide->number_type; - init->number_presentation = guide->number_presentation; + ast_party_name_set_init(&init->name, &guide->name); + ast_party_number_set_init(&init->number, &guide->number); ast_party_subaddress_set_init(&init->subaddress, &guide->subaddress); + init->tag = NULL; } -/*! - * \internal - * \brief Set the source party id information into the destination party id. - * - * \param dest Destination party id - * \param src Source party id - * - * \return Nothing - */ -static void ast_party_id_set(struct ast_party_id *dest, const struct ast_party_id *src) +void ast_party_id_set(struct ast_party_id *dest, const struct ast_party_id *src, const struct ast_set_party_id *update) { if (dest == src) { /* Don't set to self */ return; } - if (src->name && src->name != dest->name) { - if (dest->name) { - ast_free(dest->name); - } - dest->name = ast_strdup(src->name); + if (!update || update->name) { + ast_party_name_set(&dest->name, &src->name); } - - if (src->number && src->number != dest->number) { - if (dest->number) { - ast_free(dest->number); - } - dest->number = ast_strdup(src->number); + if (!update || update->number) { + ast_party_number_set(&dest->number, &src->number); + } + if (!update || update->subaddress) { + ast_party_subaddress_set(&dest->subaddress, &src->subaddress); } if (src->tag && src->tag != dest->tag) { - if (dest->tag) { - ast_free(dest->tag); - } + ast_free(dest->tag); dest->tag = ast_strdup(src->tag); } - - dest->number_type = src->number_type; - dest->number_presentation = src->number_presentation; - ast_party_subaddress_set(&dest->subaddress, &src->subaddress); } void ast_party_id_free(struct ast_party_id *doomed) { - if (doomed->number) { - ast_free(doomed->number); - doomed->number = NULL; + ast_party_name_free(&doomed->name); + ast_party_number_free(&doomed->number); + ast_party_subaddress_free(&doomed->subaddress); + + ast_free(doomed->tag); + doomed->tag = NULL; +} + +int ast_party_id_presentation(const struct ast_party_id *id) +{ + int number_priority; + int number_value; + int number_screening; + int name_priority; + int name_value; + + /* Determine name presentation priority. */ + if (!id->name.valid) { + name_value = AST_PRES_UNAVAILABLE; + name_priority = 3; + } else { + name_value = id->name.presentation & AST_PRES_RESTRICTION; + switch (name_value) { + case AST_PRES_RESTRICTED: + name_priority = 0; + break; + case AST_PRES_ALLOWED: + name_priority = 1; + break; + case AST_PRES_UNAVAILABLE: + name_priority = 2; + break; + default: + name_value = AST_PRES_UNAVAILABLE; + name_priority = 3; + break; + } } - if (doomed->name) { - ast_free(doomed->name); - doomed->name = NULL; + /* Determine number presentation priority. */ + if (!id->number.valid) { + number_screening = AST_PRES_USER_NUMBER_UNSCREENED; + number_value = AST_PRES_UNAVAILABLE; + number_priority = 3; + } else { + number_screening = id->number.presentation & AST_PRES_NUMBER_TYPE; + number_value = id->number.presentation & AST_PRES_RESTRICTION; + switch (number_value) { + case AST_PRES_RESTRICTED: + number_priority = 0; + break; + case AST_PRES_ALLOWED: + number_priority = 1; + break; + case AST_PRES_UNAVAILABLE: + number_priority = 2; + break; + default: + number_screening = AST_PRES_USER_NUMBER_UNSCREENED; + number_value = AST_PRES_UNAVAILABLE; + number_priority = 3; + break; + } } - if (doomed->tag) { - ast_free(doomed->tag); - doomed->tag = NULL; + /* Select the wining presentation value. */ + if (name_priority < number_priority) { + number_value = name_value; } - ast_party_subaddress_free(&doomed->subaddress); + + return number_value | number_screening; } -void ast_party_caller_init(struct ast_party_caller *init) +void ast_party_dialed_init(struct ast_party_dialed *init) { - ast_party_id_init(&init->id); - init->ani = NULL; - init->ani2 = 0; + init->number.str = NULL; + init->number.plan = 0;/* Unknown */ + ast_party_subaddress_init(&init->subaddress); + init->transit_network_select = 0; } -void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid *src) +void ast_party_dialed_copy(struct ast_party_dialed *dest, const struct ast_party_dialed *src) { if (dest == src) { /* Don't copy to self */ return; } -#if 1 - /* Copy caller-id specific information ONLY from struct ast_callerid */ - if (dest->cid_num) - { - ast_free(dest->cid_num); - } - dest->cid_num = ast_strdup(src->cid_num); + ast_free(dest->number.str); + dest->number.str = ast_strdup(src->number.str); + dest->number.plan = src->number.plan; + ast_party_subaddress_copy(&dest->subaddress, &src->subaddress); + dest->transit_network_select = src->transit_network_select; +} - if (dest->cid_name) - { - ast_free(dest->cid_name); - } - dest->cid_name = ast_strdup(src->cid_name); +void ast_party_dialed_set_init(struct ast_party_dialed *init, const struct ast_party_dialed *guide) +{ + init->number.str = NULL; + init->number.plan = guide->number.plan; + ast_party_subaddress_set_init(&init->subaddress, &guide->subaddress); + init->transit_network_select = guide->transit_network_select; +} - if (dest->cid_tag) { - ast_free(dest->cid_tag); +void ast_party_dialed_set(struct ast_party_dialed *dest, const struct ast_party_dialed *src) +{ + if (src->number.str && src->number.str != dest->number.str) { + ast_free(dest->number.str); + dest->number.str = ast_strdup(src->number.str); } - dest->cid_tag = ast_strdup(src->cid_tag); + dest->number.plan = src->number.plan; - dest->cid_ton = src->cid_ton; - dest->cid_pres = src->cid_pres; + ast_party_subaddress_set(&dest->subaddress, &src->subaddress); + dest->transit_network_select = src->transit_network_select; +} - if (dest->cid_ani) - { - ast_free(dest->cid_ani); +void ast_party_dialed_free(struct ast_party_dialed *doomed) +{ + ast_free(doomed->number.str); + doomed->number.str = NULL; + ast_party_subaddress_free(&doomed->subaddress); +} + +void ast_party_caller_init(struct ast_party_caller *init) +{ + ast_party_id_init(&init->id); + init->ani = NULL; + init->ani2 = 0; +} + +void ast_party_caller_copy(struct ast_party_caller *dest, const struct ast_party_caller *src) +{ + if (dest == src) { + /* Don't copy to self */ + return; } - dest->cid_ani = ast_strdup(src->cid_ani); - dest->cid_ani2 = src->cid_ani2; + ast_party_id_copy(&dest->id, &src->id); - ast_party_subaddress_copy(&dest->subaddress, &src->subaddress); + ast_free(dest->ani); + dest->ani = ast_strdup(src->ani); -#else + dest->ani2 = src->ani2; +} - /* The src and dest parameter types will become struct ast_party_caller ptrs. */ - /* This is future code */ +void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide) +{ + ast_party_id_set_init(&init->id, &guide->id); + init->ani = NULL; + init->ani2 = guide->ani2; +} - ast_party_id_copy(&dest->id, &src->id); +void ast_party_caller_set(struct ast_party_caller *dest, const struct ast_party_caller *src, const struct ast_set_party_caller *update) +{ + ast_party_id_set(&dest->id, &src->id, update ? &update->id : NULL); - if (dest->ani) { + if (src->ani && src->ani != dest->ani) { ast_free(dest->ani); + dest->ani = ast_strdup(src->ani); } - dest->ani = ast_strdup(src->ani); dest->ani2 = src->ani2; -#endif +} + +void ast_party_caller_free(struct ast_party_caller *doomed) +{ + ast_party_id_free(&doomed->id); + + ast_free(doomed->ani); + doomed->ani = NULL; } void ast_party_connected_line_init(struct ast_party_connected_line *init) @@ -2059,9 +2199,7 @@ void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const ast_party_id_copy(&dest->id, &src->id); - if (dest->ani) { - ast_free(dest->ani); - } + ast_free(dest->ani); dest->ani = ast_strdup(src->ani); dest->ani2 = src->ani2; @@ -2076,14 +2214,12 @@ void ast_party_connected_line_set_init(struct ast_party_connected_line *init, co init->source = guide->source; } -void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src) +void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update) { - ast_party_id_set(&dest->id, &src->id); + ast_party_id_set(&dest->id, &src->id, update ? &update->id : NULL); if (src->ani && src->ani != dest->ani) { - if (dest->ani) { - ast_free(dest->ani); - } + ast_free(dest->ani); dest->ani = ast_strdup(src->ani); } @@ -2091,17 +2227,11 @@ void ast_party_connected_line_set(struct ast_party_connected_line *dest, const s dest->source = src->source; } -void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_callerid *cid) +void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_party_caller *caller) { - connected->id.number = cid->cid_num; - connected->id.name = cid->cid_name; - connected->id.number_type = cid->cid_ton; - connected->id.number_presentation = cid->cid_pres; - connected->id.tag = cid->cid_tag; - connected->id.subaddress = cid->subaddress; - - connected->ani = cid->cid_ani; - connected->ani2 = cid->cid_ani2; + connected->id = caller->id; + connected->ani = caller->ani; + connected->ani2 = caller->ani2; connected->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN; } @@ -2109,10 +2239,16 @@ void ast_party_connected_line_free(struct ast_party_connected_line *doomed) { ast_party_id_free(&doomed->id); - if (doomed->ani) { - ast_free(doomed->ani); - doomed->ani = NULL; - } + ast_free(doomed->ani); + doomed->ani = NULL; +} + +void ast_party_redirecting_init(struct ast_party_redirecting *init) +{ + ast_party_id_init(&init->from); + ast_party_id_init(&init->to); + init->count = 0; + init->reason = AST_REDIRECTING_REASON_UNKNOWN; } void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src) @@ -2136,6 +2272,14 @@ void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const st init->reason = guide->reason; } +void ast_party_redirecting_set(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src, const struct ast_set_party_redirecting *update) +{ + ast_party_id_set(&dest->from, &src->from, update ? &update->from : NULL); + ast_party_id_set(&dest->to, &src->to, update ? &update->to : NULL); + dest->reason = src->reason; + dest->count = src->count; +} + void ast_party_redirecting_free(struct ast_party_redirecting *doomed) { ast_party_id_free(&doomed->from); @@ -2210,7 +2354,8 @@ static void ast_channel_destructor(void *obj) if (chan->pbx) ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name); - free_cid(&chan->cid); + ast_party_dialed_free(&chan->dialed); + ast_party_caller_free(&chan->caller); ast_party_connected_line_free(&chan->connected); ast_party_redirecting_free(&chan->redirecting); @@ -2275,7 +2420,10 @@ static void ast_dummy_channel_destructor(void *obj) headp = &chan->varshead; - free_cid(&chan->cid); + ast_party_dialed_free(&chan->dialed); + ast_party_caller_free(&chan->caller); + ast_party_connected_line_free(&chan->connected); + ast_party_redirecting_free(&chan->redirecting); /* loop over the variables list, freeing all data and deleting list items */ /* no need to lock the list, as the channel is already locked */ @@ -2574,19 +2722,19 @@ int ast_hangup(struct ast_channel *chan) ast_channel_unlock(chan); ast_cc_offer(chan); ast_manager_event(chan, EVENT_FLAG_CALL, "Hangup", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "Cause: %d\r\n" - "Cause-txt: %s\r\n", - chan->name, - chan->uniqueid, - S_OR(chan->cid.cid_num, "<unknown>"), - S_OR(chan->cid.cid_name, "<unknown>"), - chan->hangupcause, - ast_cause2str(chan->hangupcause) - ); + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "CallerIDNum: %s\r\n" + "CallerIDName: %s\r\n" + "Cause: %d\r\n" + "Cause-txt: %s\r\n", + chan->name, + chan->uniqueid, + S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"), + S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>"), + chan->hangupcause, + ast_cause2str(chan->hangupcause) + ); if (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_BRIDGED) && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED) && @@ -4012,7 +4160,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, ast_party_connected_line_set_init(&connected, &chan->connected); res = ast_connected_line_parse_data(data, datalen, &connected); if (!res) { - ast_channel_set_connected_line(chan, &connected); + ast_channel_set_connected_line(chan, &connected, NULL); } ast_party_connected_line_free(&connected); } @@ -4025,7 +4173,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, ast_party_redirecting_set_init(&redirecting, &chan->redirecting); res = ast_redirecting_parse_data(data, datalen, &redirecting); if (!res) { - ast_channel_set_redirecting(chan, &redirecting); + ast_channel_set_redirecting(chan, &redirecting, NULL); } ast_party_redirecting_free(&redirecting); } @@ -4810,7 +4958,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan return NULL; } - ast_channel_set_redirecting(new, apr); + ast_channel_set_redirecting(new, apr, NULL); /* Copy/inherit important information into new channel */ if (oh) { @@ -4821,7 +4969,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan ast_set_callerid(new, oh->cid_num, oh->cid_name, oh->cid_num); } if (oh->parent_channel) { - ast_channel_update_redirecting(oh->parent_channel, apr); + ast_channel_update_redirecting(oh->parent_channel, apr, NULL); ast_channel_inherit_variables(oh->parent_channel, new); ast_channel_datastore_inherit(oh->parent_channel, new); } @@ -4829,7 +4977,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan ast_cdr_setaccount(new, oh->account); } } else if (caller) { /* no outgoing helper so use caller if avaliable */ - ast_channel_update_redirecting(caller, apr); + ast_channel_update_redirecting(caller, apr, NULL); ast_channel_inherit_variables(caller, new); ast_channel_datastore_inherit(caller, new); } @@ -4840,7 +4988,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan } ast_copy_flags(new->cdr, orig->cdr, AST_CDR_FLAG_ORIGINATED); ast_string_field_set(new, accountcode, orig->accountcode); - ast_party_caller_copy(&new->cid, &orig->cid); + ast_party_caller_copy(&new->caller, &orig->caller); ast_party_connected_line_copy(&new->connected, &orig->connected); ast_channel_unlock(new); ast_channel_unlock(orig); @@ -4895,10 +5043,17 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co ast_set_callerid(chan, cid_num, cid_name, cid_num); ast_set_flag(chan->cdr, AST_CDR_FLAG_ORIGINATED); ast_party_connected_line_set_init(&connected, &chan->connected); - connected.id.number = (char *) cid_num; - connected.id.name = (char *) cid_name; - connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; - ast_channel_set_connected_line(chan, &connected); + if (cid_num) { + connected.id.number.valid = 1; + connected.id.number.str = (char *) cid_num; + connected.id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + } + if (cid_name) { + connected.id.name.valid = 1; + connected.id.name.str = (char *) cid_name; + connected.id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + } + ast_channel_set_connected_line(chan, &connected, NULL); if (ast_call(chan, data, 0)) { /* ast_call failed... */ ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); @@ -5658,19 +5813,22 @@ static void ast_set_owners_and_peers(struct ast_channel *chan1, */ static void report_new_callerid(struct ast_channel *chan) { + int pres; + + pres = ast_party_id_presentation(&chan->caller.id); ast_manager_event(chan, EVENT_FLAG_CALL, "NewCallerid", - "Channel: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "Uniqueid: %s\r\n" - "CID-CallingPres: %d (%s)\r\n", - chan->name, - S_OR(chan->cid.cid_num, ""), - S_OR(chan->cid.cid_name, ""), - chan->uniqueid, - chan->cid.cid_pres, - ast_describe_caller_presentation(chan->cid.cid_pres) - ); + "Channel: %s\r\n" + "CallerIDNum: %s\r\n" + "CallerIDName: %s\r\n" + "Uniqueid: %s\r\n" + "CID-CallingPres: %d (%s)\r\n", + chan->name, + S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), + S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, ""), + chan->uniqueid, + pres, + ast_describe_caller_presentation(pres) + ); } /*! @@ -5690,7 +5848,8 @@ int ast_do_masquerade(struct ast_channel *original) const struct ast_channel_tech *t; void *t_pvt; union { - struct ast_callerid cid; + struct ast_party_dialed dialed; + struct ast_party_caller caller; struct ast_party_connected_line connected; struct ast_party_redirecting redirecting; } exchange; @@ -5917,18 +6076,24 @@ int ast_do_masquerade(struct ast_channel *original) * Just swap the whole structures, nevermind the allocations, * they'll work themselves out. */ - exchange.cid = original->cid; - original->cid = clonechan->cid; - clonechan->cid = exchange.cid; - report_new_callerid(original); + exchange.dialed = original->dialed; + original->dialed = clonechan->dialed; + clonechan->dialed = exchange.dialed; + + exchange.caller = original->caller; + original->caller = clonechan->caller; + clonechan->caller = exchange.caller; exchange.connected = original->connected; original->connected = clonechan->connected; clonechan->connected = exchange.connected; + exchange.redirecting = original->redirecting; original->redirecting = clonechan->redirecting; clonechan->redirecting = exchange.redirecting; + report_new_callerid(original); + /* Restore original timing file descriptor */ ast_channel_set_fd(original, AST_TIMING_FD, original->timingfd); @@ -6030,19 +6195,18 @@ void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char ast_channel_lock(chan); if (cid_num) { - if (chan->cid.cid_num) - ast_free(chan->cid.cid_num); - chan->cid.cid_num = ast_strdup(cid_num); + chan->caller.id.number.valid = 1; + ast_free(chan->caller.id.number.str); + chan->caller.id.number.str = ast_strdup(cid_num); } if (cid_name) { - if (chan->cid.cid_name) - ast_free(chan->cid.cid_name); - chan->cid.cid_name = ast_strdup(cid_name); + chan->caller.id.name.valid = 1; + ast_free(chan->caller.id.name.str); + chan->caller.id.name.str = ast_strdup(cid_name); } if (cid_ani) { - if (chan->cid.cid_ani) - ast_free(chan->cid.cid_ani); - chan->cid.cid_ani = ast_strdup(cid_ani); + ast_free(chan->caller.ani); + chan->caller.ani = ast_strdup(cid_ani); } report_new_callerid(chan); @@ -6050,6 +6214,40 @@ void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char ast_channel_unlock(chan); } +void ast_channel_set_caller(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update) +{ + if (&chan->caller == caller) { + /* Don't set to self */ + return; + } + + ast_channel_lock(chan); + ast_party_caller_set(&chan->caller, caller, update); + ast_channel_unlock(chan); +} + +void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update) +{ + struct ast_party_caller pre_set; + + if (&chan->caller == caller) { + /* Don't set to self */ + return; + } + + ast_channel_lock(chan); + pre_set = chan->caller; + ast_party_caller_set(&chan->caller, caller, update); + if (S_COR(pre_set.id.number.valid, pre_set.id.number.str, NULL) + != S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL) + || S_COR(pre_set.id.name.valid, pre_set.id.name.str, NULL) + != S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL)) { + /* The caller id name or number changed. */ + report_new_callerid(chan); + } + ast_channel_unlock(chan); +} + int ast_setstate(struct ast_channel *chan, enum ast_channel_state state) { int oldstate = chan->_state; @@ -6072,16 +6270,16 @@ int ast_setstate(struct ast_channel *chan, enum ast_channel_state state) /* setstate used to conditionally report Newchannel; this is no more */ ast_manager_event(chan, EVENT_FLAG_CALL, "Newstate", - "Channel: %s\r\n" - "ChannelState: %d\r\n" - "ChannelStateDesc: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "Uniqueid: %s\r\n", - chan->name, chan->_state, ast_state2str(chan->_state), - S_OR(chan->cid.cid_num, ""), - S_OR(chan->cid.cid_name, ""), - chan->uniqueid); + "Channel: %s\r\n" + "ChannelState: %d\r\n" + "ChannelStateDesc: %s\r\n" + "CallerIDNum: %s\r\n" + "CallerIDName: %s\r\n" + "Uniqueid: %s\r\n", + chan->name, chan->_state, ast_state2str(chan->_state), + S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), + S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, ""), + chan->uniqueid); return 0; } @@ -6346,19 +6544,20 @@ static void manager_bridge_event(int onoff, int type, struct ast_channel *c0, st { struct ast_channel *chans[2] = { c0, c1 }; ast_manager_event_multichan(EVENT_FLAG_CALL, "Bridge", 2, chans, - "Bridgestate: %s\r\n" - "Bridgetype: %s\r\n" - "Channel1: %s\r\n" - "Channel2: %s\r\n" - "Uniqueid1: %s\r\n" - "Uniqueid2: %s\r\n" - "CallerID1: %s\r\n" - "CallerID2: %s\r\n", - onoff ? "Link" : "Unlink", - type == 1 ? "core" : "native", - c0->name, c1->name, c0->uniqueid, c1->uniqueid, - S_OR(c0->cid.cid_num, ""), - S_OR(c1->cid.cid_num, "")); + "Bridgestate: %s\r\n" + "Bridgetype: %s\r\n" + "Channel1: %s\r\n" + "Channel2: %s\r\n" + "Uniqueid1: %s\r\n" + "Uniqueid2: %s\r\n" + "CallerID1: %s\r\n" + "CallerID2: %s\r\n", + onoff ? "Link" : "Unlink", + type == 1 ? "core" : "native", + c0->name, c1->name, + c0->uniqueid, c1->uniqueid, + S_COR(c0->caller.id.number.valid, c0->caller.id.number.str, ""), + S_COR(c1->caller.id.number.valid, c1->caller.id.number.str, "")); } static void update_bridge_vars(struct ast_channel *c0, struct ast_channel *c1) @@ -6606,13 +6805,16 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha ast_set_flag(c1, AST_FLAG_NBRIDGE); if ((res = c0->tech->bridge(c0, c1, config->flags, fo, rc, timeoutms)) == AST_BRIDGE_COMPLETE) { ast_manager_event_multichan(EVENT_FLAG_CALL, "Unlink", 2, chans, - "Channel1: %s\r\n" - "Channel2: %s\r\n" - "Uniqueid1: %s\r\n" - "Uniqueid2: %s\r\n" - "CallerID1: %s\r\n" - "CallerID2: %s\r\n", - c0->name, c1->name, c0->uniqueid, c1->uniqueid, S_OR(c0->cid.cid_num, "<unknown>"), S_OR(c1->cid.cid_num, "<unknown>")); + "Channel1: %s\r\n" + "Channel2: %s\r\n" + "Uniqueid1: %s\r\n" + "Uniqueid2: %s\r\n" + "CallerID1: %s\r\n" + "CallerID2: %s\r\n", + c0->name, c1->name, + c0->uniqueid, c1->uniqueid, + S_COR(c0->caller.id.number.valid, c0->caller.id.number.str, "<unknown>"), + S_COR(c1->caller.id.number.valid, c1->caller.id.number.str, "<unknown>")); ast_debug(1, "Returning from native bridge, channels: %s, %s\n", c0->name, c1->name); @@ -6677,13 +6879,16 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha c1->_bridge = NULL; ast_manager_event_multichan(EVENT_FLAG_CALL, "Unlink", 2, chans, - "Channel1: %s\r\n" - "Channel2: %s\r\n" - "Uniqueid1: %s\r\n" - "Uniqueid2: %s\r\n" - "CallerID1: %s\r\n" - "CallerID2: %s\r\n", - c0->name, c1->name, c0->uniqueid, c1->uniqueid, S_OR(c0->cid.cid_num, "<unknown>"), S_OR(c1->cid.cid_num, "<unknown>")); + "Channel1: %s\r\n" + "Channel2: %s\r\n" + "Uniqueid1: %s\r\n" + "Uniqueid2: %s\r\n" + "CallerID1: %s\r\n" + "CallerID2: %s\r\n", + c0->name, c1->name, + c0->uniqueid, c1->uniqueid, + S_COR(c0->caller.id.number.valid, c0->caller.id.number.str, "<unknown>"), + S_COR(c1->caller.id.number.valid, c1->caller.id.number.str, "<unknown>")); ast_debug(1, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name); return res; @@ -7289,101 +7494,27 @@ int ast_say_digits_full(struct ast_channel *chan, int num, return ast_say_digit_str_full(chan, buf, ints, lang, audiofd, ctrlfd); } -void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_callerid *src) +void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src) { -#if 1 - /* Must manually fill in struct ast_party_id until struct ast_callerid goes away */ - if (dest->id.number) { - ast_free(dest->id.number); - } - dest->id.number = ast_strdup(src->cid_num); - - if (dest->id.name) { - ast_free(dest->id.name); - } - dest->id.name = ast_strdup(src->cid_name); - - if (dest->id.tag) { - ast_free(dest->id.tag); - } - dest->id.tag = ast_strdup(src->cid_tag); - - dest->id.number_type = src->cid_ton; - dest->id.number_presentation = src->cid_pres; - - - if (dest->ani) { - ast_free(dest->ani); - } - dest->ani = ast_strdup(src->cid_ani); - - dest->ani2 = src->cid_ani2; - ast_party_subaddress_copy(&dest->id.subaddress, &src->subaddress); - -#else - - /* The src parameter type will become a struct ast_party_caller ptr. */ - /* This is future code */ - ast_party_id_copy(&dest->id, &src->id); - if (dest->ani) { - ast_free(dest->ani); - } + ast_free(dest->ani); dest->ani = ast_strdup(src->ani); dest->ani2 = src->ani2; -#endif } -void ast_connected_line_copy_to_caller(struct ast_callerid *dest, const struct ast_party_connected_line *src) +void ast_connected_line_copy_to_caller(struct ast_party_caller *dest, const struct ast_party_connected_line *src) { -#if 1 - /* Must manually extract from struct ast_party_id until struct ast_callerid goes away */ - if (dest->cid_num) { - ast_free(dest->cid_num); - } - dest->cid_num = ast_strdup(src->id.number); - - if (dest->cid_name) { - ast_free(dest->cid_name); - } - dest->cid_name = ast_strdup(src->id.name); - - if (dest->cid_tag) { - ast_free(dest->cid_tag); - } - dest->cid_tag = ast_strdup(src->id.tag); - - dest->cid_ton = src->id.number_type; - dest->cid_pres = src->id.number_presentation; - - - if (dest->cid_ani) { - ast_free(dest->cid_ani); - } - dest->cid_ani = ast_strdup(src->ani); - - dest->cid_ani2 = src->ani2; - ast_party_subaddress_copy(&dest->subaddress, &src->id.subaddress); - -#else - - /* The dest parameter type will become a struct ast_party_caller ptr. */ - /* This is future code */ - ast_party_id_copy(&dest->id, &src->id); - if (dest->ani) { - ast_free(dest->ani); - } + ast_free(dest->ani); dest->ani = ast_strdup(src->ani); dest->ani2 = src->ani2; -#endif } -void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected) +void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update) { if (&chan->connected == connected) { /* Don't set to self */ @@ -7391,30 +7522,38 @@ void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_p } ast_channel_lock(chan); - ast_party_connected_line_set(&chan->connected, connected); + ast_party_connected_line_set(&chan->connected, connected, update); ast_channel_unlock(chan); } -/*! - * \brief Element identifiers for connected line indication frame data - * \note Only add to the end of this enum. - */ -enum { - AST_CONNECTED_LINE_NUMBER, - AST_CONNECTED_LINE_NAME, - AST_CONNECTED_LINE_NUMBER_TYPE, - AST_CONNECTED_LINE_NUMBER_PRESENTATION, - AST_CONNECTED_LINE_SOURCE, - AST_CONNECTED_LINE_SUBADDRESS, - AST_CONNECTED_LINE_SUBADDRESS_TYPE, - AST_CONNECTED_LINE_SUBADDRESS_ODD_EVEN, - AST_CONNECTED_LINE_SUBADDRESS_VALID, - AST_CONNECTED_LINE_TAG, +/*! \note Should follow struct ast_party_name */ +struct ast_party_name_ies { + /*! \brief Subscriber name ie */ + int str; + /*! \brief Character set ie. */ + int char_set; + /*! \brief presentation-indicator ie */ + int presentation; + /*! \brief valid/present ie */ + int valid; }; -int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected) +/*! + * \internal + * \since 1.8 + * \brief Build a party name information data frame component. + * + * \param data Buffer to fill with the frame data + * \param datalen Size of the buffer to fill + * \param name Party name information + * \param label Name of particular party name + * \param ies Data frame ie values for the party name components + * + * \retval -1 if error + * \retval Amount of data buffer used + */ +static int party_name_build_data(unsigned char *data, size_t datalen, const struct ast_party_name *name, const char *label, const struct ast_party_name_ies *ies) { - int32_t value; size_t length; size_t pos = 0; @@ -7422,110 +7561,383 @@ int ast_connected_line_build_data(unsigned char *data, size_t datalen, const str * The size of integer values must be fixed in case the frame is * shipped to another machine. */ - - /* *************** Connected line party id *************** */ - if (connected->id.number) { - length = strlen(connected->id.number); + if (name->str) { + length = strlen(name->str); if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for connected line number\n"); + ast_log(LOG_WARNING, "No space left for %s name\n", label); return -1; } - data[pos++] = AST_CONNECTED_LINE_NUMBER; + data[pos++] = ies->str; data[pos++] = length; - memcpy(data + pos, connected->id.number, length); + memcpy(data + pos, name->str, length); pos += length; } - if (connected->id.name) { - length = strlen(connected->id.name); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for connected line name\n"); - return -1; - } - data[pos++] = AST_CONNECTED_LINE_NAME; - data[pos++] = length; - memcpy(data + pos, connected->id.name, length); - pos += length; + if (datalen < pos + (sizeof(data[0]) * 2) + 1) { + ast_log(LOG_WARNING, "No space left for %s name char set\n", label); + return -1; } + data[pos++] = ies->char_set; + data[pos++] = 1; + data[pos++] = name->char_set; + + if (datalen < pos + (sizeof(data[0]) * 2) + 1) { + ast_log(LOG_WARNING, "No space left for %s name presentation\n", label); + return -1; + } + data[pos++] = ies->presentation; + data[pos++] = 1; + data[pos++] = name->presentation; + + if (datalen < pos + (sizeof(data[0]) * 2) + 1) { + ast_log(LOG_WARNING, "No space left for %s name valid\n", label); + return -1; + } + data[pos++] = ies->valid; + data[pos++] = 1; + data[pos++] = name->valid; + + return pos; +} - if (connected->id.tag) { - length = strlen(connected->id.tag); +/*! \note Should follow struct ast_party_number */ +struct ast_party_number_ies { + /*! \brief Subscriber phone number ie */ + int str; + /*! \brief Type-Of-Number and Numbering-Plan ie */ + int plan; + /*! \brief presentation-indicator ie */ + int presentation; + /*! \brief valid/present ie */ + int valid; +}; + +/*! + * \internal + * \since 1.8 + * \brief Build a party number information data frame component. + * + * \param data Buffer to fill with the frame data + * \param datalen Size of the buffer to fill + * \param number Party number information + * \param label Name of particular party number + * \param ies Data frame ie values for the party number components + * + * \retval -1 if error + * \retval Amount of data buffer used + */ +static int party_number_build_data(unsigned char *data, size_t datalen, const struct ast_party_number *number, const char *label, const struct ast_party_number_ies *ies) +{ + size_t length; + size_t pos = 0; + + /* + * The size of integer values must be fixed in case the frame is + * shipped to another machine. + */ + if (number->str) { + length = strlen(number->str); if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for connected line tag\n"); + ast_log(LOG_WARNING, "No space left for %s number\n", label); return -1; } - data[pos++] = AST_CONNECTED_LINE_TAG; + data[pos++] = ies->str; data[pos++] = length; - memcpy(data + pos, connected->id.tag, length); + memcpy(data + pos, number->str, length); pos += length; } if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for connected line type of number\n"); + ast_log(LOG_WARNING, "No space left for %s numbering plan\n", label); return -1; } - data[pos++] = AST_CONNECTED_LINE_NUMBER_TYPE; + data[pos++] = ies->plan; data[pos++] = 1; - data[pos++] = connected->id.number_type; + data[pos++] = number->plan; if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for connected line presentation\n"); + ast_log(LOG_WARNING, "No space left for %s number presentation\n", label); return -1; } - data[pos++] = AST_CONNECTED_LINE_NUMBER_PRESENTATION; + data[pos++] = ies->presentation; data[pos++] = 1; - data[pos++] = connected->id.number_presentation; + data[pos++] = number->presentation; - /* Connected line source */ - if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) { - ast_log(LOG_WARNING, "No space left for connected line source\n"); + if (datalen < pos + (sizeof(data[0]) * 2) + 1) { + ast_log(LOG_WARNING, "No space left for %s number valid\n", label); return -1; } - data[pos++] = AST_CONNECTED_LINE_SOURCE; - data[pos++] = sizeof(value); - value = htonl(connected->source); - memcpy(data + pos, &value, sizeof(value)); - pos += sizeof(value); + data[pos++] = ies->valid; + data[pos++] = 1; + data[pos++] = number->valid; + + return pos; +} + +/*! \note Should follow struct ast_party_subaddress */ +struct ast_party_subaddress_ies { + /*! \brief subaddress ie. */ + int str; + /*! \brief subaddress type ie */ + int type; + /*! \brief odd/even indicator ie */ + int odd_even_indicator; + /*! \brief valid/present ie */ + int valid; +}; - /* Connected line Subaddress */ - if (connected->id.subaddress.str) { - length = strlen(connected->id.subaddress.str); +/*! + * \internal + * \since 1.8 + * \brief Build a party subaddress information data frame component. + * + * \param data Buffer to fill with the frame data + * \param datalen Size of the buffer to fill + * \param subaddress Party subaddress information + * \param label Name of particular party subaddress + * \param ies Data frame ie values for the party subaddress components + * + * \retval -1 if error + * \retval Amount of data buffer used + */ +static int party_subaddress_build_data(unsigned char *data, size_t datalen, const struct ast_party_subaddress *subaddress, const char *label, const struct ast_party_subaddress_ies *ies) +{ + size_t length; + size_t pos = 0; + + /* + * The size of integer values must be fixed in case the frame is + * shipped to another machine. + */ + if (subaddress->str) { + length = strlen(subaddress->str); if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for connected line subaddress\n"); + ast_log(LOG_WARNING, "No space left for %s subaddress\n", label); return -1; } - data[pos++] = AST_CONNECTED_LINE_SUBADDRESS; + data[pos++] = ies->str; data[pos++] = length; - memcpy(data + pos, connected->id.subaddress.str, length); + memcpy(data + pos, subaddress->str, length); pos += length; } - /* Connected line Subaddress Type */ + if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for connected line type of subaddress\n"); + ast_log(LOG_WARNING, "No space left for %s type of subaddress\n", label); return -1; } - data[pos++] = AST_CONNECTED_LINE_SUBADDRESS_TYPE; + data[pos++] = ies->type; data[pos++] = 1; - data[pos++] = connected->id.subaddress.type; + data[pos++] = subaddress->type; - /* Connected line Subaddress Odd/Even indicator */ if (datalen < pos + (sizeof(data[0]) * 2) + 1) { ast_log(LOG_WARNING, - "No space left for connected line subaddress odd-even indicator\n"); + "No space left for %s subaddress odd-even indicator\n", label); + return -1; + } + data[pos++] = ies->odd_even_indicator; + data[pos++] = 1; + data[pos++] = subaddress->odd_even_indicator; + + if (datalen < pos + (sizeof(data[0]) * 2) + 1) { + ast_log(LOG_WARNING, "No space left for %s subaddress valid\n", label); return -1; } - data[pos++] = AST_CONNECTED_LINE_SUBADDRESS_ODD_EVEN; + data[pos++] = ies->valid; data[pos++] = 1; - data[pos++] = connected->id.subaddress.odd_even_indicator; + data[pos++] = subaddress->valid; + + return pos; +} + +/*! \note Should follow struct ast_party_id */ +struct ast_party_id_ies { + /*! \brief Subscriber name ies */ + struct ast_party_name_ies name; + /*! \brief Subscriber phone number ies */ + struct ast_party_number_ies number; + /*! \brief Subscriber subaddress ies. */ + struct ast_party_subaddress_ies subaddress; + /*! \brief User party id tag ie. */ + int tag; + /*! \brief Combined name and number presentation ie. */ + int combined_presentation; +}; + +/*! + * \internal + * \since 1.8 + * \brief Build a party id information data frame component. + * + * \param data Buffer to fill with the frame data + * \param datalen Size of the buffer to fill + * \param id Party id information + * \param label Name of particular party id + * \param ies Data frame ie values for the party id components + * \param update What id information to build. NULL if all. + * + * \retval -1 if error + * \retval Amount of data buffer used + */ +static int party_id_build_data(unsigned char *data, size_t datalen, + const struct ast_party_id *id, const char *label, const struct ast_party_id_ies *ies, + const struct ast_set_party_id *update) +{ + size_t length; + size_t pos = 0; + int res; + + /* + * The size of integer values must be fixed in case the frame is + * shipped to another machine. + */ + + if (!update || update->name) { + res = party_name_build_data(data + pos, datalen - pos, &id->name, label, + &ies->name); + if (res < 0) { + return -1; + } + pos += res; + } + + if (!update || update->number) { + res = party_number_build_data(data + pos, datalen - pos, &id->number, label, + &ies->number); + if (res < 0) { + return -1; + } + pos += res; + } + + if (!update || update->subaddress) { + res = party_subaddress_build_data(data + pos, datalen - pos, &id->subaddress, + label, &ies->subaddress); + if (res < 0) { + return -1; + } + pos += res; + } + + /* *************** Party id user tag **************************** */ + if (id->tag) { + length = strlen(id->tag); + if (datalen < pos + (sizeof(data[0]) * 2) + length) { + ast_log(LOG_WARNING, "No space left for %s tag\n", label); + return -1; + } + data[pos++] = ies->tag; + data[pos++] = length; + memcpy(data + pos, id->tag, length); + pos += length; + } + + /* *************** Party id combined presentation *************** */ + if (!update || update->number) { + int presentation; + + if (!update || update->name) { + presentation = ast_party_id_presentation(id); + } else { + /* + * We must compromise because not all the information is available + * to determine a combined presentation value. + * We will only send the number presentation instead. + */ + presentation = id->number.presentation; + } + + if (datalen < pos + (sizeof(data[0]) * 2) + 1) { + ast_log(LOG_WARNING, "No space left for %s combined presentation\n", label); + return -1; + } + data[pos++] = ies->combined_presentation; + data[pos++] = 1; + data[pos++] = presentation; + } + + return pos; +} + +/*! + * \brief Element identifiers for connected line indication frame data + * \note Only add to the end of this enum. + */ +enum { + AST_CONNECTED_LINE_NUMBER, + AST_CONNECTED_LINE_NAME, + AST_CONNECTED_LINE_NUMBER_PLAN, + AST_CONNECTED_LINE_ID_PRESENTATION,/* Combined number and name presentation. */ + AST_CONNECTED_LINE_SOURCE, + AST_CONNECTED_LINE_SUBADDRESS, + AST_CONNECTED_LINE_SUBADDRESS_TYPE, + AST_CONNECTED_LINE_SUBADDRESS_ODD_EVEN, + AST_CONNECTED_LINE_SUBADDRESS_VALID, + AST_CONNECTED_LINE_TAG, + AST_CONNECTED_LINE_VERSION, + AST_CONNECTED_LINE_NAME_VALID, + AST_CONNECTED_LINE_NAME_CHAR_SET, + AST_CONNECTED_LINE_NAME_PRESENTATION, + AST_CONNECTED_LINE_NUMBER_VALID, + AST_CONNECTED_LINE_NUMBER_PRESENTATION, +}; - /* Connected line Subaddress Valid */ +int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update) +{ + int32_t value; + size_t pos = 0; + int res; + + static const struct ast_party_id_ies ies = { + .name.str = AST_CONNECTED_LINE_NAME, + .name.char_set = AST_CONNECTED_LINE_NAME_CHAR_SET, + .name.presentation = AST_CONNECTED_LINE_NAME_PRESENTATION, + .name.valid = AST_CONNECTED_LINE_NAME_VALID, + + .number.str = AST_CONNECTED_LINE_NUMBER, + .number.plan = AST_CONNECTED_LINE_NUMBER_PLAN, + .number.presentation = AST_CONNECTED_LINE_NUMBER_PRESENTATION, + .number.valid = AST_CONNECTED_LINE_NUMBER_VALID, + + .subaddress.str = AST_CONNECTED_LINE_SUBADDRESS, + .subaddress.type = AST_CONNECTED_LINE_SUBADDRESS_TYPE, + .subaddress.odd_even_indicator = AST_CONNECTED_LINE_SUBADDRESS_ODD_EVEN, + .subaddress.valid = AST_CONNECTED_LINE_SUBADDRESS_VALID, + + .tag = AST_CONNECTED_LINE_TAG, + .combined_presentation = AST_CONNECTED_LINE_ID_PRESENTATION, + }; + + /* + * The size of integer values must be fixed in case the frame is + * shipped to another machine. + */ + + /* Connected line frame version */ if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for connected line subaddress valid\n"); + ast_log(LOG_WARNING, "No space left for connected line frame version\n"); return -1; } - data[pos++] = AST_CONNECTED_LINE_SUBADDRESS_VALID; + data[pos++] = AST_CONNECTED_LINE_VERSION; data[pos++] = 1; - data[pos++] = connected->id.subaddress.valid; + data[pos++] = 2;/* Version 1 did not have a version ie */ + + res = party_id_build_data(data + pos, datalen - pos, &connected->id, + "connected line", &ies, update ? &update->id : NULL); + if (res < 0) { + return -1; + } + pos += res; + + /* Connected line source */ + if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) { + ast_log(LOG_WARNING, "No space left for connected line source\n"); + return -1; + } + data[pos++] = AST_CONNECTED_LINE_SOURCE; + data[pos++] = sizeof(value); + value = htonl(connected->source); + memcpy(data + pos, &value, sizeof(value)); + pos += sizeof(value); return pos; } @@ -7536,6 +7948,9 @@ int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, str unsigned char ie_len; unsigned char ie_id; int32_t value; + int frame_version = 1; + int combined_presentation = 0; + int got_combined_presentation = 0;/* TRUE if got a combined name and number presentation value. */ for (pos = 0; pos < datalen; pos += ie_len) { if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) { @@ -7550,62 +7965,94 @@ int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, str } switch (ie_id) { - case AST_CONNECTED_LINE_NUMBER: - if (connected->id.number) { - ast_free(connected->id.number); - } - connected->id.number = ast_malloc(ie_len + 1); - if (connected->id.number) { - memcpy(connected->id.number, data + pos, ie_len); - connected->id.number[ie_len] = 0; +/* Connected line party frame version */ + case AST_CONNECTED_LINE_VERSION: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid connected line frame version (%u)\n", + (unsigned) ie_len); + break; } + frame_version = data[pos]; break; +/* Connected line party id name */ case AST_CONNECTED_LINE_NAME: - if (connected->id.name) { - ast_free(connected->id.name); + ast_free(connected->id.name.str); + connected->id.name.str = ast_malloc(ie_len + 1); + if (connected->id.name.str) { + memcpy(connected->id.name.str, data + pos, ie_len); + connected->id.name.str[ie_len] = 0; } - connected->id.name = ast_malloc(ie_len + 1); - if (connected->id.name) { - memcpy(connected->id.name, data + pos, ie_len); - connected->id.name[ie_len] = 0; + break; + case AST_CONNECTED_LINE_NAME_CHAR_SET: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid connected line name char set (%u)\n", + (unsigned) ie_len); + break; } + connected->id.name.char_set = data[pos]; break; - case AST_CONNECTED_LINE_TAG: - if (connected->id.tag) { - ast_free(connected->id.tag); + case AST_CONNECTED_LINE_NAME_PRESENTATION: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid connected line name presentation (%u)\n", + (unsigned) ie_len); + break; } - connected->id.tag = ast_malloc(ie_len + 1); - if (connected->id.tag) { - memcpy(connected->id.tag, data + pos, ie_len); - connected->id.tag[ie_len] = 0; + connected->id.name.presentation = data[pos]; + break; + case AST_CONNECTED_LINE_NAME_VALID: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid connected line name valid (%u)\n", + (unsigned) ie_len); + break; + } + connected->id.name.valid = data[pos]; + break; +/* Connected line party id number */ + case AST_CONNECTED_LINE_NUMBER: + ast_free(connected->id.number.str); + connected->id.number.str = ast_malloc(ie_len + 1); + if (connected->id.number.str) { + memcpy(connected->id.number.str, data + pos, ie_len); + connected->id.number.str[ie_len] = 0; } break; - case AST_CONNECTED_LINE_NUMBER_TYPE: + case AST_CONNECTED_LINE_NUMBER_PLAN: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid connected line type of number (%u)\n", (unsigned) ie_len); + ast_log(LOG_WARNING, "Invalid connected line numbering plan (%u)\n", + (unsigned) ie_len); break; } - connected->id.number_type = data[pos]; + connected->id.number.plan = data[pos]; break; case AST_CONNECTED_LINE_NUMBER_PRESENTATION: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid connected line presentation (%u)\n", (unsigned) ie_len); + ast_log(LOG_WARNING, "Invalid connected line number presentation (%u)\n", + (unsigned) ie_len); break; } - connected->id.number_presentation = data[pos]; + connected->id.number.presentation = data[pos]; break; - case AST_CONNECTED_LINE_SOURCE: - if (ie_len != sizeof(value)) { - ast_log(LOG_WARNING, "Invalid connected line source (%u)\n", (unsigned) ie_len); + case AST_CONNECTED_LINE_NUMBER_VALID: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid connected line number valid (%u)\n", + (unsigned) ie_len); break; } - memcpy(&value, data + pos, sizeof(value)); - connected->source = ntohl(value); + connected->id.number.valid = data[pos]; break; - case AST_CONNECTED_LINE_SUBADDRESS: - if (connected->id.subaddress.str) { - ast_free(connected->id.subaddress.str); +/* Connected line party id combined presentation */ + case AST_CONNECTED_LINE_ID_PRESENTATION: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid connected line combined presentation (%u)\n", + (unsigned) ie_len); + break; } + combined_presentation = data[pos]; + got_combined_presentation = 1; + break; +/* Connected line party id subaddress */ + case AST_CONNECTED_LINE_SUBADDRESS: + ast_free(connected->id.subaddress.str); connected->id.subaddress.str = ast_malloc(ie_len + 1); if (connected->id.subaddress.str) { memcpy(connected->id.subaddress.str, data + pos, ie_len); @@ -7637,21 +8084,69 @@ int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, str } connected->id.subaddress.valid = data[pos]; break; +/* Connected line party tag */ + case AST_CONNECTED_LINE_TAG: + ast_free(connected->id.tag); + connected->id.tag = ast_malloc(ie_len + 1); + if (connected->id.tag) { + memcpy(connected->id.tag, data + pos, ie_len); + connected->id.tag[ie_len] = 0; + } + break; +/* Connected line party source */ + case AST_CONNECTED_LINE_SOURCE: + if (ie_len != sizeof(value)) { + ast_log(LOG_WARNING, "Invalid connected line source (%u)\n", + (unsigned) ie_len); + break; + } + memcpy(&value, data + pos, sizeof(value)); + connected->source = ntohl(value); + break; +/* Connected line party unknown element */ default: - ast_log(LOG_DEBUG, "Unknown connected line element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len); + ast_log(LOG_DEBUG, "Unknown connected line element: %u (%u)\n", + (unsigned) ie_id, (unsigned) ie_len); break; } } + switch (frame_version) { + case 1: + /* + * The other end is an earlier version that we need to adjust + * for compatibility. + */ + connected->id.name.valid = 1; + connected->id.name.char_set = AST_PARTY_CHAR_SET_ISO8859_1; + connected->id.number.valid = 1; + if (got_combined_presentation) { + connected->id.name.presentation = combined_presentation; + connected->id.number.presentation = combined_presentation; + } + break; + case 2: + /* The other end is at the same level as we are. */ + break; + default: + /* + * The other end is newer than we are. + * We need to assume that they are compatible with us. + */ + ast_log(LOG_DEBUG, "Connected line frame has newer version: %u\n", + (unsigned) frame_version); + break; + } + return 0; } -void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected) +void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update) { unsigned char data[1024]; /* This should be large enough */ size_t datalen; - datalen = ast_connected_line_build_data(data, sizeof(data), connected); + datalen = ast_connected_line_build_data(data, sizeof(data), connected, update); if (datalen == (size_t) -1) { return; } @@ -7659,12 +8154,12 @@ void ast_channel_update_connected_line(struct ast_channel *chan, const struct as ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen); } -void ast_channel_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected) +void ast_channel_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update) { unsigned char data[1024]; /* This should be large enough */ size_t datalen; - datalen = ast_connected_line_build_data(data, sizeof(data), connected); + datalen = ast_connected_line_build_data(data, sizeof(data), connected, update); if (datalen == (size_t) -1) { return; } @@ -7672,7 +8167,7 @@ void ast_channel_queue_connected_line_update(struct ast_channel *chan, const str ast_queue_control_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen); } -void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting) +void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update) { if (&chan->redirecting == redirecting) { /* Don't set to self */ @@ -7680,12 +8175,7 @@ void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_part } ast_channel_lock(chan); - - ast_party_id_set(&chan->redirecting.from, &redirecting->from); - ast_party_id_set(&chan->redirecting.to, &redirecting->to); - chan->redirecting.reason = redirecting->reason; - chan->redirecting.count = redirecting->count; - + ast_party_redirecting_set(&chan->redirecting, redirecting, update); ast_channel_unlock(chan); } @@ -7696,12 +8186,12 @@ void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_part enum { AST_REDIRECTING_FROM_NUMBER, AST_REDIRECTING_FROM_NAME, - AST_REDIRECTING_FROM_NUMBER_TYPE, - AST_REDIRECTING_FROM_NUMBER_PRESENTATION, + AST_REDIRECTING_FROM_NUMBER_PLAN, + AST_REDIRECTING_FROM_ID_PRESENTATION, AST_REDIRECTING_TO_NUMBER, AST_REDIRECTING_TO_NAME, - AST_REDIRECTING_TO_NUMBER_TYPE, - AST_REDIRECTING_TO_NUMBER_PRESENTATION, + AST_REDIRECTING_TO_NUMBER_PLAN, + AST_REDIRECTING_TO_ID_PRESENTATION, AST_REDIRECTING_REASON, AST_REDIRECTING_COUNT, AST_REDIRECTING_FROM_SUBADDRESS, @@ -7714,200 +8204,86 @@ enum { AST_REDIRECTING_TO_SUBADDRESS_VALID, AST_REDIRECTING_FROM_TAG, AST_REDIRECTING_TO_TAG, + AST_REDIRECTING_VERSION, + AST_REDIRECTING_FROM_NAME_VALID, + AST_REDIRECTING_FROM_NAME_CHAR_SET, + AST_REDIRECTING_FROM_NAME_PRESENTATION, + AST_REDIRECTING_FROM_NUMBER_VALID, + AST_REDIRECTING_FROM_NUMBER_PRESENTATION, + AST_REDIRECTING_TO_NAME_VALID, + AST_REDIRECTING_TO_NAME_CHAR_SET, + AST_REDIRECTING_TO_NAME_PRESENTATION, + AST_REDIRECTING_TO_NUMBER_VALID, + AST_REDIRECTING_TO_NUMBER_PRESENTATION, }; -int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting) +int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update) { int32_t value; - size_t length; size_t pos = 0; + int res; - /* - * The size of integer values must be fixed in case the frame is - * shipped to another machine. - */ - - /* *************** Redirecting from party id *************** */ - if (redirecting->from.number) { - length = strlen(redirecting->from.number); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for redirecting from number\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_NUMBER; - data[pos++] = length; - memcpy(data + pos, redirecting->from.number, length); - pos += length; - } - - if (redirecting->from.name) { - length = strlen(redirecting->from.name); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for redirecting from name\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_NAME; - data[pos++] = length; - memcpy(data + pos, redirecting->from.name, length); - pos += length; - } - - if (redirecting->from.tag) { - length = strlen(redirecting->from.tag); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for redirecting from name\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_TAG; - data[pos++] = length; - memcpy(data + pos, redirecting->from.tag, length); - pos += length; - } - - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for redirecting from type of number\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_NUMBER_TYPE; - data[pos++] = 1; - data[pos++] = redirecting->from.number_type; - - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for redirecting from presentation\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_NUMBER_PRESENTATION; - data[pos++] = 1; - data[pos++] = redirecting->from.number_presentation; - - /* subaddress */ - if (redirecting->from.subaddress.str) { - length = strlen(redirecting->from.subaddress.str); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for redirecting-from subaddress\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_SUBADDRESS; - data[pos++] = length; - memcpy(data + pos, redirecting->from.subaddress.str, length); - pos += length; - } - - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for redirecting-from type of subaddress\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_SUBADDRESS_TYPE; - data[pos++] = 1; - data[pos++] = redirecting->from.subaddress.type; - - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, - "No space left for redirecting-from subaddress odd-even indicator\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_SUBADDRESS_ODD_EVEN; - data[pos++] = 1; - data[pos++] = redirecting->from.subaddress.odd_even_indicator; - - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for redirecting-from subaddress valid\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_FROM_SUBADDRESS_VALID; - data[pos++] = 1; - data[pos++] = redirecting->from.subaddress.valid; - - /* *************** Redirecting to party id *************** */ - if (redirecting->to.number) { - length = strlen(redirecting->to.number); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for redirecting to number\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_TO_NUMBER; - data[pos++] = length; - memcpy(data + pos, redirecting->to.number, length); - pos += length; - } - - if (redirecting->to.name) { - length = strlen(redirecting->to.name); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for redirecting to name\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_TO_NAME; - data[pos++] = length; - memcpy(data + pos, redirecting->to.name, length); - pos += length; - } - - if (redirecting->to.tag) { - length = strlen(redirecting->to.tag); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for redirecting to name\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_TO_TAG; - data[pos++] = length; - memcpy(data + pos, redirecting->to.tag, length); - pos += length; - } + static const struct ast_party_id_ies from_ies = { + .name.str = AST_REDIRECTING_FROM_NAME, + .name.char_set = AST_REDIRECTING_FROM_NAME_CHAR_SET, + .name.presentation = AST_REDIRECTING_FROM_NAME_PRESENTATION, + .name.valid = AST_REDIRECTING_FROM_NAME_VALID, - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for redirecting to type of number\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_TO_NUMBER_TYPE; - data[pos++] = 1; - data[pos++] = redirecting->to.number_type; + .number.str = AST_REDIRECTING_FROM_NUMBER, + .number.plan = AST_REDIRECTING_FROM_NUMBER_PLAN, + .number.presentation = AST_REDIRECTING_FROM_NUMBER_PRESENTATION, + .number.valid = AST_REDIRECTING_FROM_NUMBER_VALID, - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for redirecting to presentation\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_TO_NUMBER_PRESENTATION; - data[pos++] = 1; - data[pos++] = redirecting->to.number_presentation; + .subaddress.str = AST_REDIRECTING_FROM_SUBADDRESS, + .subaddress.type = AST_REDIRECTING_FROM_SUBADDRESS_TYPE, + .subaddress.odd_even_indicator = AST_REDIRECTING_FROM_SUBADDRESS_ODD_EVEN, + .subaddress.valid = AST_REDIRECTING_FROM_SUBADDRESS_VALID, - /* subaddress */ - if (redirecting->to.subaddress.str) { - length = strlen(redirecting->to.subaddress.str); - if (datalen < pos + (sizeof(data[0]) * 2) + length) { - ast_log(LOG_WARNING, "No space left for redirecting-to subaddress\n"); - return -1; - } - data[pos++] = AST_REDIRECTING_TO_SUBADDRESS; - data[pos++] = length; - memcpy(data + pos, redirecting->to.subaddress.str, length); - pos += length; - } + .tag = AST_REDIRECTING_FROM_TAG, + .combined_presentation = AST_REDIRECTING_FROM_ID_PRESENTATION, + }; + static const struct ast_party_id_ies to_ies = { + .name.str = AST_REDIRECTING_TO_NAME, + .name.char_set = AST_REDIRECTING_TO_NAME_CHAR_SET, + .name.presentation = AST_REDIRECTING_TO_NAME_PRESENTATION, + .name.valid = AST_REDIRECTING_TO_NAME_VALID, + + .number.str = AST_REDIRECTING_TO_NUMBER, + .number.plan = AST_REDIRECTING_TO_NUMBER_PLAN, + .number.presentation = AST_REDIRECTING_TO_NUMBER_PRESENTATION, + .number.valid = AST_REDIRECTING_TO_NUMBER_VALID, + + .subaddress.str = AST_REDIRECTING_TO_SUBADDRESS, + .subaddress.type = AST_REDIRECTING_TO_SUBADDRESS_TYPE, + .subaddress.odd_even_indicator = AST_REDIRECTING_TO_SUBADDRESS_ODD_EVEN, + .subaddress.valid = AST_REDIRECTING_TO_SUBADDRESS_VALID, + + .tag = AST_REDIRECTING_TO_TAG, + .combined_presentation = AST_REDIRECTING_TO_ID_PRESENTATION, + }; + /* Redirecting frame version */ if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for redirecting-to type of subaddress\n"); + ast_log(LOG_WARNING, "No space left for redirecting frame version\n"); return -1; } - data[pos++] = AST_REDIRECTING_TO_SUBADDRESS_TYPE; + data[pos++] = AST_REDIRECTING_VERSION; data[pos++] = 1; - data[pos++] = redirecting->to.subaddress.type; + data[pos++] = 2;/* Version 1 did not have a version ie */ - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, - "No space left for redirecting-to subaddress odd-even indicator\n"); + res = party_id_build_data(data + pos, datalen - pos, &redirecting->from, + "redirecting-from", &from_ies, update ? &update->from : NULL); + if (res < 0) { return -1; } - data[pos++] = AST_REDIRECTING_TO_SUBADDRESS_ODD_EVEN; - data[pos++] = 1; - data[pos++] = redirecting->to.subaddress.odd_even_indicator; + pos += res; - if (datalen < pos + (sizeof(data[0]) * 2) + 1) { - ast_log(LOG_WARNING, "No space left for redirecting-to subaddress valid\n"); + res = party_id_build_data(data + pos, datalen - pos, &redirecting->to, + "redirecting-to", &to_ies, update ? &update->to : NULL); + if (res < 0) { return -1; } - data[pos++] = AST_REDIRECTING_TO_SUBADDRESS_VALID; - data[pos++] = 1; - data[pos++] = redirecting->to.subaddress.valid; + pos += res; /* Redirecting reason */ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) { @@ -7940,6 +8316,11 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct unsigned char ie_len; unsigned char ie_id; int32_t value; + int frame_version = 1; + int from_combined_presentation = 0; + int got_from_combined_presentation = 0;/* TRUE if got a combined name and number presentation value. */ + int to_combined_presentation = 0; + int got_to_combined_presentation = 0;/* TRUE if got a combined name and number presentation value. */ for (pos = 0; pos < datalen; pos += ie_len) { if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) { @@ -7954,54 +8335,94 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct } switch (ie_id) { - case AST_REDIRECTING_FROM_NUMBER: - if (redirecting->from.number) { - ast_free(redirecting->from.number); - } - redirecting->from.number = ast_malloc(ie_len + 1); - if (redirecting->from.number) { - memcpy(redirecting->from.number, data + pos, ie_len); - redirecting->from.number[ie_len] = 0; +/* Redirecting frame version */ + case AST_REDIRECTING_VERSION: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting frame version (%u)\n", + (unsigned) ie_len); + break; } + frame_version = data[pos]; break; +/* Redirecting-from party id name */ case AST_REDIRECTING_FROM_NAME: - if (redirecting->from.name) { - ast_free(redirecting->from.name); + ast_free(redirecting->from.name.str); + redirecting->from.name.str = ast_malloc(ie_len + 1); + if (redirecting->from.name.str) { + memcpy(redirecting->from.name.str, data + pos, ie_len); + redirecting->from.name.str[ie_len] = 0; + } + break; + case AST_REDIRECTING_FROM_NAME_CHAR_SET: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-from name char set (%u)\n", + (unsigned) ie_len); + break; } - redirecting->from.name = ast_malloc(ie_len + 1); - if (redirecting->from.name) { - memcpy(redirecting->from.name, data + pos, ie_len); - redirecting->from.name[ie_len] = 0; + redirecting->from.name.char_set = data[pos]; + break; + case AST_REDIRECTING_FROM_NAME_PRESENTATION: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-from name presentation (%u)\n", + (unsigned) ie_len); + break; } + redirecting->from.name.presentation = data[pos]; break; - case AST_REDIRECTING_FROM_TAG: - if (redirecting->from.tag) { - ast_free(redirecting->from.tag); + case AST_REDIRECTING_FROM_NAME_VALID: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-from name valid (%u)\n", + (unsigned) ie_len); + break; } - redirecting->from.tag = ast_malloc(ie_len + 1); - if (redirecting->from.tag) { - memcpy(redirecting->from.tag, data + pos, ie_len); - redirecting->from.tag[ie_len] = 0; + redirecting->from.name.valid = data[pos]; + break; +/* Redirecting-from party id number */ + case AST_REDIRECTING_FROM_NUMBER: + ast_free(redirecting->from.number.str); + redirecting->from.number.str = ast_malloc(ie_len + 1); + if (redirecting->from.number.str) { + memcpy(redirecting->from.number.str, data + pos, ie_len); + redirecting->from.number.str[ie_len] = 0; } break; - case AST_REDIRECTING_FROM_NUMBER_TYPE: + case AST_REDIRECTING_FROM_NUMBER_PLAN: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid redirecting from type of number (%u)\n", (unsigned) ie_len); + ast_log(LOG_WARNING, "Invalid redirecting-from numbering plan (%u)\n", + (unsigned) ie_len); break; } - redirecting->from.number_type = data[pos]; + redirecting->from.number.plan = data[pos]; break; case AST_REDIRECTING_FROM_NUMBER_PRESENTATION: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid redirecting from presentation (%u)\n", (unsigned) ie_len); + ast_log(LOG_WARNING, "Invalid redirecting-from number presentation (%u)\n", + (unsigned) ie_len); break; } - redirecting->from.number_presentation = data[pos]; + redirecting->from.number.presentation = data[pos]; break; - case AST_REDIRECTING_FROM_SUBADDRESS: - if (redirecting->from.subaddress.str) { - ast_free(redirecting->from.subaddress.str); + case AST_REDIRECTING_FROM_NUMBER_VALID: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-from number valid (%u)\n", + (unsigned) ie_len); + break; } + redirecting->from.number.valid = data[pos]; + break; +/* Redirecting-from party id combined presentation */ + case AST_REDIRECTING_FROM_ID_PRESENTATION: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-from combined presentation (%u)\n", + (unsigned) ie_len); + break; + } + from_combined_presentation = data[pos]; + got_from_combined_presentation = 1; + break; +/* Redirecting-from party id subaddress */ + case AST_REDIRECTING_FROM_SUBADDRESS: + ast_free(redirecting->from.subaddress.str); redirecting->from.subaddress.str = ast_malloc(ie_len + 1); if (redirecting->from.subaddress.str) { memcpy(redirecting->from.subaddress.str, data + pos, ie_len); @@ -8010,7 +8431,7 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct break; case AST_REDIRECTING_FROM_SUBADDRESS_TYPE: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid redirecting from type of subaddress (%u)\n", + ast_log(LOG_WARNING, "Invalid redirecting-from type of subaddress (%u)\n", (unsigned) ie_len); break; } @@ -8019,7 +8440,7 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct case AST_REDIRECTING_FROM_SUBADDRESS_ODD_EVEN: if (ie_len != 1) { ast_log(LOG_WARNING, - "Invalid redirecting from subaddress odd-even indicator (%u)\n", + "Invalid redirecting-from subaddress odd-even indicator (%u)\n", (unsigned) ie_len); break; } @@ -8027,60 +8448,100 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct break; case AST_REDIRECTING_FROM_SUBADDRESS_VALID: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid redirecting from subaddress valid (%u)\n", + ast_log(LOG_WARNING, "Invalid redirecting-from subaddress valid (%u)\n", (unsigned) ie_len); break; } redirecting->from.subaddress.valid = data[pos]; break; - case AST_REDIRECTING_TO_NUMBER: - if (redirecting->to.number) { - ast_free(redirecting->to.number); - } - redirecting->to.number = ast_malloc(ie_len + 1); - if (redirecting->to.number) { - memcpy(redirecting->to.number, data + pos, ie_len); - redirecting->to.number[ie_len] = 0; +/* Redirecting-from party id tag */ + case AST_REDIRECTING_FROM_TAG: + ast_free(redirecting->from.tag); + redirecting->from.tag = ast_malloc(ie_len + 1); + if (redirecting->from.tag) { + memcpy(redirecting->from.tag, data + pos, ie_len); + redirecting->from.tag[ie_len] = 0; } break; +/* Redirecting-to party id name */ case AST_REDIRECTING_TO_NAME: - if (redirecting->to.name) { - ast_free(redirecting->to.name); + ast_free(redirecting->to.name.str); + redirecting->to.name.str = ast_malloc(ie_len + 1); + if (redirecting->to.name.str) { + memcpy(redirecting->to.name.str, data + pos, ie_len); + redirecting->to.name.str[ie_len] = 0; } - redirecting->to.name = ast_malloc(ie_len + 1); - if (redirecting->to.name) { - memcpy(redirecting->to.name, data + pos, ie_len); - redirecting->to.name[ie_len] = 0; + break; + case AST_REDIRECTING_TO_NAME_CHAR_SET: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-to name char set (%u)\n", + (unsigned) ie_len); + break; } + redirecting->to.name.char_set = data[pos]; break; - case AST_REDIRECTING_TO_TAG: - if (redirecting->to.tag) { - ast_free(redirecting->to.tag); + case AST_REDIRECTING_TO_NAME_PRESENTATION: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-to name presentation (%u)\n", + (unsigned) ie_len); + break; } - redirecting->to.tag = ast_malloc(ie_len + 1); - if (redirecting->to.tag) { - memcpy(redirecting->to.tag, data + pos, ie_len); - redirecting->to.tag[ie_len] = 0; + redirecting->to.name.presentation = data[pos]; + break; + case AST_REDIRECTING_TO_NAME_VALID: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-to name valid (%u)\n", + (unsigned) ie_len); + break; + } + redirecting->to.name.valid = data[pos]; + break; +/* Redirecting-to party id number */ + case AST_REDIRECTING_TO_NUMBER: + ast_free(redirecting->to.number.str); + redirecting->to.number.str = ast_malloc(ie_len + 1); + if (redirecting->to.number.str) { + memcpy(redirecting->to.number.str, data + pos, ie_len); + redirecting->to.number.str[ie_len] = 0; } break; - case AST_REDIRECTING_TO_NUMBER_TYPE: + case AST_REDIRECTING_TO_NUMBER_PLAN: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid redirecting to type of number (%u)\n", (unsigned) ie_len); + ast_log(LOG_WARNING, "Invalid redirecting-to numbering plan (%u)\n", + (unsigned) ie_len); break; } - redirecting->to.number_type = data[pos]; + redirecting->to.number.plan = data[pos]; break; case AST_REDIRECTING_TO_NUMBER_PRESENTATION: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid redirecting to presentation (%u)\n", (unsigned) ie_len); + ast_log(LOG_WARNING, "Invalid redirecting-to number presentation (%u)\n", + (unsigned) ie_len); break; } - redirecting->to.number_presentation = data[pos]; + redirecting->to.number.presentation = data[pos]; break; - case AST_REDIRECTING_TO_SUBADDRESS: - if (redirecting->to.subaddress.str) { - ast_free(redirecting->to.subaddress.str); + case AST_REDIRECTING_TO_NUMBER_VALID: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-to number valid (%u)\n", + (unsigned) ie_len); + break; } + redirecting->to.number.valid = data[pos]; + break; +/* Redirecting-to party id combined presentation */ + case AST_REDIRECTING_TO_ID_PRESENTATION: + if (ie_len != 1) { + ast_log(LOG_WARNING, "Invalid redirecting-to combined presentation (%u)\n", + (unsigned) ie_len); + break; + } + to_combined_presentation = data[pos]; + got_to_combined_presentation = 1; + break; +/* Redirecting-to party id subaddress */ + case AST_REDIRECTING_TO_SUBADDRESS: + ast_free(redirecting->to.subaddress.str); redirecting->to.subaddress.str = ast_malloc(ie_len + 1); if (redirecting->to.subaddress.str) { memcpy(redirecting->to.subaddress.str, data + pos, ie_len); @@ -8089,7 +8550,7 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct break; case AST_REDIRECTING_TO_SUBADDRESS_TYPE: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid redirecting to type of subaddress (%u)\n", + ast_log(LOG_WARNING, "Invalid redirecting-to type of subaddress (%u)\n", (unsigned) ie_len); break; } @@ -8098,7 +8559,7 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct case AST_REDIRECTING_TO_SUBADDRESS_ODD_EVEN: if (ie_len != 1) { ast_log(LOG_WARNING, - "Invalid redirecting to subaddress odd-even indicator (%u)\n", + "Invalid redirecting-to subaddress odd-even indicator (%u)\n", (unsigned) ie_len); break; } @@ -8106,43 +8567,93 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct break; case AST_REDIRECTING_TO_SUBADDRESS_VALID: if (ie_len != 1) { - ast_log(LOG_WARNING, "Invalid redirecting to subaddress valid (%u)\n", + ast_log(LOG_WARNING, "Invalid redirecting-to subaddress valid (%u)\n", (unsigned) ie_len); break; } redirecting->to.subaddress.valid = data[pos]; break; +/* Redirecting-to party id tag */ + case AST_REDIRECTING_TO_TAG: + ast_free(redirecting->to.tag); + redirecting->to.tag = ast_malloc(ie_len + 1); + if (redirecting->to.tag) { + memcpy(redirecting->to.tag, data + pos, ie_len); + redirecting->to.tag[ie_len] = 0; + } + break; +/* Redirecting reason */ case AST_REDIRECTING_REASON: if (ie_len != sizeof(value)) { - ast_log(LOG_WARNING, "Invalid redirecting reason (%u)\n", (unsigned) ie_len); + ast_log(LOG_WARNING, "Invalid redirecting reason (%u)\n", + (unsigned) ie_len); break; } memcpy(&value, data + pos, sizeof(value)); redirecting->reason = ntohl(value); break; +/* Redirecting count */ case AST_REDIRECTING_COUNT: if (ie_len != sizeof(value)) { - ast_log(LOG_WARNING, "Invalid redirecting count (%u)\n", (unsigned) ie_len); + ast_log(LOG_WARNING, "Invalid redirecting count (%u)\n", + (unsigned) ie_len); break; } memcpy(&value, data + pos, sizeof(value)); redirecting->count = ntohl(value); break; +/* Redirecting unknown element */ default: - ast_log(LOG_DEBUG, "Unknown redirecting element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len); + ast_log(LOG_DEBUG, "Unknown redirecting element: %u (%u)\n", + (unsigned) ie_id, (unsigned) ie_len); break; } } + switch (frame_version) { + case 1: + /* + * The other end is an earlier version that we need to adjust + * for compatibility. + */ + redirecting->from.name.valid = 1; + redirecting->from.name.char_set = AST_PARTY_CHAR_SET_ISO8859_1; + redirecting->from.number.valid = 1; + if (got_from_combined_presentation) { + redirecting->from.name.presentation = from_combined_presentation; + redirecting->from.number.presentation = from_combined_presentation; + } + + redirecting->to.name.valid = 1; + redirecting->to.name.char_set = AST_PARTY_CHAR_SET_ISO8859_1; + redirecting->to.number.valid = 1; + if (got_to_combined_presentation) { + redirecting->to.name.presentation = to_combined_presentation; + redirecting->to.number.presentation = to_combined_presentation; + } + break; + case 2: + /* The other end is at the same level as we are. */ + break; + default: + /* + * The other end is newer than we are. + * We need to assume that they are compatible with us. + */ + ast_log(LOG_DEBUG, "Redirecting frame has newer version: %u\n", + (unsigned) frame_version); + break; + } + return 0; } -void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting) +void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update) { unsigned char data[1024]; /* This should be large enough */ size_t datalen; - datalen = ast_redirecting_build_data(data, sizeof(data), redirecting); + datalen = ast_redirecting_build_data(data, sizeof(data), redirecting, update); if (datalen == (size_t) -1) { return; } @@ -8150,12 +8661,12 @@ void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_p ast_indicate_data(chan, AST_CONTROL_REDIRECTING, data, datalen); } -void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting) +void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update) { unsigned char data[1024]; /* This should be large enough */ size_t datalen; - datalen = ast_redirecting_build_data(data, sizeof(data), redirecting); + datalen = ast_redirecting_build_data(data, sizeof(data), redirecting, update); if (datalen == (size_t) -1) { return; } @@ -8193,7 +8704,7 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc } if (!(retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args))) { - ast_channel_update_connected_line(macro_chan, ¯o_chan->connected); + ast_channel_update_connected_line(macro_chan, ¯o_chan->connected, NULL); } return retval; @@ -8230,7 +8741,7 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); if (!retval) { - ast_channel_update_redirecting(macro_chan, ¯o_chan->redirecting); + ast_channel_update_redirecting(macro_chan, ¯o_chan->redirecting, NULL); } return retval; |