Asterisk - The Open Source Telephony Project GIT-master-77d630f
res_pjsip_diversion.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Kevin Harwell <kharwell@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*** MODULEINFO
20 <depend>pjproject</depend>
21 <depend>res_pjsip</depend>
22 <depend>res_pjsip_session</depend>
23 <support_level>core</support_level>
24 ***/
25
26#include "asterisk.h"
27
28#include <pjsip.h>
29#include <pjsip_ua.h>
30
31#include "asterisk/res_pjsip.h"
33#include "asterisk/callerid.h"
34#include "asterisk/channel.h"
35#include "asterisk/module.h"
36#include "asterisk/strings.h"
37
38static const pj_str_t diversion_name = { "Diversion", 9 };
39static const pj_str_t history_info_name = { "History-Info", 12 };
40static pj_str_t HISTINFO_SUPPORTED_NAME = { "histinfo", 8 };
41
42/*
43 * Should we queue a frame with the updated redirecting information.
44 */
45typedef enum {
49
50/*!
51 * \internal
52 * \brief Determine if the given string is a SIP token.
53 * \since 13.8.0
54 *
55 * \param str String to determine if is a SIP token.
56 *
57 * \note A token is defined by RFC3261 Section 25.1
58 *
59 * \return Non-zero if the string is a SIP token.
60 */
61static int sip_is_token(const char *str)
62{
63 int is_token;
64
65 if (ast_strlen_zero(str)) {
66 /* An empty string is not a token. */
67 return 0;
68 }
69
70 is_token = 1;
71 do {
72 if (!isalnum(*str)
73 && !strchr("-.!%*_+`'~", *str)) {
74 /* The character is not allowed in a token. */
75 is_token = 0;
76 break;
77 }
78 } while (*++str);
79
80 return is_token;
81}
82
83/*! \brief Diversion header reasons
84 *
85 * The core defines a bunch of constants used to define
86 * redirecting reasons. This provides a translation table
87 * between those and the strings which may be present in
88 * a SIP Diversion header
89 */
90static const struct reasons {
92 const char *text;
93 const unsigned int cause;
94} reason_table[] = {
95 { AST_REDIRECTING_REASON_UNKNOWN, "unknown", 404 },
96 { AST_REDIRECTING_REASON_USER_BUSY, "user-busy", 486 },
97 { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer", 408 },
98 { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable", 503 },
99 { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional", 302 },
100 { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day", 404 },
101 { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb", 404 },
102 { AST_REDIRECTING_REASON_DEFLECTION, "deflection", 480 },
103 { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me", 404 },
104 { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service", 404 },
105 { AST_REDIRECTING_REASON_AWAY, "away", 404 },
106 { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", 404 }, /* Non-standard */
107 { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm", 404 }, /* Non-standard */
109
110static enum AST_REDIRECTING_REASON cause_to_reason(const unsigned long cause) {
111 switch(cause) {
112 case 302:
114 case 486:
116 case 408:
118 case 480:
119 case 487:
121 case 503:
123 default:
125 }
126}
127
128static int add_supported(pjsip_tx_data *tdata)
129{
130 pjsip_supported_hdr *hdr;
131 unsigned int i;
132
133 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
134 if (!hdr) {
135 /* insert a new Supported header */
136 hdr = pjsip_supported_hdr_create(tdata->pool);
137 if (!hdr) {
138 return -1;
139 }
140
141 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
142 }
143
144 /* Asterisk can send multiple "181 Call forwarded" in a single session,
145 * we might have already modified Supported before
146 */
147 for (i = 0; i < hdr->count; ++i) {
148 if (pj_stricmp(&hdr->values[i], &HISTINFO_SUPPORTED_NAME) == 0) {
149 return 0;
150 }
151 }
152
153 if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
154 return -1;
155 }
156
157 /* add on to the existing Supported header */
158 pj_strassign(&hdr->values[hdr->count++], &HISTINFO_SUPPORTED_NAME);
159
160 return 0;
161}
162
163static const char *reason_code_to_str(const struct ast_party_redirecting_reason *reason)
164{
165 int idx;
166 int code;
167
168 /* use specific string if given */
169 if (!ast_strlen_zero(reason->str)) {
170 return reason->str;
171 }
172
173 code = reason->code;
174 for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
175 if (code == reason_table[idx].code) {
176 return reason_table[idx].text;
177 }
178 }
179
180 return "unknown";
181}
182
183static const unsigned int reason_code_to_cause(const struct ast_party_redirecting_reason *reason)
184{
185 int idx;
186 int code;
187
188 code = reason->code;
189 for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
190 if (code == reason_table[idx].code) {
191 return reason_table[idx].cause;
192 }
193 }
194
195 return 404;
196}
197
198static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
199{
200 static const pj_str_t from_name = { "From", 4 };
201
202 pjsip_generic_string_hdr *hdr;
203 pj_str_t value;
204 int size;
205
206 if (!(hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &diversion_name, NULL))) {
207 return NULL;
208 }
209
210 pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
211
212 /* parse as a fromto header */
213 return pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
214 pj_strlen(&value), &size);
215}
216
217/* Asterisk keeps track of 2 things. The redirected from address and
218 * the redirected to address. If first=0 method will get the most recent
219 * redirection target for use as the redirected to address. If first=1
220 * then this method will get the original redirection target (index=1)
221 * for use as the redirected from address.
222 */
223static pjsip_fromto_hdr *get_history_info_header(pjsip_rx_data *rdata, const unsigned int first)
224{
225 static const pj_str_t from_name = { "From", 4 };
226 pjsip_fromto_hdr * result_hdr = NULL;
227
228 pjsip_generic_string_hdr *hdr = NULL;
229
230 hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &history_info_name, NULL);
231
232 if (!hdr) {
233 return NULL;
234 }
235
236 do {
237 static const pj_str_t index_name = { "index", 5 };
238 pj_str_t value;
239 int size;
240 pjsip_fromto_hdr * fromto_hdr = NULL;
241 pjsip_param * index = NULL;
242
243 pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
244
245 /* parse as a fromto header */
246 fromto_hdr = pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
247 pj_strlen(&value), &size);
248
249 if (fromto_hdr == NULL) {
250 continue;
251 }
252
253 index = pjsip_param_find(&fromto_hdr->other_param, &index_name);
254
255 if (index) {
256 if (!pj_strcmp2(&index->value, "1")) {
257 if (!first) {
258 continue;
259 } else {
260 return fromto_hdr;
261 }
262 }
263 }
264
265 result_hdr = fromto_hdr;
266
267 } while ((hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &history_info_name, hdr->next)));
268
269 return result_hdr;
270}
271
272static void set_redirecting_value(char **dst, const pj_str_t *src)
273{
274 ast_free(*dst);
275 *dst = ast_malloc(pj_strlen(src) + 1);
276 if (*dst) {
277 ast_copy_pj_str(*dst, src, pj_strlen(src) + 1);
278 }
279}
280
281static void set_redirecting_id(pjsip_name_addr *name_addr, struct ast_party_id *data,
282 struct ast_set_party_id *update)
283{
284 pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr->uri);
285 char *semi;
286 pj_str_t uri_user;
287
288 uri_user = uri->user;
289
290 /* Always truncate redirecting number at a semicolon. */
291 semi = pj_strchr(&uri_user, ';');
292 if (semi) {
293 /*
294 * We need to be able to handle URI's looking like
295 * "sip:1235557890;phone-context=national@x.x.x.x;user=phone"
296 *
297 * Where the uri->user field will result in:
298 * "1235557890;phone-context=national"
299 *
300 * People don't care about anything after the semicolon
301 * showing up on their displays even though the RFC
302 * allows the semicolon.
303 */
304 pj_strset(&uri_user, (char *) pj_strbuf(&uri_user), semi - pj_strbuf(&uri_user));
305 }
306
307 if (pj_strlen(&uri_user)) {
308 update->number = 1;
309 data->number.valid = 1;
310 set_redirecting_value(&data->number.str, &uri_user);
311 }
312
313 if (pj_strlen(&name_addr->display)) {
314 update->name = 1;
315 data->name.valid = 1;
316 set_redirecting_value(&data->name.str, &name_addr->display);
317 }
318}
319
320static void copy_redirecting_id(struct ast_party_id *dst, const struct ast_party_id *src,
321 struct ast_set_party_id *update)
322{
323 ast_party_id_copy(dst, src);
324
325 if (dst->number.valid) {
326 update->number = 1;
327 }
328
329 if (dst->name.valid) {
330 update->name = 1;
331 }
332}
333
334static void set_redirecting_reason_by_cause(pjsip_name_addr *name_addr,
335 struct ast_party_redirecting_reason *data)
336{
337 static const pj_str_t cause_name = { "cause", 5 };
338 pjsip_uri *uri = name_addr->uri;
339 pjsip_param *cause = NULL;
340 unsigned long cause_value = 0;
341
342 if (!ast_sip_is_allowed_uri(uri)) {
343 return;
344 }
345
346 cause = ast_sip_pjsip_uri_get_other_param(uri, &cause_name);
347
348 if (!cause) {
349 return;
350 }
351
352 cause_value = pj_strtoul(&cause->value);
353
354 data->code = cause_to_reason(cause_value);
355 ast_free(data->str);
356 data->str = ast_strdup("");
357}
358
359static void set_redirecting_reason(pjsip_fromto_hdr *from_info, pjsip_name_addr *to_info,
360 struct ast_party_redirecting_reason *data)
361{
362 static const pj_str_t reason_name = { "reason", 6 };
363 pjsip_param *reason = pjsip_param_find(&from_info->other_param, &reason_name);
364 char *reason_str;
365
366 if (!reason) {
367 if (to_info) {
368 set_redirecting_reason_by_cause(to_info, data);
369 }
370 return;
371 }
372
373 set_redirecting_value(&data->str, &reason->value);
374 if (!data->str) {
375 /* Oops, allocation failure */
376 return;
377 }
378 reason_str = ast_strdupa(data->str);
379
380 /* Remove any enclosing double-quotes */
381 if (*reason_str == '"') {
382 reason_str = ast_strip_quoted(reason_str, "\"", "\"");
383 }
384
385 data->code = ast_redirecting_reason_parse(reason_str);
386 if (data->code < 0) {
388 } else {
389 ast_free(data->str);
390 data->str = ast_strdup("");
391 }
392}
393
395 pjsip_fromto_hdr *from_info,
396 pjsip_name_addr *to_info,
397 pjsip_diversion_send_update send_update)
398{
399 struct ast_party_redirecting data;
401
402 if (!session->channel) {
403 return;
404 }
405
407 memset(&update, 0, sizeof(update));
408
410 if (from_info) {
411 set_redirecting_id((pjsip_name_addr*)from_info->uri,
412 &data.from, &update.from);
413 set_redirecting_reason(from_info, to_info, &data.reason);
415 } else {
416 copy_redirecting_id(&data.from, &session->id, &update.from);
417 }
418
419 if (to_info) {
420 set_redirecting_id(to_info, &data.to, &update.to);
421 }
422
423 ast_set_party_id_all(&update.priv_orig);
424 ast_set_party_id_all(&update.priv_from);
426 ++data.count;
427
428 ast_channel_set_redirecting(session->channel, &data, &update);
429 /* Only queue an indication if it was due to a response received pre media*/
430 if (session->inv_session->role == PJSIP_ROLE_UAC && send_update) {
432 }
434}
435
436static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
437{
438 pjsip_fromto_hdr *hdr = get_diversion_header(rdata);
439
440 if (hdr) {
441 set_redirecting(session, hdr, (pjsip_name_addr*)
442 PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri, PJSIP_DIVERSION_SEND_UPDATE);
443 } else {
444 pjsip_fromto_hdr *history_info_to;
445 pjsip_fromto_hdr *history_info_from;
446 history_info_to = get_history_info_header(rdata, 0);
447
448 if (history_info_to) {
449 /* If History-Info is present, then it will also include the original
450 redirected-from in addition to the redirected-to */
451 history_info_from = get_history_info_header(rdata, 1);
452 set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri, PJSIP_DIVERSION_SEND_UPDATE);
453 }
454 }
455
456 return 0;
457}
458
459static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_diversion_send_update send_update)
460{
461 static const pj_str_t contact_name = { "Contact", 7 };
462 static const pj_str_t contact_name_s = { "m", 1 };
463
464 pjsip_status_line status = rdata->msg_info.msg->line.status;
465 pjsip_fromto_hdr *div_hdr;
466 pjsip_fromto_hdr *history_info_to;
467 pjsip_fromto_hdr *history_info_from;
468 pjsip_contact_hdr *contact_hdr;
469
470 if ((status.code != 302) && (status.code != 181)) {
471 return;
472 }
473
474 /* use the diversion header info if there is one. if not one then use the
475 the history-info, if that doesn't exist, use session caller id info. if
476 that doesn't exist use info from the To hdr*/
477 if (!(div_hdr = get_diversion_header(rdata))) {
478 history_info_to = get_history_info_header(rdata, 0);
479
480 if (history_info_to) {
481 /* If History-Info is present, then it will also include the original
482 redirected-from in addition to the redirected-to */
483 history_info_from = get_history_info_header(rdata, 1);
484 set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri, send_update);
485 return;
486 }
487 if (!div_hdr && !session->id.number.valid) {
488 div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
489 }
490 }
491
492
493 if (status.code == 302) {
494 /* With 302, Contact indicates the final destination and possibly Diversion indicates the hop before */
495 contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL);
496 set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri :
497 (pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri, send_update);
498 } else {
499 /* With 181, Diversion is non-standard, but if present indicates the new final destination, and To indicating the original */
500 set_redirecting(session, PJSIP_MSG_TO_HDR(rdata->msg_info.msg),
501 div_hdr ? (pjsip_name_addr*)div_hdr->uri : NULL, send_update);
502 }
503}
504
505static void diversion_incoming_response_media(struct ast_sip_session *session, pjsip_rx_data *rdata)
506{
507 /* Trigger an update if the event is triggered by the PJSIP AST_SIP_SESSION_BEFORE_MEDIA callback */
509 return;
510}
511
512static void diversion_incoming_response_redirecting(struct ast_sip_session *session, pjsip_rx_data *rdata)
513{
514 /* Don't trigger an update if the event is triggered by the PJSIP AST_SIP_SESSION_REDIRECTING callback
515 otherwise, we will send a duplicate 181 to the UAC */
517 return;
518}
519
520/*!
521 * \internal
522 * \brief Adds diversion header information to an outbound SIP message
523 *
524 * \param tdata The outbound message
525 * \param data The redirecting data used to fill parts of the diversion header
526 */
527static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
528{
529 static const pj_str_t reason_name = { "reason", 6 };
530
531 pjsip_fromto_hdr *hdr;
532 pjsip_name_addr *name_addr;
533 pjsip_param *param;
534 pjsip_fromto_hdr *old_hdr;
535 const char *reason_str;
536 const char *quote_str;
537 char *reason_buf;
538 pjsip_uri *base;
539
540 struct ast_party_id *id = NULL;
541 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
542 id = &data->from;
543 } else {
544 /* In responses indicate the new destination */
545 id = &data->to;
546 }
547
548 base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
549
550 if (!id->number.valid || ast_strlen_zero(id->number.str)) {
551 return;
552 }
553
554 hdr = pjsip_from_hdr_create(tdata->pool);
555 hdr->type = PJSIP_H_OTHER;
556 hdr->sname = hdr->name = diversion_name;
557
558 name_addr = pjsip_uri_clone(tdata->pool, base);
559
560 pj_strdup2(tdata->pool, &name_addr->display, id->name.str);
561 pj_strdup2(tdata->pool, (pj_str_t *)ast_sip_pjsip_uri_get_username(name_addr->uri), id->number.str);
562
563 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
564 param->name = reason_name;
565
566 reason_str = reason_code_to_str(&data->reason);
567
568 /* Reason is either already quoted or it is a token to not need quotes added. */
569 quote_str = *reason_str == '\"' || sip_is_token(reason_str) ? "" : "\"";
570
571 reason_buf = pj_pool_alloc(tdata->pool, strlen(reason_str) + 3);
572 sprintf(reason_buf, "%s%s%s", quote_str, reason_str, quote_str);/* Safe */
573
574 param->value = pj_str(reason_buf);
575
576 pj_list_insert_before(&hdr->other_param, param);
577
578 hdr->uri = (pjsip_uri *) name_addr;
579 old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &diversion_name, NULL);
580 if (old_hdr) {
581 pj_list_erase(old_hdr);
582 }
583 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
584}
585
586/*!
587 * \internal
588 * \brief Adds history-info header information to an outbound SIP message
589 *
590 * \param tdata The outbound message
591 * \param data The redirecting data used to fill parts of the history-info header
592 */
593static void add_history_info_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
594{
595 static const pj_str_t index_name = { "index", 5 };
596 static const pj_str_t cause_name = { "cause", 5 };
597 static const pj_str_t first_index = { "1", 1 };
598 static const pj_str_t last_index = { "1.1", 3 };
599
600 pjsip_fromto_hdr *hdr;
601 pjsip_name_addr *name_addr;
602 pjsip_sip_uri *uri;
603 pjsip_param *param;
604 pjsip_fromto_hdr *old_hdr;
605 unsigned int cause;
606 char *cause_buf;
607
608 struct ast_party_id *to = &data->to;
609 struct ast_party_id *from = &data->from;
610
611 pjsip_uri *base = PJSIP_MSG_TO_HDR(tdata->msg)->uri;
612
613
614 hdr = pjsip_from_hdr_create(tdata->pool);
615 hdr->type = PJSIP_H_OTHER;
616 hdr->sname = hdr->name = history_info_name;
617
618 name_addr = pjsip_uri_clone(tdata->pool, base);
619 uri = pjsip_uri_get_uri(name_addr->uri);
620
621 /* if no redirecting information, then TO is the original destination */
622 if (from->number.valid && !ast_strlen_zero(from->number.str)) {
623 pj_strdup2(tdata->pool, &name_addr->display, from->name.str);
624 pj_strdup2(tdata->pool, &uri->user, from->number.str);
625 }
626
627 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
628 param->name = index_name;
629 param->value = first_index;
630
631
632 pj_list_insert_before(&hdr->other_param, param);
633 hdr->uri = (pjsip_uri *) name_addr;
634
635 while ((old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &history_info_name, NULL)) != NULL) {
636 pj_list_erase(old_hdr);
637 }
638
639 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
640
641 if (!to->number.valid || ast_strlen_zero(to->number.str)) {
642 return;
643 }
644
645 hdr = pjsip_from_hdr_create(tdata->pool);
646 hdr->type = PJSIP_H_OTHER;
647 hdr->sname = hdr->name = history_info_name;
648
649 name_addr = pjsip_uri_clone(tdata->pool, base);
650 uri = pjsip_uri_get_uri(name_addr->uri);
651
652 pj_strdup2(tdata->pool, &name_addr->display, to->name.str);
653 pj_strdup2(tdata->pool, &uri->user, to->number.str);
654
655 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
656 param->name = index_name;
657 param->value = last_index;
658 pj_list_insert_before(&hdr->other_param, param);
659
660 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
661 param->name = cause_name;
662 cause = reason_code_to_cause(&data->reason);
663 cause_buf = pj_pool_alloc(tdata->pool, 4);
664 snprintf(cause_buf, 4, "%ud", cause);
665 param->value = pj_str(cause_buf);
666 pj_list_insert_before(&uri->other_param, param);
667 hdr->uri = (pjsip_uri *) name_addr;
668
669 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
670}
671
672static void get_redirecting_add_diversion(struct ast_sip_session *session, pjsip_tx_data *tdata)
673{
674 struct ast_party_redirecting *data;
675
676 add_supported(tdata);
677
678 if (session->channel && session->endpoint->id.send_diversion &&
679 (data = ast_channel_redirecting(session->channel))->count) {
680 add_diversion_header(tdata, data);
681 }
682 if (session->channel && session->endpoint->id.send_history_info) {
683 data = ast_channel_redirecting(session->channel);
684 add_history_info_header(tdata, data);
685 }
686}
687
688/*!
689 * \internal
690 * \brief Adds a diversion header to an outgoing INVITE request if
691 * redirecting information is available.
692 *
693 * \param session The session on which the INVITE request is to be sent
694 * \param tdata The outbound INVITE request
695 */
696static void diversion_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
697{
699}
700
701/*!
702 * \internal
703 * \brief Adds a diversion header to an outgoing 3XX response
704 *
705 * \param session The session on which the INVITE response is to be sent
706 * \param tdata The outbound INVITE response
707 */
708static void diversion_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
709{
710 struct pjsip_status_line status = tdata->msg->line.status;
711
712 /* add to 302 and 181 */
713 if (PJSIP_IS_STATUS_IN_CLASS(status.code, 300) || (status.code == 181)) {
715 }
716}
717
719 .method = "INVITE",
720 /* this supplement needs to be called after caller id
721 and after the channel has been created */
722 .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 100,
723 .incoming_response = diversion_incoming_response_media,
724 .response_priority = AST_SIP_SESSION_BEFORE_MEDIA,
725};
726
728 .method = "INVITE",
729 /* this supplement needs to be called after caller id
730 and after the channel has been created */
731 .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 100,
732 .incoming_request = diversion_incoming_request,
733 .incoming_response = diversion_incoming_response_redirecting,
734 .outgoing_request = diversion_outgoing_request,
735 .outgoing_response = diversion_outgoing_response,
736 .response_priority = AST_SIP_SESSION_BEFORE_REDIRECTING,
737};
738
739static int load_module(void)
740{
741 /* Because we are passing static memory to pjsip, we need to make sure it
742 * stays valid while we potentially have active sessions */
747}
748
749static int unload_module(void)
750{
753 return 0;
754}
755
756AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Add Diversion Header Support",
757 .support_level = AST_MODULE_SUPPORT_CORE,
758 .load = load_module,
759 .unload = unload_module,
760 .load_pri = AST_MODPRI_APP_DEPEND,
761 .requires = "res_pjsip,res_pjsip_session",
jack_status_t status
Definition: app_jack.c:149
const char * str
Definition: app_jack.c:150
enum queue_result id
Definition: app_queue.c:1767
struct sla_ringing_trunk * first
Definition: app_sla.c:338
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
AST_REDIRECTING_REASON
redirecting reason codes.
Definition: callerid.h:498
@ AST_REDIRECTING_REASON_AWAY
Definition: callerid.h:509
@ AST_REDIRECTING_REASON_UNKNOWN
Definition: callerid.h:499
@ AST_REDIRECTING_REASON_SEND_TO_VM
Definition: callerid.h:511
@ AST_REDIRECTING_REASON_NO_ANSWER
Definition: callerid.h:501
@ AST_REDIRECTING_REASON_DO_NOT_DISTURB
Definition: callerid.h:505
@ AST_REDIRECTING_REASON_FOLLOW_ME
Definition: callerid.h:507
@ AST_REDIRECTING_REASON_DEFLECTION
Definition: callerid.h:506
@ AST_REDIRECTING_REASON_UNAVAILABLE
Definition: callerid.h:502
@ AST_REDIRECTING_REASON_UNCONDITIONAL
Definition: callerid.h:503
@ AST_REDIRECTING_REASON_CALL_FWD_DTE
Definition: callerid.h:510
@ AST_REDIRECTING_REASON_OUT_OF_ORDER
Definition: callerid.h:508
@ AST_REDIRECTING_REASON_TIME_OF_DAY
Definition: callerid.h:504
@ AST_REDIRECTING_REASON_USER_BUSY
Definition: callerid.h:500
int ast_redirecting_reason_parse(const char *data)
Convert redirecting reason text code to value (used in config file parsing)
Definition: callerid.c:1423
General Asterisk PBX channel definitions.
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2090
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.
Definition: channel.c:9133
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
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.
Definition: channel.c:10311
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.
Definition: channel.c:1718
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.
Definition: channel.c:1733
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2147
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition: codec_g726.c:367
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:478
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_APP_DEPEND
Definition: module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
struct pjsip_param * ast_sip_pjsip_uri_get_other_param(pjsip_uri *uri, const pj_str_t *param_str)
Find an 'other' SIP/SIPS URI parameter by name.
Definition: res_pjsip.c:3511
const pj_str_t * ast_sip_pjsip_uri_get_username(pjsip_uri *uri)
Get the user portion of the pjsip_uri.
Definition: res_pjsip.c:3477
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition: res_pjsip.c:3472
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition: res_pjsip.h:3339
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
static void set_redirecting_reason(pjsip_fromto_hdr *from_info, pjsip_name_addr *to_info, struct ast_party_redirecting_reason *data)
static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_diversion_send_update send_update)
static const struct reasons reason_table[]
static void diversion_incoming_response_redirecting(struct ast_sip_session *session, pjsip_rx_data *rdata)
static pjsip_fromto_hdr * get_history_info_header(pjsip_rx_data *rdata, const unsigned int first)
static const unsigned int reason_code_to_cause(const struct ast_party_redirecting_reason *reason)
static struct ast_sip_session_supplement diversion_supplement_redirecting
static void add_history_info_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
pjsip_diversion_send_update
@ PJSIP_DIVERSION_NOSEND_UPDATE
@ PJSIP_DIVERSION_SEND_UPDATE
static void set_redirecting_reason_by_cause(pjsip_name_addr *name_addr, struct ast_party_redirecting_reason *data)
static const pj_str_t history_info_name
static int add_supported(pjsip_tx_data *tdata)
static pj_str_t HISTINFO_SUPPORTED_NAME
static pjsip_fromto_hdr * get_diversion_header(pjsip_rx_data *rdata)
static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
static void diversion_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
static const pj_str_t diversion_name
static void diversion_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
static void diversion_incoming_response_media(struct ast_sip_session *session, pjsip_rx_data *rdata)
static void set_redirecting(struct ast_sip_session *session, pjsip_fromto_hdr *from_info, pjsip_name_addr *to_info, pjsip_diversion_send_update send_update)
static void get_redirecting_add_diversion(struct ast_sip_session *session, pjsip_tx_data *tdata)
static void set_redirecting_value(char **dst, const pj_str_t *src)
static void set_redirecting_id(pjsip_name_addr *name_addr, struct ast_party_id *data, struct ast_set_party_id *update)
static int load_module(void)
static struct ast_sip_session_supplement diversion_supplement_media
static const char * reason_code_to_str(const struct ast_party_redirecting_reason *reason)
static int unload_module(void)
static int sip_is_token(const char *str)
static enum AST_REDIRECTING_REASON cause_to_reason(const unsigned long cause)
static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
static void copy_redirecting_id(struct ast_party_id *dst, const struct ast_party_id *src, struct ast_set_party_id *update)
@ AST_SIP_SESSION_BEFORE_REDIRECTING
@ AST_SIP_SESSION_BEFORE_MEDIA
#define ast_sip_session_register_supplement(supplement)
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
Definition: pjsip_session.c:63
#define NULL
Definition: resample.c:96
String manipulation functions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition: utils.c:1854
struct ast_module * self
Definition: module.h:356
Information needed to identify an endpoint in a call.
Definition: channel.h:340
struct ast_party_name name
Subscriber name.
Definition: channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:281
char * str
Subscriber name (Malloced)
Definition: channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:299
char * str
Subscriber phone number (Malloced)
Definition: channel.h:293
Redirecting reason information.
Definition: channel.h:503
int code
enum AST_REDIRECTING_REASON value for redirection
Definition: channel.h:512
char * str
a string value for the redirecting reason
Definition: channel.h:509
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:524
struct ast_party_redirecting_reason reason
Reason for the redirection.
Definition: channel.h:544
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:529
int count
Number of times the call was redirected.
Definition: channel.h:550
struct ast_party_id to
Call is redirecting to a new party (Sent to the caller)
Definition: channel.h:532
Indicate what information in ast_party_id should be set.
Definition: channel.h:363
Indicate what information in ast_party_redirecting should be set.
Definition: channel.h:557
A supplement to SIP message processing.
A structure describing a SIP session.
Diversion header reasons.
const char * text
enum AST_REDIRECTING_REASON code
const unsigned int cause
int value
Definition: syslog.c:37
#define ARRAY_LEN(a)
Definition: utils.h:703