31 #include "asterisk/res_pjsip.h"
32 #include "asterisk/res_pjsip_session.h"
38 static const pj_str_t diversion_name = {
"Diversion", 9 };
39 static const pj_str_t history_info_name = {
"History-Info", 12 };
40 static pj_str_t HISTINFO_SUPPORTED_NAME = {
"histinfo", 8 };
53 static int sip_is_token(
const char *str)
57 if (ast_strlen_zero(str)) {
65 && !strchr(
"-.!%*_+`'~", *str)) {
85 const unsigned int cause;
87 { AST_REDIRECTING_REASON_UNKNOWN,
"unknown", 404 },
88 { AST_REDIRECTING_REASON_USER_BUSY,
"user-busy", 486 },
89 { AST_REDIRECTING_REASON_NO_ANSWER,
"no-answer", 408 },
90 { AST_REDIRECTING_REASON_UNAVAILABLE,
"unavailable", 503 },
91 { AST_REDIRECTING_REASON_UNCONDITIONAL,
"unconditional", 302 },
92 { AST_REDIRECTING_REASON_TIME_OF_DAY,
"time-of-day", 404 },
93 { AST_REDIRECTING_REASON_DO_NOT_DISTURB,
"do-not-disturb", 404 },
94 { AST_REDIRECTING_REASON_DEFLECTION,
"deflection", 480 },
95 { AST_REDIRECTING_REASON_FOLLOW_ME,
"follow-me", 404 },
96 { AST_REDIRECTING_REASON_OUT_OF_ORDER,
"out-of-service", 404 },
97 { AST_REDIRECTING_REASON_AWAY,
"away", 404 },
98 { AST_REDIRECTING_REASON_CALL_FWD_DTE,
"cf_dte", 404 },
99 { AST_REDIRECTING_REASON_SEND_TO_VM,
"send_to_vm", 404 },
105 return AST_REDIRECTING_REASON_UNCONDITIONAL;
107 return AST_REDIRECTING_REASON_USER_BUSY;
109 return AST_REDIRECTING_REASON_NO_ANSWER;
112 return AST_REDIRECTING_REASON_DEFLECTION;
114 return AST_REDIRECTING_REASON_UNAVAILABLE;
116 return AST_REDIRECTING_REASON_UNKNOWN;
120 static int add_supported(pjsip_tx_data *tdata)
122 pjsip_supported_hdr *hdr;
125 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
128 hdr = pjsip_supported_hdr_create(tdata->pool);
133 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
139 for (i = 0; i < hdr->count; ++i) {
140 if (pj_stricmp(&hdr->values[i], &HISTINFO_SUPPORTED_NAME) == 0) {
145 if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
150 pj_strassign(&hdr->values[hdr->count++], &HISTINFO_SUPPORTED_NAME);
161 if (!ast_strlen_zero(reason->
str)) {
166 for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
167 if (code == reason_table[idx].code) {
168 return reason_table[idx].text;
181 for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
182 if (code == reason_table[idx].code) {
183 return reason_table[idx].cause;
190 static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
192 static const pj_str_t from_name = {
"From", 4 };
194 pjsip_generic_string_hdr *hdr;
198 if (!(hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &diversion_name, NULL))) {
202 pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
205 return pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
206 pj_strlen(&value), &size);
215 static pjsip_fromto_hdr *get_history_info_header(pjsip_rx_data *rdata,
const unsigned int first)
217 static const pj_str_t from_name = {
"From", 4 };
218 pjsip_fromto_hdr * result_hdr = NULL;
220 pjsip_generic_string_hdr *hdr = NULL;
222 hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &history_info_name, NULL);
229 static const pj_str_t index_name = {
"index", 5 };
232 pjsip_fromto_hdr * fromto_hdr = NULL;
233 pjsip_param * index = NULL;
235 pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
238 fromto_hdr = pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
239 pj_strlen(&value), &size);
241 if (fromto_hdr == NULL) {
245 index = pjsip_param_find(&fromto_hdr->other_param, &index_name);
248 if (!pj_strcmp2(&index->value,
"1")) {
257 result_hdr = fromto_hdr;
259 }
while ((hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &history_info_name, hdr->next)));
264 static void set_redirecting_value(
char **dst,
const pj_str_t *src)
269 ast_copy_pj_str(*dst, src, pj_strlen(src) + 1);
273 static void set_redirecting_id(pjsip_name_addr *name_addr,
struct ast_party_id *data,
276 pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr->uri);
280 uri_user = uri->user;
283 semi = pj_strchr(&uri_user,
';');
296 pj_strset(&uri_user, (
char *) pj_strbuf(&uri_user), semi - pj_strbuf(&uri_user));
299 if (pj_strlen(&uri_user)) {
302 set_redirecting_value(&data->
number.
str, &uri_user);
305 if (pj_strlen(&name_addr->display)) {
308 set_redirecting_value(&data->
name.
str, &name_addr->display);
326 static void set_redirecting_reason_by_cause(pjsip_name_addr *name_addr,
329 static const pj_str_t cause_name = {
"cause", 5 };
330 pjsip_uri *uri = name_addr->uri;
331 pjsip_param *cause = NULL;
332 unsigned long cause_value = 0;
334 if (!ast_sip_is_allowed_uri(uri)) {
338 cause = ast_sip_pjsip_uri_get_other_param(uri, &cause_name);
344 cause_value = pj_strtoul(&cause->value);
346 data->
code = cause_to_reason(cause_value);
351 static void set_redirecting_reason(pjsip_fromto_hdr *from_info, pjsip_name_addr *to_info,
354 static const pj_str_t reason_name = {
"reason", 6 };
355 pjsip_param *reason = pjsip_param_find(&from_info->other_param, &reason_name);
360 set_redirecting_reason_by_cause(to_info, data);
365 set_redirecting_value(&data->
str, &reason->value);
373 if (*reason_str ==
'"') {
378 if (data->
code < 0) {
379 data->
code = AST_REDIRECTING_REASON_UNKNOWN;
387 pjsip_fromto_hdr *from_info,
388 pjsip_name_addr *to_info)
398 memset(&update, 0,
sizeof(update));
400 data.reason.
code = AST_REDIRECTING_REASON_UNKNOWN;
402 set_redirecting_id((pjsip_name_addr*)from_info->uri,
403 &data.from, &update.from);
404 set_redirecting_reason(from_info, to_info, &data.reason);
407 copy_redirecting_id(&data.from, &session->
id, &update.from);
411 set_redirecting_id(to_info, &data.to, &update.to);
421 if (session->
inv_session->role == PJSIP_ROLE_UAC) {
427 static int diversion_incoming_request(
struct ast_sip_session *session, pjsip_rx_data *rdata)
429 pjsip_fromto_hdr *hdr = get_diversion_header(rdata);
432 set_redirecting(session, hdr, (pjsip_name_addr*)
433 PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri);
435 pjsip_fromto_hdr *history_info_to;
436 pjsip_fromto_hdr *history_info_from;
437 history_info_to = get_history_info_header(rdata, 0);
439 if (history_info_to) {
442 history_info_from = get_history_info_header(rdata, 1);
443 set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri);
450 static void diversion_incoming_response(
struct ast_sip_session *session, pjsip_rx_data *rdata)
452 static const pj_str_t contact_name = {
"Contact", 7 };
453 static const pj_str_t contact_name_s = {
"m", 1 };
455 pjsip_status_line status = rdata->msg_info.msg->line.status;
456 pjsip_fromto_hdr *div_hdr;
457 pjsip_fromto_hdr *history_info_to;
458 pjsip_fromto_hdr *history_info_from;
459 pjsip_contact_hdr *contact_hdr;
461 if ((status.code != 302) && (status.code != 181)) {
468 if (!(div_hdr = get_diversion_header(rdata))) {
469 history_info_to = get_history_info_header(rdata, 0);
471 if (history_info_to) {
474 history_info_from = get_history_info_header(rdata, 1);
475 set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri);
479 div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
484 if (status.code == 302) {
486 contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL);
488 set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri :
489 (pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri);
492 set_redirecting(session, PJSIP_MSG_TO_HDR(rdata->msg_info.msg),
493 div_hdr ? (pjsip_name_addr*)div_hdr->uri : NULL);
506 static const pj_str_t reason_name = {
"reason", 6 };
508 pjsip_fromto_hdr *hdr;
509 pjsip_name_addr *name_addr;
511 pjsip_fromto_hdr *old_hdr;
512 const char *reason_str;
513 const char *quote_str;
518 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
525 base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
531 hdr = pjsip_from_hdr_create(tdata->pool);
532 hdr->type = PJSIP_H_OTHER;
533 hdr->sname = hdr->name = diversion_name;
535 name_addr = pjsip_uri_clone(tdata->pool, base);
537 pj_strdup2(tdata->pool, &name_addr->display, id->
name.
str);
538 pj_strdup2(tdata->pool, (pj_str_t *)ast_sip_pjsip_uri_get_username(name_addr->uri), id->
number.
str);
540 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
541 param->name = reason_name;
543 reason_str = reason_code_to_str(&data->
reason);
546 quote_str = *reason_str ==
'\"' || sip_is_token(reason_str) ?
"" :
"\"";
548 reason_buf = pj_pool_alloc(tdata->pool, strlen(reason_str) + 3);
549 sprintf(reason_buf,
"%s%s%s", quote_str, reason_str, quote_str);
551 param->value = pj_str(reason_buf);
553 pj_list_insert_before(&hdr->other_param, param);
555 hdr->uri = (pjsip_uri *) name_addr;
556 old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &diversion_name, NULL);
558 pj_list_erase(old_hdr);
560 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
572 static const pj_str_t index_name = {
"index", 5 };
573 static const pj_str_t cause_name = {
"cause", 5 };
574 static const pj_str_t first_index = {
"1", 1 };
575 static const pj_str_t last_index = {
"1.1", 3 };
577 pjsip_fromto_hdr *hdr;
578 pjsip_name_addr *name_addr;
581 pjsip_fromto_hdr *old_hdr;
588 pjsip_uri *base = PJSIP_MSG_TO_HDR(tdata->msg)->uri;
591 hdr = pjsip_from_hdr_create(tdata->pool);
592 hdr->type = PJSIP_H_OTHER;
593 hdr->sname = hdr->name = history_info_name;
595 name_addr = pjsip_uri_clone(tdata->pool, base);
596 uri = pjsip_uri_get_uri(name_addr->uri);
600 pj_strdup2(tdata->pool, &name_addr->display, from->
name.
str);
601 pj_strdup2(tdata->pool, &uri->user, from->
number.
str);
604 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
605 param->name = index_name;
606 param->value = first_index;
609 pj_list_insert_before(&hdr->other_param, param);
610 hdr->uri = (pjsip_uri *) name_addr;
612 while ((old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &history_info_name, NULL)) != NULL) {
613 pj_list_erase(old_hdr);
616 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
622 hdr = pjsip_from_hdr_create(tdata->pool);
623 hdr->type = PJSIP_H_OTHER;
624 hdr->sname = hdr->name = history_info_name;
626 name_addr = pjsip_uri_clone(tdata->pool, base);
627 uri = pjsip_uri_get_uri(name_addr->uri);
629 pj_strdup2(tdata->pool, &name_addr->display, to->
name.
str);
630 pj_strdup2(tdata->pool, &uri->user, to->
number.
str);
632 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
633 param->name = index_name;
634 param->value = last_index;
635 pj_list_insert_before(&hdr->other_param, param);
637 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
638 param->name = cause_name;
639 cause = reason_code_to_cause(&data->
reason);
640 cause_buf = pj_pool_alloc(tdata->pool, 4);
641 snprintf(cause_buf, 4,
"%ud", cause);
642 param->value = pj_str(cause_buf);
643 pj_list_insert_before(&uri->other_param, param);
644 hdr->uri = (pjsip_uri *) name_addr;
646 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
649 static void get_redirecting_add_diversion(
struct ast_sip_session *session, pjsip_tx_data *tdata)
653 add_supported(tdata);
656 (data = ast_channel_redirecting(session->
channel))->count) {
657 add_diversion_header(tdata, data);
660 data = ast_channel_redirecting(session->
channel);
661 add_history_info_header(tdata, data);
673 static void diversion_outgoing_request(
struct ast_sip_session *session, pjsip_tx_data *tdata)
675 get_redirecting_add_diversion(session, tdata);
685 static void diversion_outgoing_response(
struct ast_sip_session *session, pjsip_tx_data *tdata)
687 struct pjsip_status_line status = tdata->msg->line.status;
690 if (PJSIP_IS_STATUS_IN_CLASS(status.code, 300) || (status.code == 181)) {
691 get_redirecting_add_diversion(session, tdata);
699 .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 100,
700 .incoming_request = diversion_incoming_request,
701 .incoming_response = diversion_incoming_response,
702 .outgoing_request = diversion_outgoing_request,
703 .outgoing_response = diversion_outgoing_response,
704 .response_priority = AST_SIP_SESSION_BEFORE_MEDIA,
707 static int load_module(
void)
712 ast_sip_session_register_supplement(&diversion_supplement);
716 static int unload_module(
void)
718 ast_sip_session_unregister_supplement(&diversion_supplement);
722 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP Add Diversion Header Support",
723 .support_level = AST_MODULE_SUPPORT_CORE,
725 .unload = unload_module,
727 .requires =
"res_pjsip,res_pjsip_session",
Information needed to identify an endpoint in a call.
struct ast_sip_endpoint * endpoint
char * str
Subscriber phone number (Malloced)
unsigned int send_history_info
Asterisk main include file. File version handling, generic pbx functions.
String manipulation functions.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
struct ast_party_name name
Subscriber name.
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
int ast_redirecting_reason_parse(const char *data)
Convert redirecting reason text code to value (used in config file parsing)
void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
Copy the source party id information to the destination party id.
char * str
Subscriber name (Malloced)
#define ast_strdup(str)
A wrapper for strdup()
struct pjsip_inv_session * inv_session
int code
enum AST_REDIRECTING_REASON value for redirection
A structure describing a SIP session.
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Diversion header reasons.
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
struct ast_channel * channel
void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Set the redirecting id information in the Asterisk channel.
#define ast_malloc(len)
A wrapper for malloc()
AST_REDIRECTING_REASON
redirecting reason codes.
struct ast_sip_endpoint_id_configuration id
Redirecting reason information.
Indicate what information in ast_party_id should be set.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
char * str
a string value for the redirecting reason
struct ast_party_redirecting_reason reason
Reason for the redirection.
A supplement to SIP message processing.
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Indicate what information in ast_party_redirecting should be set.
struct ast_party_id to
Call is redirecting to a new party (Sent to the caller)
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Queue a redirecting update frame on a channel.
unsigned char valid
TRUE if the name information is valid/present.
void ast_set_party_id_all(struct ast_set_party_id *update_id)
Set the update marker to update all information of a corresponding party id.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
unsigned char valid
TRUE if the number information is valid/present.
struct ast_party_number number
Subscriber phone number.
unsigned int send_diversion