aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/callerid.c235
-rw-r--r--main/channel.c936
-rw-r--r--main/dial.c19
-rw-r--r--main/features.c61
-rw-r--r--main/stun.c2
5 files changed, 1171 insertions, 82 deletions
diff --git a/main/callerid.c b/main/callerid.c
index a7836904e..57119958a 100644
--- a/main/callerid.c
+++ b/main/callerid.c
@@ -922,8 +922,10 @@ int callerid_generate(unsigned char *buf, const char *number, const char *name,
return bytes;
}
-/*! \brief Clean up phone string
- * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
+/*!
+ * \brief Clean up phone string
+ * \details
+ * Remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
* Basically, remove anything that could be invalid in a pattern.
*/
void ast_shrink_phone_number(char *n)
@@ -958,11 +960,13 @@ void ast_shrink_phone_number(char *n)
n[y] = '\0';
}
-/*! \brief Checks if phone number consists of valid characters
- \param exten String that needs to be checked
- \param valid Valid characters in string
- \return 1 if valid string, 0 if string contains invalid characters
-*/
+/*!
+ * \brief Checks if phone number consists of valid characters
+ * \param exten String that needs to be checked
+ * \param valid Valid characters in string
+ * \retval 1 if valid string
+ * \retval 0 if string contains invalid characters
+ */
static int ast_is_valid_string(const char *exten, const char *valid)
{
int x;
@@ -975,34 +979,16 @@ static int ast_is_valid_string(const char *exten, const char *valid)
return 1;
}
-/*! \brief checks if string consists only of digits and * \# and +
- \return 1 if string is valid AST phone number
- \return 0 if not
-*/
int ast_isphonenumber(const char *n)
{
return ast_is_valid_string(n, "0123456789*#+");
}
-/*! \brief checks if string consists only of digits and ( ) - * \# and +
- Pre-qualifies the string for ast_shrink_phone_number()
- \return 1 if string is valid AST shrinkable phone number
- \return 0 if not
-*/
int ast_is_shrinkable_phonenumber(const char *exten)
{
return ast_is_valid_string(exten, "0123456789*#+()-.");
}
-/*!
- * \brief Destructively parse instr for caller id information
- * \return always returns 0, as the code always returns something.
- * \note XXX 'name' is not parsed consistently e.g. we have
- * input location name
- * " foo bar " <123> 123 ' foo bar ' (with spaces around)
- * " foo bar " NULL 'foo bar' (without spaces around)
- * The parsing of leading and trailing space/quotes should be more consistent.
- */
int ast_callerid_parse(char *instr, char **name, char **location)
{
char *ns, *ne, *ls, *le;
@@ -1103,68 +1089,191 @@ int ast_callerid_split(const char *buf, char *name, int namelen, char *num, int
return 0;
}
-/*! \brief Translation table for Caller ID Presentation settings */
-static struct {
- int val;
+struct ast_value_translation {
+ int value;
const char *name;
const char *description;
-} pres_types[] = {
- { AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened"},
- { AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen"},
- { AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen"},
- { AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number"},
- { AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened"},
- { AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen"},
- { AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen"},
- { AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number"},
- { AST_PRES_NUMBER_NOT_AVAILABLE, "unavailable", "Number Unavailable"},
};
-/*! \brief Convert caller ID text code to value
- used in config file parsing
- \param data text string
- \return value AST_PRES_ from callerid.h
-*/
+/*! \brief Translation table for Caller ID Presentation settings */
+static const struct ast_value_translation pres_types[] = {
+/* *INDENT-OFF* */
+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened" },
+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen" },
+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen" },
+ { AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number" },
+
+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened" },
+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen" },
+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen" },
+ { AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number" },
+
+ { AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER, "unavailable", "Number Unavailable" }, /* Default name to value conversion. */
+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED, "unavailable", "Number Unavailable" },
+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_FAILED_SCREEN, "unavailable", "Number Unavailable" },
+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_PASSED_SCREEN, "unavailable", "Number Unavailable" },
+/* *INDENT-ON* */
+};
+
+/*!
+ * \brief Convert caller ID text code to value (used in config file parsing)
+ * \param data text string from config file
+ * \retval value AST_PRES_ from callerid.h
+ * \retval -1 if not in table
+ */
int ast_parse_caller_presentation(const char *data)
{
- int i;
+ int index;
- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
- if (!strcasecmp(pres_types[i].name, data))
- return pres_types[i].val;
+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+ if (!strcasecmp(pres_types[index].name, data)) {
+ return pres_types[index].value;
+ }
}
return -1;
}
-/*! \brief Convert caller ID pres value to explanatory string
- \param data value (see callerid.h AST_PRES_ )
- \return string for human presentation
-*/
+/*!
+ * \brief Convert caller ID pres value to explanatory string
+ * \param data AST_PRES_ value from callerid.h
+ * \return string for human presentation
+ */
const char *ast_describe_caller_presentation(int data)
{
- int i;
+ int index;
- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
- if (pres_types[i].val == data)
- return pres_types[i].description;
+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+ if (pres_types[index].value == data) {
+ return pres_types[index].description;
+ }
}
return "unknown";
}
-/*! \brief Convert caller ID pres value to text code
- \param data text string
- \return string for config file
-*/
+/*!
+ * \brief Convert caller ID pres value to text code
+ * \param data AST_PRES_ value from callerid.h
+ * \return string for config file
+ */
const char *ast_named_caller_presentation(int data)
{
- int i;
+ int index;
- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
- if (pres_types[i].val == data)
- return pres_types[i].name;
+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+ if (pres_types[index].value == data) {
+ return pres_types[index].name;
+ }
}
return "unknown";
}
+
+/*! \brief Translation table for redirecting reason settings */
+static const struct ast_value_translation redirecting_reason_types[] = {
+/* *INDENT-OFF* */
+ { AST_REDIRECTING_REASON_UNKNOWN, "unknown", "Unknown" },
+ { AST_REDIRECTING_REASON_USER_BUSY, "cfb", "Call Forwarding Busy" },
+ { AST_REDIRECTING_REASON_NO_ANSWER, "cfnr", "Call Forwarding No Reply" },
+ { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable", "Callee is Unavailable" },
+ { AST_REDIRECTING_REASON_UNCONDITIONAL, "cfu", "Call Forwarding Unconditional" },
+ { AST_REDIRECTING_REASON_TIME_OF_DAY, "time_of_day", "Time of Day" },
+ { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "dnd", "Do Not Disturb" },
+ { AST_REDIRECTING_REASON_DEFLECTION, "deflection", "Call Deflection" },
+ { AST_REDIRECTING_REASON_FOLLOW_ME, "follow_me", "Follow Me" },
+ { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out_of_order", "Called DTE Out-Of-Order" },
+ { AST_REDIRECTING_REASON_AWAY, "away", "Callee is Away" },
+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", "Call Forwarding By The Called DTE" },
+/* *INDENT-ON* */
+};
+
+int ast_redirecting_reason_parse(const char *data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+ if (!strcasecmp(redirecting_reason_types[index].name, data)) {
+ return redirecting_reason_types[index].value;
+ }
+ }
+
+ return -1;
+}
+
+const char *ast_redirecting_reason_describe(int data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+ if (redirecting_reason_types[index].value == data) {
+ return redirecting_reason_types[index].description;
+ }
+ }
+
+ return "not-known";
+}
+
+const char *ast_redirecting_reason_name(int data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+ if (redirecting_reason_types[index].value == data) {
+ return redirecting_reason_types[index].name;
+ }
+ }
+
+ return "not-known";
+}
+
+/*! \brief Translation table for connected line update source settings */
+static const struct ast_value_translation connected_line_source_types[] = {
+/* *INDENT-OFF* */
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN, "unknown", "Unknown" },
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, "answer", "Normal Call Answering" },
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION, "diversion", "Call Diversion (Deprecated, use REDIRECTING)" },
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, "transfer_active", "Call Transfer(Active)" },
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, "transfer", "Call Transfer(Active)" },/* Old name must come after new name. */
+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, "transfer_alerting", "Call Transfer(Alerting)" }
+/* *INDENT-ON* */
+};
+
+int ast_connected_line_source_parse(const char *data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+ if (!strcasecmp(connected_line_source_types[index].name, data)) {
+ return connected_line_source_types[index].value;
+ }
+ }
+
+ return -1;
+}
+
+const char *ast_connected_line_source_describe(int data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+ if (connected_line_source_types[index].value == data) {
+ return connected_line_source_types[index].description;
+ }
+ }
+
+ return "not-known";
+}
+
+const char *ast_connected_line_source_name(int data)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+ if (connected_line_source_types[index].value == data) {
+ return connected_line_source_types[index].name;
+ }
+ }
+
+ return "not-known";
+}
diff --git a/main/channel.c b/main/channel.c
index 9b2ad405c..718677b39 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -796,6 +796,13 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
return NULL;
}
+ if (!(tmp->cid.cid_name = ast_strdup(cid_name)) || !(tmp->cid.cid_num = ast_strdup(cid_num))) {
+ ast_string_field_free_memory(tmp);
+ sched_context_destroy(tmp->sched);
+ ast_free(tmp);
+ return NULL;
+ }
+
#ifdef HAVE_EPOLL
tmp->epfd = epoll_create(25);
#endif
@@ -866,9 +873,6 @@ alertpipe_failed:
ast_string_field_build(tmp, uniqueid, "%s-%li.%d", ast_config_AST_SYSTEM_NAME,
(long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
}
-
- tmp->cid.cid_name = ast_strdup(cid_name);
- tmp->cid.cid_num = ast_strdup(cid_num);
if (!ast_strlen_zero(name_fmt)) {
/* Almost every channel is calling this function, and setting the name via the ast_string_field_build() call.
@@ -1311,6 +1315,279 @@ static void free_cid(struct ast_callerid *cid)
cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = cid->cid_rdnis = NULL;
}
+/*!
+ * \internal
+ * \brief Initialize the given party id structure.
+ *
+ * \param init Party id structure to initialize.
+ *
+ * \return Nothing
+ */
+static void ast_party_id_init(struct ast_party_id *init)
+{
+ init->number = NULL;
+ init->name = NULL;
+ init->number_type = 0; /* Unknown */
+ init->number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+}
+
+/*!
+ * \internal
+ * \brief Copy the source party id information to the destination party id.
+ *
+ * \param dest Destination party id
+ * \param src Source party id
+ *
+ * \return Nothing
+ */
+static void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
+{
+ if (dest == src) {
+ /* Don't copy to self */
+ return;
+ }
+
+ if (dest->number) {
+ ast_free(dest->number);
+ }
+ dest->number = ast_strdup(src->number);
+
+ if (dest->name) {
+ ast_free(dest->name);
+ }
+ dest->name = ast_strdup(src->name);
+
+ dest->number_type = src->number_type;
+ dest->number_presentation = src->number_presentation;
+}
+
+/*!
+ * \internal
+ * \brief Initialize the given party id structure using the given guide
+ * for a set update operation.
+ *
+ * \details
+ * The initialization is needed to allow a set operation to know if a
+ * value needs to be updated. Simple integers need the guide's original
+ * value in case the set operation is not trying to set a new value.
+ * String values are simply set to NULL pointers if they are not going
+ * to be updated.
+ *
+ * \param init Party id structure to initialize.
+ * \param guide Source party id to use as a guide in initializing.
+ *
+ * \return Nothing
+ */
+static void ast_party_id_set_init(struct ast_party_id *init, const struct ast_party_id *guide)
+{
+ init->number = NULL;
+ init->name = NULL;
+ init->number_type = guide->number_type;
+ init->number_presentation = guide->number_presentation;
+}
+
+/*!
+ * \internal
+ * \brief Set the source party id information into the destination party id.
+ *
+ * \param dest Destination party id
+ * \param src Source party id
+ *
+ * \return Nothing
+ */
+static void ast_party_id_set(struct ast_party_id *dest, const struct ast_party_id *src)
+{
+ if (dest == src) {
+ /* Don't set to self */
+ return;
+ }
+
+ if (src->name && src->name != dest->name) {
+ if (dest->name) {
+ ast_free(dest->name);
+ }
+ dest->name = ast_strdup(src->name);
+ }
+
+ if (src->number && src->number != dest->number) {
+ if (dest->number) {
+ ast_free(dest->number);
+ }
+ dest->number = ast_strdup(src->number);
+ }
+
+ dest->number_type = src->number_type;
+ dest->number_presentation = src->number_presentation;
+}
+
+/*!
+ * \internal
+ * \brief Destroy the party id contents
+ *
+ * \param doomed The party id to destroy.
+ *
+ * \return Nothing
+ */
+static void ast_party_id_free(struct ast_party_id *doomed)
+{
+ if (doomed->number) {
+ ast_free(doomed->number);
+ doomed->number = NULL;
+ }
+
+ if (doomed->name) {
+ ast_free(doomed->name);
+ doomed->name = NULL;
+ }
+}
+
+void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid *src)
+{
+ if (dest == src) {
+ /* Don't copy to self */
+ return;
+ }
+
+#if 1
+ /* Copy caller-id specific information ONLY from struct ast_callerid */
+ if (dest->cid_num)
+ {
+ ast_free(dest->cid_num);
+ }
+ dest->cid_num = ast_strdup(src->cid_num);
+
+ if (dest->cid_name)
+ {
+ ast_free(dest->cid_name);
+ }
+ dest->cid_name = ast_strdup(src->cid_name);
+
+ dest->cid_ton = src->cid_ton;
+ dest->cid_pres = src->cid_pres;
+
+
+ if (dest->cid_ani)
+ {
+ ast_free(dest->cid_ani);
+ }
+ dest->cid_ani = ast_strdup(src->cid_ani);
+
+ dest->cid_ani2 = src->cid_ani2;
+
+#else
+
+ /* The src and dest parameter types will become struct ast_party_caller ptrs. */
+ /* This is future code */
+
+ ast_party_id_copy(&dest->id, &src->id);
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+
+ dest->ani2 = src->ani2;
+#endif
+}
+
+void ast_party_connected_line_init(struct ast_party_connected_line *init)
+{
+ ast_party_id_init(&init->id);
+ init->ani = NULL;
+ init->ani2 = 0;
+ init->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
+}
+
+void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
+{
+ if (dest == src) {
+ /* Don't copy to self */
+ return;
+ }
+
+ ast_party_id_copy(&dest->id, &src->id);
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+
+ dest->ani2 = src->ani2;
+ dest->source = src->source;
+}
+
+void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
+{
+ ast_party_id_set_init(&init->id, &guide->id);
+ init->ani = NULL;
+ init->ani2 = guide->ani2;
+ init->source = guide->source;
+}
+
+void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
+{
+ ast_party_id_set(&dest->id, &src->id);
+
+ if (src->ani && src->ani != dest->ani) {
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+ }
+
+ dest->ani2 = src->ani2;
+ dest->source = src->source;
+}
+
+void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_callerid *cid)
+{
+ connected->id.number = cid->cid_num;
+ connected->id.name = cid->cid_name;
+ connected->id.number_type = cid->cid_ton;
+ connected->id.number_presentation = cid->cid_pres;
+
+ connected->ani = cid->cid_ani;
+ connected->ani2 = cid->cid_ani2;
+ connected->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
+}
+
+void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
+{
+ ast_party_id_free(&doomed->id);
+
+ if (doomed->ani) {
+ ast_free(doomed->ani);
+ doomed->ani = NULL;
+ }
+}
+
+void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
+{
+ if (dest == src) {
+ /* Don't copy to self */
+ return;
+ }
+
+ ast_party_id_copy(&dest->from, &src->from);
+ ast_party_id_copy(&dest->to, &src->to);
+ dest->count = src->count;
+ dest->reason = src->reason;
+}
+
+void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide)
+{
+ ast_party_id_set_init(&init->from, &guide->from);
+ ast_party_id_set_init(&init->to, &guide->to);
+ init->count = guide->count;
+ init->reason = guide->reason;
+}
+
+void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
+{
+ ast_party_id_free(&doomed->from);
+ ast_party_id_free(&doomed->to);
+}
+
/*! \brief Free a channel structure */
void ast_channel_free(struct ast_channel *chan)
{
@@ -1374,7 +1651,11 @@ void ast_channel_free(struct ast_channel *chan)
ast_translator_free_path(chan->writetrans);
if (chan->pbx)
ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
+
free_cid(&chan->cid);
+ ast_party_connected_line_free(&chan->connected);
+ ast_party_redirecting_free(&chan->redirecting);
+
/* Close pipes if appropriate */
if ((fd = chan->alertpipe[0]) > -1)
close(fd);
@@ -2396,6 +2677,8 @@ int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd)
case AST_CONTROL_RINGING:
case AST_CONTROL_ANSWER:
case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
/* Unimportant */
break;
default:
@@ -2994,8 +3277,10 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
case AST_CONTROL_ANSWER:
case AST_CONTROL_HANGUP:
case AST_CONTROL_T38:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
case AST_CONTROL_TRANSFER:
- return 0;
+ break;
case AST_CONTROL_CONGESTION:
case AST_CONTROL_BUSY:
@@ -3016,7 +3301,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
* in switch statements. */
enum ast_control_frame_type condition = _condition;
struct ast_tone_zone_sound *ts = NULL;
- int res = -1;
+ int res;
ast_channel_lock(chan);
@@ -3025,10 +3310,41 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
ast_channel_unlock(chan);
return -1;
}
+ switch (condition) {
+ case AST_CONTROL_CONNECTED_LINE:
+ {
+ struct ast_party_connected_line connected;
+
+ ast_party_connected_line_set_init(&connected, &chan->connected);
+ res = ast_connected_line_parse_data(data, datalen, &connected);
+ if (!res) {
+ ast_channel_set_connected_line(chan, &connected);
+ }
+ ast_party_connected_line_free(&connected);
+ }
+ break;
+
+ case AST_CONTROL_REDIRECTING:
+ {
+ struct ast_party_redirecting redirecting;
+ ast_party_redirecting_set_init(&redirecting, &chan->redirecting);
+ res = ast_redirecting_parse_data(data, datalen, &redirecting);
+ if (!res) {
+ ast_channel_set_redirecting(chan, &redirecting);
+ }
+ ast_party_redirecting_free(&redirecting);
+ }
+ break;
+
+ default:
+ break;
+ }
if (chan->tech->indicate) {
/* See if the channel driver can handle this condition. */
res = chan->tech->indicate(chan, condition, data, datalen);
+ } else {
+ res = -1;
}
ast_channel_unlock(chan);
@@ -3082,6 +3398,8 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
case AST_CONTROL_UNHOLD:
case AST_CONTROL_T38:
case AST_CONTROL_TRANSFER:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
/* Nothing left to do for these. */
res = 0;
break;
@@ -3544,6 +3862,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
struct ast_channel *chan;
int res = 0;
int last_subclass = 0;
+ struct ast_party_connected_line connected;
if (outstate)
*outstate = 0;
@@ -3574,7 +3893,13 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
if (oh->account)
ast_cdr_setaccount(chan, oh->account);
}
+
ast_set_callerid(chan, cid_num, cid_name, cid_num);
+ ast_party_connected_line_set_init(&connected, &chan->connected);
+ connected.id.number = (char *) cid_num;
+ connected.id.name = (char *) cid_name;
+ connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+ ast_channel_set_connected_line(chan, &connected);
if (ast_call(chan, data, 0)) { /* ast_call failed... */
ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
@@ -3613,6 +3938,8 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
case AST_CONTROL_UNHOLD:
case AST_CONTROL_VIDUPDATE:
case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
case -1: /* Ignore -- just stopping indications */
break;
@@ -4088,7 +4415,11 @@ int ast_do_masquerade(struct ast_channel *original)
struct ast_frame *current;
const struct ast_channel_tech *t;
void *t_pvt;
- struct ast_callerid tmpcid;
+ union {
+ struct ast_callerid cid;
+ struct ast_party_connected_line connected;
+ struct ast_party_redirecting redirecting;
+ } exchange;
struct ast_channel *clonechan = original->masq;
struct ast_cdr *cdr;
int rformat = original->readformat;
@@ -4269,11 +4600,19 @@ int ast_do_masquerade(struct ast_channel *original)
/* Stream stuff stays the same */
/* Keep the original state. The fixup code will need to work with it most likely */
- /* Just swap the whole structures, nevermind the allocations, they'll work themselves
- out. */
- tmpcid = original->cid;
+ /*
+ * Just swap the whole structures, nevermind the allocations,
+ * they'll work themselves out.
+ */
+ exchange.cid = original->cid;
original->cid = clonechan->cid;
- clonechan->cid = tmpcid;
+ clonechan->cid = exchange.cid;
+ exchange.connected = original->connected;
+ original->connected = clonechan->connected;
+ clonechan->connected = exchange.connected;
+ exchange.redirecting = original->redirecting;
+ original->redirecting = clonechan->redirecting;
+ clonechan->redirecting = exchange.redirecting;
/* Restore original timing file descriptor */
ast_channel_set_fd(original, AST_TIMING_FD, original->timingfd);
@@ -4566,8 +4905,10 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
case AST_CONTROL_HOLD:
case AST_CONTROL_UNHOLD:
case AST_CONTROL_VIDUPDATE:
- case AST_CONTROL_SRCUPDATE:
case AST_CONTROL_T38:
+ case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_CONNECTED_LINE:
+ case AST_CONTROL_REDIRECTING:
ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
if (jb_in_use) {
ast_jb_empty_and_reset(c0, c1);
@@ -5530,3 +5871,576 @@ int ast_say_digits_full(struct ast_channel *chan, int num,
return ast_say_digit_str_full(chan, buf, ints, lang, audiofd, ctrlfd);
}
+
+void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_callerid *src)
+{
+#if 1
+ /* Must manually fill in struct ast_party_id until struct ast_callerid goes away */
+ if (dest->id.number) {
+ ast_free(dest->id.number);
+ }
+ dest->id.number = ast_strdup(src->cid_num);
+
+ if (dest->id.name) {
+ ast_free(dest->id.name);
+ }
+ dest->id.name = ast_strdup(src->cid_name);
+
+ dest->id.number_type = src->cid_ton;
+ dest->id.number_presentation = src->cid_pres;
+
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->cid_ani);
+
+ dest->ani2 = src->cid_ani2;
+
+#else
+
+ /* The src parameter type will become a struct ast_party_caller ptr. */
+ /* This is future code */
+
+ ast_party_id_copy(&dest->id, &src->id);
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+
+ dest->ani2 = src->ani2;
+#endif
+}
+
+void ast_connected_line_copy_to_caller(struct ast_callerid *dest, const struct ast_party_connected_line *src)
+{
+#if 1
+ /* Must manually extract from struct ast_party_id until struct ast_callerid goes away */
+ if (dest->cid_num) {
+ ast_free(dest->cid_num);
+ }
+ dest->cid_num = ast_strdup(src->id.number);
+
+ if (dest->cid_name) {
+ ast_free(dest->cid_name);
+ }
+ dest->cid_name = ast_strdup(src->id.name);
+
+ dest->cid_ton = src->id.number_type;
+ dest->cid_pres = src->id.number_presentation;
+
+
+ if (dest->cid_ani) {
+ ast_free(dest->cid_ani);
+ }
+ dest->cid_ani = ast_strdup(src->ani);
+
+ dest->cid_ani2 = src->ani2;
+
+#else
+
+ /* The dest parameter type will become a struct ast_party_caller ptr. */
+ /* This is future code */
+
+ ast_party_id_copy(&dest->id, &src->id);
+
+ if (dest->ani) {
+ ast_free(dest->ani);
+ }
+ dest->ani = ast_strdup(src->ani);
+
+ dest->ani2 = src->ani2;
+#endif
+}
+
+void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected)
+{
+ if (&chan->connected == connected) {
+ /* Don't set to self */
+ return;
+ }
+
+ ast_channel_lock(chan);
+ ast_party_connected_line_set(&chan->connected, connected);
+ ast_channel_unlock(chan);
+}
+
+/*!
+ * \brief Element identifiers for connected line indication frame data
+ * \note Only add to the end of this enum.
+ */
+enum {
+ AST_CONNECTED_LINE_NUMBER,
+ AST_CONNECTED_LINE_NAME,
+ AST_CONNECTED_LINE_NUMBER_TYPE,
+ AST_CONNECTED_LINE_NUMBER_PRESENTATION,
+ AST_CONNECTED_LINE_SOURCE
+};
+
+int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected)
+{
+ int32_t value;
+ size_t length;
+ size_t pos = 0;
+
+ /*
+ * The size of integer values must be fixed in case the frame is
+ * shipped to another machine.
+ */
+
+ /* *************** Connected line party id *************** */
+ if (connected->id.number) {
+ length = strlen(connected->id.number);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for connected line number\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_NUMBER;
+ data[pos++] = length;
+ memcpy(data + pos, connected->id.number, length);
+ pos += length;
+ }
+
+ if (connected->id.name) {
+ length = strlen(connected->id.name);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for connected line name\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_NAME;
+ data[pos++] = length;
+ memcpy(data + pos, connected->id.name, length);
+ pos += length;
+ }
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for connected line type of number\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_NUMBER_TYPE;
+ data[pos++] = 1;
+ data[pos++] = connected->id.number_type;
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for connected line presentation\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_NUMBER_PRESENTATION;
+ data[pos++] = 1;
+ data[pos++] = connected->id.number_presentation;
+
+ /* Connected line source */
+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
+ ast_log(LOG_WARNING, "No space left for connected line source\n");
+ return -1;
+ }
+ data[pos++] = AST_CONNECTED_LINE_SOURCE;
+ data[pos++] = sizeof(value);
+ value = htonl(connected->source);
+ memcpy(data + pos, &value, sizeof(value));
+ pos += sizeof(value);
+
+ return pos;
+}
+
+int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
+{
+ size_t pos;
+ unsigned char ie_len;
+ unsigned char ie_id;
+ int32_t value;
+
+ for (pos = 0; pos < datalen; pos += ie_len) {
+ if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) {
+ ast_log(LOG_WARNING, "Invalid connected line update\n");
+ return -1;
+ }
+ ie_id = data[pos++];
+ ie_len = data[pos++];
+ if (datalen < pos + ie_len) {
+ ast_log(LOG_WARNING, "Invalid connected line update\n");
+ return -1;
+ }
+
+ switch (ie_id) {
+ case AST_CONNECTED_LINE_NUMBER:
+ if (connected->id.number) {
+ ast_free(connected->id.number);
+ }
+ connected->id.number = ast_malloc(ie_len + 1);
+ if (connected->id.number) {
+ memcpy(connected->id.number, data + pos, ie_len);
+ connected->id.number[ie_len] = 0;
+ }
+ break;
+ case AST_CONNECTED_LINE_NAME:
+ if (connected->id.name) {
+ ast_free(connected->id.name);
+ }
+ connected->id.name = ast_malloc(ie_len + 1);
+ if (connected->id.name) {
+ memcpy(connected->id.name, data + pos, ie_len);
+ connected->id.name[ie_len] = 0;
+ }
+ break;
+ case AST_CONNECTED_LINE_NUMBER_TYPE:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid connected line type of number (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ connected->id.number_type = data[pos];
+ break;
+ case AST_CONNECTED_LINE_NUMBER_PRESENTATION:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid connected line presentation (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ connected->id.number_presentation = data[pos];
+ break;
+ case AST_CONNECTED_LINE_SOURCE:
+ if (ie_len != sizeof(value)) {
+ ast_log(LOG_WARNING, "Invalid connected line source (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ memcpy(&value, data + pos, sizeof(value));
+ connected->source = ntohl(value);
+ break;
+ default:
+ ast_log(LOG_DEBUG, "Unknown connected line element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected)
+{
+ unsigned char data[1024]; /* This should be large enough */
+ size_t datalen;
+
+ datalen = ast_connected_line_build_data(data, sizeof(data), connected);
+ if (datalen == (size_t) -1) {
+ return;
+ }
+
+ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen);
+}
+
+void ast_channel_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected)
+{
+ unsigned char data[1024]; /* This should be large enough */
+ size_t datalen;
+
+ datalen = ast_connected_line_build_data(data, sizeof(data), connected);
+ if (datalen == (size_t) -1) {
+ return;
+ }
+
+ ast_queue_control_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen);
+}
+
+void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
+{
+ if (&chan->redirecting == redirecting) {
+ /* Don't set to self */
+ return;
+ }
+
+ ast_channel_lock(chan);
+
+ ast_party_id_set(&chan->redirecting.from, &redirecting->from);
+ if (redirecting->from.number
+ && redirecting->from.number != chan->redirecting.from.number) {
+ /*
+ * Must move string to ast_channel.cid.cid_rdnis until it goes away.
+ */
+ if (chan->cid.cid_rdnis) {
+ ast_free(chan->cid.cid_rdnis);
+ }
+ chan->cid.cid_rdnis = chan->redirecting.from.number;
+ chan->redirecting.from.number = NULL;
+ }
+
+ ast_party_id_set(&chan->redirecting.to, &redirecting->to);
+ chan->redirecting.reason = redirecting->reason;
+ chan->redirecting.count = redirecting->count;
+
+ ast_channel_unlock(chan);
+}
+
+/*!
+ * \brief Element identifiers for redirecting indication frame data
+ * \note Only add to the end of this enum.
+ */
+enum {
+ AST_REDIRECTING_FROM_NUMBER,
+ AST_REDIRECTING_FROM_NAME,
+ AST_REDIRECTING_FROM_NUMBER_TYPE,
+ AST_REDIRECTING_FROM_NUMBER_PRESENTATION,
+ AST_REDIRECTING_TO_NUMBER,
+ AST_REDIRECTING_TO_NAME,
+ AST_REDIRECTING_TO_NUMBER_TYPE,
+ AST_REDIRECTING_TO_NUMBER_PRESENTATION,
+ AST_REDIRECTING_REASON,
+ AST_REDIRECTING_COUNT
+};
+
+int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting)
+{
+ int32_t value;
+ size_t length;
+ size_t pos = 0;
+
+ /*
+ * The size of integer values must be fixed in case the frame is
+ * shipped to another machine.
+ */
+
+ /* *************** Redirecting from party id *************** */
+ if (redirecting->from.number) {
+ length = strlen(redirecting->from.number);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting from number\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_NUMBER;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->from.number, length);
+ pos += length;
+ }
+
+ if (redirecting->from.name) {
+ length = strlen(redirecting->from.name);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting from name\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_NAME;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->from.name, length);
+ pos += length;
+ }
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for redirecting from type of number\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_NUMBER_TYPE;
+ data[pos++] = 1;
+ data[pos++] = redirecting->from.number_type;
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for redirecting from presentation\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_FROM_NUMBER_PRESENTATION;
+ data[pos++] = 1;
+ data[pos++] = redirecting->from.number_presentation;
+
+ /* *************** Redirecting to party id *************** */
+ if (redirecting->to.number) {
+ length = strlen(redirecting->to.number);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting to number\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_NUMBER;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->to.number, length);
+ pos += length;
+ }
+
+ if (redirecting->to.name) {
+ length = strlen(redirecting->to.name);
+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+ ast_log(LOG_WARNING, "No space left for redirecting to name\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_NAME;
+ data[pos++] = length;
+ memcpy(data + pos, redirecting->to.name, length);
+ pos += length;
+ }
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for redirecting to type of number\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_NUMBER_TYPE;
+ data[pos++] = 1;
+ data[pos++] = redirecting->to.number_type;
+
+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
+ ast_log(LOG_WARNING, "No space left for redirecting to presentation\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_TO_NUMBER_PRESENTATION;
+ data[pos++] = 1;
+ data[pos++] = redirecting->to.number_presentation;
+
+ /* Redirecting reason */
+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
+ ast_log(LOG_WARNING, "No space left for redirecting reason\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_REASON;
+ data[pos++] = sizeof(value);
+ value = htonl(redirecting->reason);
+ memcpy(data + pos, &value, sizeof(value));
+ pos += sizeof(value);
+
+ /* Redirecting count */
+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
+ ast_log(LOG_WARNING, "No space left for redirecting count\n");
+ return -1;
+ }
+ data[pos++] = AST_REDIRECTING_COUNT;
+ data[pos++] = sizeof(value);
+ value = htonl(redirecting->count);
+ memcpy(data + pos, &value, sizeof(value));
+ pos += sizeof(value);
+
+ return pos;
+}
+
+int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct ast_party_redirecting *redirecting)
+{
+ size_t pos;
+ unsigned char ie_len;
+ unsigned char ie_id;
+ int32_t value;
+
+ for (pos = 0; pos < datalen; pos += ie_len) {
+ if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) {
+ ast_log(LOG_WARNING, "Invalid redirecting update\n");
+ return -1;
+ }
+ ie_id = data[pos++];
+ ie_len = data[pos++];
+ if (datalen < pos + ie_len) {
+ ast_log(LOG_WARNING, "Invalid redirecting update\n");
+ return -1;
+ }
+
+ switch (ie_id) {
+ case AST_REDIRECTING_FROM_NUMBER:
+ if (redirecting->from.number) {
+ ast_free(redirecting->from.number);
+ }
+ redirecting->from.number = ast_malloc(ie_len + 1);
+ if (redirecting->from.number) {
+ memcpy(redirecting->from.number, data + pos, ie_len);
+ redirecting->from.number[ie_len] = 0;
+ }
+ break;
+ case AST_REDIRECTING_FROM_NAME:
+ if (redirecting->from.name) {
+ ast_free(redirecting->from.name);
+ }
+ redirecting->from.name = ast_malloc(ie_len + 1);
+ if (redirecting->from.name) {
+ memcpy(redirecting->from.name, data + pos, ie_len);
+ redirecting->from.name[ie_len] = 0;
+ }
+ break;
+ case AST_REDIRECTING_FROM_NUMBER_TYPE:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid redirecting from type of number (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ redirecting->from.number_type = data[pos];
+ break;
+ case AST_REDIRECTING_FROM_NUMBER_PRESENTATION:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid redirecting from presentation (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ redirecting->from.number_presentation = data[pos];
+ break;
+ case AST_REDIRECTING_TO_NUMBER:
+ if (redirecting->to.number) {
+ ast_free(redirecting->to.number);
+ }
+ redirecting->to.number = ast_malloc(ie_len + 1);
+ if (redirecting->to.number) {
+ memcpy(redirecting->to.number, data + pos, ie_len);
+ redirecting->to.number[ie_len] = 0;
+ }
+ break;
+ case AST_REDIRECTING_TO_NAME:
+ if (redirecting->to.name) {
+ ast_free(redirecting->to.name);
+ }
+ redirecting->to.name = ast_malloc(ie_len + 1);
+ if (redirecting->to.name) {
+ memcpy(redirecting->to.name, data + pos, ie_len);
+ redirecting->to.name[ie_len] = 0;
+ }
+ break;
+ case AST_REDIRECTING_TO_NUMBER_TYPE:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid redirecting to type of number (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ redirecting->to.number_type = data[pos];
+ break;
+ case AST_REDIRECTING_TO_NUMBER_PRESENTATION:
+ if (ie_len != 1) {
+ ast_log(LOG_WARNING, "Invalid redirecting to presentation (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ redirecting->to.number_presentation = data[pos];
+ break;
+ case AST_REDIRECTING_REASON:
+ if (ie_len != sizeof(value)) {
+ ast_log(LOG_WARNING, "Invalid redirecting reason (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ memcpy(&value, data + pos, sizeof(value));
+ redirecting->reason = ntohl(value);
+ break;
+ case AST_REDIRECTING_COUNT:
+ if (ie_len != sizeof(value)) {
+ ast_log(LOG_WARNING, "Invalid redirecting count (%u)\n", (unsigned) ie_len);
+ break;
+ }
+ memcpy(&value, data + pos, sizeof(value));
+ redirecting->count = ntohl(value);
+ break;
+ default:
+ ast_log(LOG_DEBUG, "Unknown redirecting element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
+{
+ unsigned char data[1024]; /* This should be large enough */
+ size_t datalen;
+
+ datalen = ast_redirecting_build_data(data, sizeof(data), redirecting);
+ if (datalen == (size_t) -1) {
+ return;
+ }
+
+ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
+}
+
+void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
+{
+ unsigned char data[1024]; /* This should be large enough */
+ size_t datalen;
+
+ datalen = ast_redirecting_build_data(data, sizeof(data), redirecting);
+ if (datalen == (size_t) -1) {
+ return;
+ }
+
+ ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
+}
+
diff --git a/main/dial.c b/main/dial.c
index e8c9ca221..d38b4829d 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -274,10 +274,12 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann
ast_channel_datastore_inherit(chan, channel->owner);
/* Copy over callerid information */
- S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num));
- S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name));
- S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+ ast_party_redirecting_copy(&channel->owner->redirecting, &chan->redirecting);
+
+ channel->owner->cid.cid_tns = chan->cid.cid_tns;
+
+ ast_connected_line_copy_from_caller(&channel->owner->connected, &chan->cid);
ast_string_field_set(channel->owner, language, chan->language);
ast_string_field_set(channel->owner, accountcode, chan->accountcode);
@@ -285,9 +287,6 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann
if (ast_strlen_zero(channel->owner->musicclass))
ast_string_field_set(channel->owner, musicclass, chan->musicclass);
- channel->owner->cid.cid_pres = chan->cid.cid_pres;
- channel->owner->cid.cid_ton = chan->cid.cid_ton;
- channel->owner->cid.cid_tns = chan->cid.cid_tns;
channel->owner->adsicpe = chan->adsicpe;
channel->owner->transfercapability = chan->transfercapability;
}
@@ -429,6 +428,14 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel
ast_verbose (VERBOSE_PREFIX_3 "%s requested a source update, passing it to %s\n", channel->owner->name, chan->name);
ast_indicate(chan, AST_CONTROL_SRCUPDATE);
break;
+ case AST_CONTROL_CONNECTED_LINE:
+ ast_verb(3, "%s connected line has changed, passing it to %s\n", channel->owner->name, chan->name);
+ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, fr->data.ptr, fr->datalen);
+ break;
+ case AST_CONTROL_REDIRECTING:
+ ast_verb(3, "%s redirecting info has changed, passing it to %s\n", channel->owner->name, chan->name);
+ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen);
+ break;
case AST_CONTROL_PROCEEDING:
ast_verb(3, "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name);
ast_indicate(chan, AST_CONTROL_PROCEEDING);
diff --git a/main/features.c b/main/features.c
index 0b6d7f53c..8efe0dbf7 100644
--- a/main/features.c
+++ b/main/features.c
@@ -1387,6 +1387,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
struct ast_bridge_config bconfig;
struct ast_frame *f;
int l;
+ struct ast_party_connected_line connected_line = {{0,},};
struct ast_datastore *features_datastore;
struct ast_dial_features *dialfeatures = NULL;
@@ -1478,6 +1479,17 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
memset(&bconfig,0,sizeof(struct ast_bridge_config));
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
+ /* We need to get the transferer's connected line information copied
+ * at this point because he is likely to hang up during the bridge with
+ * newchan. This info will be used down below before bridging the
+ * transferee and newchan
+ *
+ * As a result, we need to be sure to free this data before returning
+ * or overwriting it.
+ */
+ ast_channel_lock(transferer);
+ ast_party_connected_line_copy(&connected_line, &transferer->connected);
+ ast_channel_unlock(transferer);
res = ast_bridge_call(transferer, newchan, &bconfig);
if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
ast_hangup(newchan);
@@ -1485,10 +1497,12 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
finishup(transferee);
transferer->_softhangup = 0;
+ ast_party_connected_line_free(&connected_line);
return AST_FEATURE_RETURN_SUCCESS;
}
if (check_compat(transferee, newchan)) {
finishup(transferee);
+ ast_party_connected_line_free(&connected_line);
return -1;
}
ast_indicate(transferee, AST_CONTROL_UNHOLD);
@@ -1499,11 +1513,13 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
|| ast_check_hangup(transferee)
|| ast_check_hangup(newchan)) {
ast_hangup(newchan);
+ ast_party_connected_line_free(&connected_line);
return -1;
}
xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
if (!xferchan) {
ast_hangup(newchan);
+ ast_party_connected_line_free(&connected_line);
return -1;
}
/* Make formats okay */
@@ -1523,6 +1539,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
ast_hangup(xferchan);
ast_hangup(newchan);
+ ast_party_connected_line_free(&connected_line);
return -1;
}
@@ -1557,6 +1574,18 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
}
+ /* Due to a limitation regarding when callerID is set on a Local channel,
+ * we use the transferer's connected line information here.
+ */
+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(xferchan, &connected_line);
+ ast_channel_lock(xferchan);
+ ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid);
+ ast_channel_unlock(xferchan);
+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(newchan, &connected_line);
+ ast_party_connected_line_free(&connected_line);
+
if (ast_stream_and_wait(newchan, xfersound, ""))
ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
bridge_call_thread_launch(tobj);
@@ -1653,11 +1682,24 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
tobj->chan = newchan;
tobj->peer = xferchan;
tobj->bconfig = *config;
-
+
if (tobj->bconfig.end_bridge_callback_data_fixup) {
tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
}
+ ast_channel_lock(newchan);
+ ast_connected_line_copy_from_caller(&connected_line, &newchan->cid);
+ ast_channel_unlock(newchan);
+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(xferchan, &connected_line);
+ ast_channel_lock(xferchan);
+ ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid);
+ ast_channel_unlock(xferchan);
+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ ast_channel_update_connected_line(newchan, &connected_line);
+
+ ast_party_connected_line_free(&connected_line);
+
if (ast_stream_and_wait(newchan, xfersound, ""))
ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
bridge_call_thread_launch(tobj);
@@ -2197,6 +2239,10 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
ast_channel_inherit_variables(caller, chan);
pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
+ ast_channel_lock(chan);
+ ast_connected_line_copy_from_caller(&chan->connected, &caller->cid);
+ ast_channel_unlock(chan);
+
if (ast_call(chan, data, timeout)) {
ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
goto done;
@@ -2266,6 +2312,8 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
f = NULL;
ready=1;
break;
+ } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) {
+ ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
} else if (f->subclass != -1) {
ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
}
@@ -4444,8 +4492,19 @@ int ast_pickup_call(struct ast_channel *chan)
struct ast_channel *cur = ast_channel_search_locked(find_channel_by_group, chan);
if (cur) {
+ struct ast_party_connected_line connected_caller;
+
int res = -1;
ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
+
+ connected_caller = cur->connected;
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_update_connected_line(chan, &connected_caller);
+
+ ast_party_connected_line_collect_caller(&connected_caller, &chan->cid);
+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_channel_queue_connected_line_update(chan, &connected_caller);
+
res = ast_answer(chan);
if (res)
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
diff --git a/main/stun.c b/main/stun.c
index 264430718..74652f90b 100644
--- a/main/stun.c
+++ b/main/stun.c
@@ -28,7 +28,7 @@
#include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 124370 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/_private.h"
#include "asterisk/stun.h"