Asterisk - The Open Source Telephony Project  21.4.1
res_pjsip_diversion.c
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"
32 #include "asterisk/res_pjsip_session.h"
33 #include "asterisk/callerid.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/module.h"
36 #include "asterisk/strings.h"
37 
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 };
41 
42 /*!
43  * \internal
44  * \brief Determine if the given string is a SIP token.
45  * \since 13.8.0
46  *
47  * \param str String to determine if is a SIP token.
48  *
49  * \note A token is defined by RFC3261 Section 25.1
50  *
51  * \return Non-zero if the string is a SIP token.
52  */
53 static int sip_is_token(const char *str)
54 {
55  int is_token;
56 
57  if (ast_strlen_zero(str)) {
58  /* An empty string is not a token. */
59  return 0;
60  }
61 
62  is_token = 1;
63  do {
64  if (!isalnum(*str)
65  && !strchr("-.!%*_+`'~", *str)) {
66  /* The character is not allowed in a token. */
67  is_token = 0;
68  break;
69  }
70  } while (*++str);
71 
72  return is_token;
73 }
74 
75 /*! \brief Diversion header reasons
76  *
77  * The core defines a bunch of constants used to define
78  * redirecting reasons. This provides a translation table
79  * between those and the strings which may be present in
80  * a SIP Diversion header
81  */
82 static const struct reasons {
83  enum AST_REDIRECTING_REASON code;
84  const char *text;
85  const unsigned int cause;
86 } reason_table[] = {
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 }, /* Non-standard */
99  { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm", 404 }, /* Non-standard */
100 };
101 
102 static enum AST_REDIRECTING_REASON cause_to_reason(const unsigned long cause) {
103  switch(cause) {
104  case 302:
105  return AST_REDIRECTING_REASON_UNCONDITIONAL;
106  case 486:
107  return AST_REDIRECTING_REASON_USER_BUSY;
108  case 408:
109  return AST_REDIRECTING_REASON_NO_ANSWER;
110  case 480:
111  case 487:
112  return AST_REDIRECTING_REASON_DEFLECTION;
113  case 503:
114  return AST_REDIRECTING_REASON_UNAVAILABLE;
115  default:
116  return AST_REDIRECTING_REASON_UNKNOWN;
117  }
118 }
119 
120 static int add_supported(pjsip_tx_data *tdata)
121 {
122  pjsip_supported_hdr *hdr;
123  unsigned int i;
124 
125  hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
126  if (!hdr) {
127  /* insert a new Supported header */
128  hdr = pjsip_supported_hdr_create(tdata->pool);
129  if (!hdr) {
130  return -1;
131  }
132 
133  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
134  }
135 
136  /* Asterisk can send multiple "181 Call forwarded" in a single session,
137  * we might have already modified Supported before
138  */
139  for (i = 0; i < hdr->count; ++i) {
140  if (pj_stricmp(&hdr->values[i], &HISTINFO_SUPPORTED_NAME) == 0) {
141  return 0;
142  }
143  }
144 
145  if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
146  return -1;
147  }
148 
149  /* add on to the existing Supported header */
150  pj_strassign(&hdr->values[hdr->count++], &HISTINFO_SUPPORTED_NAME);
151 
152  return 0;
153 }
154 
155 static const char *reason_code_to_str(const struct ast_party_redirecting_reason *reason)
156 {
157  int idx;
158  int code;
159 
160  /* use specific string if given */
161  if (!ast_strlen_zero(reason->str)) {
162  return reason->str;
163  }
164 
165  code = reason->code;
166  for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
167  if (code == reason_table[idx].code) {
168  return reason_table[idx].text;
169  }
170  }
171 
172  return "unknown";
173 }
174 
175 static const unsigned int reason_code_to_cause(const struct ast_party_redirecting_reason *reason)
176 {
177  int idx;
178  int code;
179 
180  code = reason->code;
181  for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
182  if (code == reason_table[idx].code) {
183  return reason_table[idx].cause;
184  }
185  }
186 
187  return 404;
188 }
189 
190 static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
191 {
192  static const pj_str_t from_name = { "From", 4 };
193 
194  pjsip_generic_string_hdr *hdr;
195  pj_str_t value;
196  int size;
197 
198  if (!(hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &diversion_name, NULL))) {
199  return NULL;
200  }
201 
202  pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
203 
204  /* parse as a fromto header */
205  return pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
206  pj_strlen(&value), &size);
207 }
208 
209 /* Asterisk keeps track of 2 things. The redirected from address and
210  * the redirected to address. If first=0 method will get the most recent
211  * redirection target for use as the redirected to address. If first=1
212  * then this method will get the original redirection target (index=1)
213  * for use as the redirected from address.
214  */
215 static pjsip_fromto_hdr *get_history_info_header(pjsip_rx_data *rdata, const unsigned int first)
216 {
217  static const pj_str_t from_name = { "From", 4 };
218  pjsip_fromto_hdr * result_hdr = NULL;
219 
220  pjsip_generic_string_hdr *hdr = NULL;
221 
222  hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &history_info_name, NULL);
223 
224  if (!hdr) {
225  return NULL;
226  }
227 
228  do {
229  static const pj_str_t index_name = { "index", 5 };
230  pj_str_t value;
231  int size;
232  pjsip_fromto_hdr * fromto_hdr = NULL;
233  pjsip_param * index = NULL;
234 
235  pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
236 
237  /* parse as a fromto header */
238  fromto_hdr = pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
239  pj_strlen(&value), &size);
240 
241  if (fromto_hdr == NULL) {
242  continue;
243  }
244 
245  index = pjsip_param_find(&fromto_hdr->other_param, &index_name);
246 
247  if (index) {
248  if (!pj_strcmp2(&index->value, "1")) {
249  if (!first) {
250  continue;
251  } else {
252  return fromto_hdr;
253  }
254  }
255  }
256 
257  result_hdr = fromto_hdr;
258 
259  } while ((hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &history_info_name, hdr->next)));
260 
261  return result_hdr;
262 }
263 
264 static void set_redirecting_value(char **dst, const pj_str_t *src)
265 {
266  ast_free(*dst);
267  *dst = ast_malloc(pj_strlen(src) + 1);
268  if (*dst) {
269  ast_copy_pj_str(*dst, src, pj_strlen(src) + 1);
270  }
271 }
272 
273 static void set_redirecting_id(pjsip_name_addr *name_addr, struct ast_party_id *data,
274  struct ast_set_party_id *update)
275 {
276  pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr->uri);
277  char *semi;
278  pj_str_t uri_user;
279 
280  uri_user = uri->user;
281 
282  /* Always truncate redirecting number at a semicolon. */
283  semi = pj_strchr(&uri_user, ';');
284  if (semi) {
285  /*
286  * We need to be able to handle URI's looking like
287  * "sip:1235557890;phone-context=national@x.x.x.x;user=phone"
288  *
289  * Where the uri->user field will result in:
290  * "1235557890;phone-context=national"
291  *
292  * People don't care about anything after the semicolon
293  * showing up on their displays even though the RFC
294  * allows the semicolon.
295  */
296  pj_strset(&uri_user, (char *) pj_strbuf(&uri_user), semi - pj_strbuf(&uri_user));
297  }
298 
299  if (pj_strlen(&uri_user)) {
300  update->number = 1;
301  data->number.valid = 1;
302  set_redirecting_value(&data->number.str, &uri_user);
303  }
304 
305  if (pj_strlen(&name_addr->display)) {
306  update->name = 1;
307  data->name.valid = 1;
308  set_redirecting_value(&data->name.str, &name_addr->display);
309  }
310 }
311 
312 static void copy_redirecting_id(struct ast_party_id *dst, const struct ast_party_id *src,
313  struct ast_set_party_id *update)
314 {
315  ast_party_id_copy(dst, src);
316 
317  if (dst->number.valid) {
318  update->number = 1;
319  }
320 
321  if (dst->name.valid) {
322  update->name = 1;
323  }
324 }
325 
326 static void set_redirecting_reason_by_cause(pjsip_name_addr *name_addr,
327  struct ast_party_redirecting_reason *data)
328 {
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;
333 
334  if (!ast_sip_is_allowed_uri(uri)) {
335  return;
336  }
337 
338  cause = ast_sip_pjsip_uri_get_other_param(uri, &cause_name);
339 
340  if (!cause) {
341  return;
342  }
343 
344  cause_value = pj_strtoul(&cause->value);
345 
346  data->code = cause_to_reason(cause_value);
347  ast_free(data->str);
348  data->str = ast_strdup("");
349 }
350 
351 static void set_redirecting_reason(pjsip_fromto_hdr *from_info, pjsip_name_addr *to_info,
352  struct ast_party_redirecting_reason *data)
353 {
354  static const pj_str_t reason_name = { "reason", 6 };
355  pjsip_param *reason = pjsip_param_find(&from_info->other_param, &reason_name);
356  char *reason_str;
357 
358  if (!reason) {
359  if (to_info) {
360  set_redirecting_reason_by_cause(to_info, data);
361  }
362  return;
363  }
364 
365  set_redirecting_value(&data->str, &reason->value);
366  if (!data->str) {
367  /* Oops, allocation failure */
368  return;
369  }
370  reason_str = ast_strdupa(data->str);
371 
372  /* Remove any enclosing double-quotes */
373  if (*reason_str == '"') {
374  reason_str = ast_strip_quoted(reason_str, "\"", "\"");
375  }
376 
377  data->code = ast_redirecting_reason_parse(reason_str);
378  if (data->code < 0) {
379  data->code = AST_REDIRECTING_REASON_UNKNOWN;
380  } else {
381  ast_free(data->str);
382  data->str = ast_strdup("");
383  }
384 }
385 
386 static void set_redirecting(struct ast_sip_session *session,
387  pjsip_fromto_hdr *from_info,
388  pjsip_name_addr *to_info)
389 {
390  struct ast_party_redirecting data;
391  struct ast_set_party_redirecting update;
392 
393  if (!session->channel) {
394  return;
395  }
396 
398  memset(&update, 0, sizeof(update));
399 
400  data.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
401  if (from_info) {
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);
405  ast_set_party_id_all(&update.priv_to);
406  } else {
407  copy_redirecting_id(&data.from, &session->id, &update.from);
408  }
409 
410  if (to_info) {
411  set_redirecting_id(to_info, &data.to, &update.to);
412  }
413 
414  ast_set_party_id_all(&update.priv_orig);
415  ast_set_party_id_all(&update.priv_from);
416  ast_set_party_id_all(&update.priv_to);
417  ++data.count;
418 
419  ast_channel_set_redirecting(session->channel, &data, &update);
420  /* Only queue an indication if it was due to a response */
421  if (session->inv_session->role == PJSIP_ROLE_UAC) {
422  ast_channel_queue_redirecting_update(session->channel, &data, &update);
423  }
425 }
426 
427 static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
428 {
429  pjsip_fromto_hdr *hdr = get_diversion_header(rdata);
430 
431  if (hdr) {
432  set_redirecting(session, hdr, (pjsip_name_addr*)
433  PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri);
434  } else {
435  pjsip_fromto_hdr *history_info_to;
436  pjsip_fromto_hdr *history_info_from;
437  history_info_to = get_history_info_header(rdata, 0);
438 
439  if (history_info_to) {
440  /* If History-Info is present, then it will also include the original
441  redirected-from in addition to the redirected-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);
444  }
445  }
446 
447  return 0;
448 }
449 
450 static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
451 {
452  static const pj_str_t contact_name = { "Contact", 7 };
453  static const pj_str_t contact_name_s = { "m", 1 };
454 
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;
460 
461  if ((status.code != 302) && (status.code != 181)) {
462  return;
463  }
464 
465  /* use the diversion header info if there is one. if not one then use the
466  the history-info, if that doesn't exist, use session caller id info. if
467  that doesn't exist use info from the To hdr*/
468  if (!(div_hdr = get_diversion_header(rdata))) {
469  history_info_to = get_history_info_header(rdata, 0);
470 
471  if (history_info_to) {
472  /* If History-Info is present, then it will also include the original
473  redirected-from in addition to the redirected-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);
476  return;
477  }
478  if (!div_hdr && !session->id.number.valid) {
479  div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
480  }
481  }
482 
483 
484  if (status.code == 302) {
485  /* With 302, Contact indicates the final destination and possibly Diversion indicates the hop before */
486  contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL);
487 
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);
490  } else {
491  /* With 181, Diversion is non-standard, but if present indicates the new final destination, and To indicating the original */
492  set_redirecting(session, PJSIP_MSG_TO_HDR(rdata->msg_info.msg),
493  div_hdr ? (pjsip_name_addr*)div_hdr->uri : NULL);
494  }
495 }
496 
497 /*!
498  * \internal
499  * \brief Adds diversion header information to an outbound SIP message
500  *
501  * \param tdata The outbound message
502  * \param data The redirecting data used to fill parts of the diversion header
503  */
504 static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
505 {
506  static const pj_str_t reason_name = { "reason", 6 };
507 
508  pjsip_fromto_hdr *hdr;
509  pjsip_name_addr *name_addr;
510  pjsip_param *param;
511  pjsip_fromto_hdr *old_hdr;
512  const char *reason_str;
513  const char *quote_str;
514  char *reason_buf;
515  pjsip_uri *base;
516 
517  struct ast_party_id *id = NULL;
518  if (tdata->msg->type == PJSIP_REQUEST_MSG) {
519  id = &data->from;
520  } else {
521  /* In responses indicate the new destination */
522  id = &data->to;
523  }
524 
525  base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
526 
527  if (!id->number.valid || ast_strlen_zero(id->number.str)) {
528  return;
529  }
530 
531  hdr = pjsip_from_hdr_create(tdata->pool);
532  hdr->type = PJSIP_H_OTHER;
533  hdr->sname = hdr->name = diversion_name;
534 
535  name_addr = pjsip_uri_clone(tdata->pool, base);
536 
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);
539 
540  param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
541  param->name = reason_name;
542 
543  reason_str = reason_code_to_str(&data->reason);
544 
545  /* Reason is either already quoted or it is a token to not need quotes added. */
546  quote_str = *reason_str == '\"' || sip_is_token(reason_str) ? "" : "\"";
547 
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);/* Safe */
550 
551  param->value = pj_str(reason_buf);
552 
553  pj_list_insert_before(&hdr->other_param, param);
554 
555  hdr->uri = (pjsip_uri *) name_addr;
556  old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &diversion_name, NULL);
557  if (old_hdr) {
558  pj_list_erase(old_hdr);
559  }
560  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
561 }
562 
563 /*!
564  * \internal
565  * \brief Adds history-info header information to an outbound SIP message
566  *
567  * \param tdata The outbound message
568  * \param data The redirecting data used to fill parts of the history-info header
569  */
570 static void add_history_info_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
571 {
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 };
576 
577  pjsip_fromto_hdr *hdr;
578  pjsip_name_addr *name_addr;
579  pjsip_sip_uri *uri;
580  pjsip_param *param;
581  pjsip_fromto_hdr *old_hdr;
582  unsigned int cause;
583  char *cause_buf;
584 
585  struct ast_party_id *to = &data->to;
586  struct ast_party_id *from = &data->from;
587 
588  pjsip_uri *base = PJSIP_MSG_TO_HDR(tdata->msg)->uri;
589 
590 
591  hdr = pjsip_from_hdr_create(tdata->pool);
592  hdr->type = PJSIP_H_OTHER;
593  hdr->sname = hdr->name = history_info_name;
594 
595  name_addr = pjsip_uri_clone(tdata->pool, base);
596  uri = pjsip_uri_get_uri(name_addr->uri);
597 
598  /* if no redirecting information, then TO is the original destination */
599  if (from->number.valid && !ast_strlen_zero(from->number.str)) {
600  pj_strdup2(tdata->pool, &name_addr->display, from->name.str);
601  pj_strdup2(tdata->pool, &uri->user, from->number.str);
602  }
603 
604  param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
605  param->name = index_name;
606  param->value = first_index;
607 
608 
609  pj_list_insert_before(&hdr->other_param, param);
610  hdr->uri = (pjsip_uri *) name_addr;
611 
612  while ((old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &history_info_name, NULL)) != NULL) {
613  pj_list_erase(old_hdr);
614  }
615 
616  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
617 
618  if (!to->number.valid || ast_strlen_zero(to->number.str)) {
619  return;
620  }
621 
622  hdr = pjsip_from_hdr_create(tdata->pool);
623  hdr->type = PJSIP_H_OTHER;
624  hdr->sname = hdr->name = history_info_name;
625 
626  name_addr = pjsip_uri_clone(tdata->pool, base);
627  uri = pjsip_uri_get_uri(name_addr->uri);
628 
629  pj_strdup2(tdata->pool, &name_addr->display, to->name.str);
630  pj_strdup2(tdata->pool, &uri->user, to->number.str);
631 
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);
636 
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;
645 
646  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
647 }
648 
649 static void get_redirecting_add_diversion(struct ast_sip_session *session, pjsip_tx_data *tdata)
650 {
651  struct ast_party_redirecting *data;
652 
653  add_supported(tdata);
654 
655  if (session->channel && session->endpoint->id.send_diversion &&
656  (data = ast_channel_redirecting(session->channel))->count) {
657  add_diversion_header(tdata, data);
658  }
659  if (session->channel && session->endpoint->id.send_history_info) {
660  data = ast_channel_redirecting(session->channel);
661  add_history_info_header(tdata, data);
662  }
663 }
664 
665 /*!
666  * \internal
667  * \brief Adds a diversion header to an outgoing INVITE request if
668  * redirecting information is available.
669  *
670  * \param session The session on which the INVITE request is to be sent
671  * \param tdata The outbound INVITE request
672  */
673 static void diversion_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
674 {
675  get_redirecting_add_diversion(session, tdata);
676 }
677 
678 /*!
679  * \internal
680  * \brief Adds a diversion header to an outgoing 3XX response
681  *
682  * \param session The session on which the INVITE response is to be sent
683  * \param tdata The outbound INVITE response
684  */
685 static void diversion_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
686 {
687  struct pjsip_status_line status = tdata->msg->line.status;
688 
689  /* add to 302 and 181 */
690  if (PJSIP_IS_STATUS_IN_CLASS(status.code, 300) || (status.code == 181)) {
691  get_redirecting_add_diversion(session, tdata);
692  }
693 }
694 
695 static struct ast_sip_session_supplement diversion_supplement = {
696  .method = "INVITE",
697  /* this supplement needs to be called after caller id
698  and after the channel has been created */
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,
705 };
706 
707 static int load_module(void)
708 {
709  /* Because we are passing static memory to pjsip, we need to make sure it
710  * stays valid while we potentially have active sessions */
712  ast_sip_session_register_supplement(&diversion_supplement);
714 }
715 
716 static int unload_module(void)
717 {
718  ast_sip_session_unregister_supplement(&diversion_supplement);
719  return 0;
720 }
721 
722 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Add Diversion Header Support",
723  .support_level = AST_MODULE_SUPPORT_CORE,
724  .load = load_module,
725  .unload = unload_module,
726  .load_pri = AST_MODPRI_APP_DEPEND,
727  .requires = "res_pjsip,res_pjsip_session",
728 );
Information needed to identify an endpoint in a call.
Definition: channel.h:338
struct ast_sip_endpoint * endpoint
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
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.
Definition: channel.h:340
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:527
int ast_redirecting_reason_parse(const char *data)
Convert redirecting reason text code to value (used in config file parsing)
Definition: callerid.c:1423
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:1765
char * str
Subscriber name (Malloced)
Definition: channel.h:264
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
struct pjsip_inv_session * inv_session
int code
enum AST_REDIRECTING_REASON value for redirection
Definition: channel.h:510
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.
Definition: utils.c:1818
Diversion header reasons.
struct ast_module * self
Definition: module.h:356
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
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.
Definition: channel.c:9119
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
AST_REDIRECTING_REASON
redirecting reason codes.
Definition: callerid.h:498
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:986
Redirecting reason information.
Definition: channel.h:501
Indicate what information in ast_party_id should be set.
Definition: channel.h:361
unsigned char number
Definition: channel.h:365
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:478
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:522
char * str
a string value for the redirecting reason
Definition: channel.h:507
struct ast_party_redirecting_reason reason
Reason for the redirection.
Definition: channel.h:542
A supplement to SIP message processing.
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2179
unsigned char name
Definition: channel.h:363
Indicate what information in ast_party_redirecting should be set.
Definition: channel.h:555
struct ast_party_id to
Call is redirecting to a new party (Sent to the caller)
Definition: channel.h:530
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2122
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:10297
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
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:1750
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
struct ast_party_id id
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342