res_pjsip_diversion.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. /*** MODULEINFO
  19. <depend>pjproject</depend>
  20. <depend>res_pjsip</depend>
  21. <depend>res_pjsip_session</depend>
  22. <support_level>core</support_level>
  23. ***/
  24. #include "asterisk.h"
  25. #include <pjsip.h>
  26. #include <pjsip_ua.h>
  27. #include "asterisk/res_pjsip.h"
  28. #include "asterisk/res_pjsip_session.h"
  29. #include "asterisk/callerid.h"
  30. #include "asterisk/channel.h"
  31. #include "asterisk/module.h"
  32. #include "asterisk/strings.h"
  33. static const pj_str_t diversion_name = { "Diversion", 9 };
  34. /*!
  35. * \internal
  36. * \brief Determine if the given string is a SIP token.
  37. * \since 13.8.0
  38. *
  39. * \param str String to determine if is a SIP token.
  40. *
  41. * \note A token is defined by RFC3261 Section 25.1
  42. *
  43. * \return Non-zero if the string is a SIP token.
  44. */
  45. static int sip_is_token(const char *str)
  46. {
  47. int is_token;
  48. if (ast_strlen_zero(str)) {
  49. /* An empty string is not a token. */
  50. return 0;
  51. }
  52. is_token = 1;
  53. do {
  54. if (!isalnum(*str)
  55. && !strchr("-.!%*_+`'~", *str)) {
  56. /* The character is not allowed in a token. */
  57. is_token = 0;
  58. break;
  59. }
  60. } while (*++str);
  61. return is_token;
  62. }
  63. /*! \brief Diversion header reasons
  64. *
  65. * The core defines a bunch of constants used to define
  66. * redirecting reasons. This provides a translation table
  67. * between those and the strings which may be present in
  68. * a SIP Diversion header
  69. */
  70. static const struct reasons {
  71. enum AST_REDIRECTING_REASON code;
  72. const char *text;
  73. } reason_table[] = {
  74. { AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
  75. { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
  76. { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" },
  77. { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable" },
  78. { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" },
  79. { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" },
  80. { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" },
  81. { AST_REDIRECTING_REASON_DEFLECTION, "deflection" },
  82. { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
  83. { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
  84. { AST_REDIRECTING_REASON_AWAY, "away" },
  85. { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte" }, /* Non-standard */
  86. { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm" }, /* Non-standard */
  87. };
  88. static const char *reason_code_to_str(const struct ast_party_redirecting_reason *reason)
  89. {
  90. int idx;
  91. int code;
  92. /* use specific string if given */
  93. if (!ast_strlen_zero(reason->str)) {
  94. return reason->str;
  95. }
  96. code = reason->code;
  97. for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
  98. if (code == reason_table[idx].code) {
  99. return reason_table[idx].text;
  100. }
  101. }
  102. return "unknown";
  103. }
  104. static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
  105. {
  106. static const pj_str_t from_name = { "From", 4 };
  107. pjsip_generic_string_hdr *hdr;
  108. pj_str_t value;
  109. int size;
  110. if (!(hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &diversion_name, NULL))) {
  111. return NULL;
  112. }
  113. pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
  114. /* parse as a fromto header */
  115. return pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
  116. pj_strlen(&value), &size);
  117. }
  118. static void set_redirecting_value(char **dst, const pj_str_t *src)
  119. {
  120. ast_free(*dst);
  121. *dst = ast_malloc(pj_strlen(src) + 1);
  122. if (*dst) {
  123. ast_copy_pj_str(*dst, src, pj_strlen(src) + 1);
  124. }
  125. }
  126. static void set_redirecting_id(pjsip_name_addr *name_addr, struct ast_party_id *data,
  127. struct ast_set_party_id *update)
  128. {
  129. pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr->uri);
  130. char *semi;
  131. pj_str_t uri_user;
  132. uri_user = uri->user;
  133. /* Always truncate redirecting number at a semicolon. */
  134. semi = pj_strchr(&uri_user, ';');
  135. if (semi) {
  136. /*
  137. * We need to be able to handle URI's looking like
  138. * "sip:1235557890;phone-context=national@x.x.x.x;user=phone"
  139. *
  140. * Where the uri->user field will result in:
  141. * "1235557890;phone-context=national"
  142. *
  143. * People don't care about anything after the semicolon
  144. * showing up on their displays even though the RFC
  145. * allows the semicolon.
  146. */
  147. pj_strset(&uri_user, (char *) pj_strbuf(&uri_user), semi - pj_strbuf(&uri_user));
  148. }
  149. if (pj_strlen(&uri_user)) {
  150. update->number = 1;
  151. data->number.valid = 1;
  152. set_redirecting_value(&data->number.str, &uri_user);
  153. }
  154. if (pj_strlen(&name_addr->display)) {
  155. update->name = 1;
  156. data->name.valid = 1;
  157. set_redirecting_value(&data->name.str, &name_addr->display);
  158. }
  159. }
  160. static void copy_redirecting_id(struct ast_party_id *dst, const struct ast_party_id *src,
  161. struct ast_set_party_id *update)
  162. {
  163. ast_party_id_copy(dst, src);
  164. if (dst->number.valid) {
  165. update->number = 1;
  166. }
  167. if (dst->name.valid) {
  168. update->name = 1;
  169. }
  170. }
  171. static void set_redirecting_reason(pjsip_fromto_hdr *hdr,
  172. struct ast_party_redirecting_reason *data)
  173. {
  174. static const pj_str_t reason_name = { "reason", 6 };
  175. pjsip_param *reason = pjsip_param_find(&hdr->other_param, &reason_name);
  176. char *reason_str;
  177. if (!reason) {
  178. return;
  179. }
  180. set_redirecting_value(&data->str, &reason->value);
  181. if (!data->str) {
  182. /* Oops, allocation failure */
  183. return;
  184. }
  185. reason_str = ast_strdupa(data->str);
  186. /* Remove any enclosing double-quotes */
  187. if (*reason_str == '"') {
  188. reason_str = ast_strip_quoted(reason_str, "\"", "\"");
  189. }
  190. data->code = ast_redirecting_reason_parse(reason_str);
  191. if (data->code < 0) {
  192. data->code = AST_REDIRECTING_REASON_UNKNOWN;
  193. } else {
  194. ast_free(data->str);
  195. data->str = ast_strdup("");
  196. }
  197. }
  198. static void set_redirecting(struct ast_sip_session *session,
  199. pjsip_fromto_hdr *from_info,
  200. pjsip_name_addr *to_info)
  201. {
  202. struct ast_party_redirecting data;
  203. struct ast_set_party_redirecting update;
  204. if (!session->channel) {
  205. return;
  206. }
  207. ast_party_redirecting_init(&data);
  208. memset(&update, 0, sizeof(update));
  209. if (from_info) {
  210. set_redirecting_id((pjsip_name_addr*)from_info->uri,
  211. &data.from, &update.from);
  212. set_redirecting_reason(from_info, &data.reason);
  213. } else {
  214. copy_redirecting_id(&data.from, &session->id, &update.from);
  215. }
  216. set_redirecting_id(to_info, &data.to, &update.to);
  217. ast_set_party_id_all(&update.priv_orig);
  218. ast_set_party_id_all(&update.priv_from);
  219. ast_set_party_id_all(&update.priv_to);
  220. ++data.count;
  221. ast_channel_set_redirecting(session->channel, &data, &update);
  222. ast_party_redirecting_free(&data);
  223. }
  224. static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
  225. {
  226. pjsip_fromto_hdr *hdr = get_diversion_header(rdata);
  227. if (hdr) {
  228. set_redirecting(session, hdr, (pjsip_name_addr*)
  229. PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri);
  230. }
  231. return 0;
  232. }
  233. static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
  234. {
  235. static const pj_str_t contact_name = { "Contact", 7 };
  236. static const pj_str_t contact_name_s = { "m", 1 };
  237. pjsip_status_line status = rdata->msg_info.msg->line.status;
  238. pjsip_fromto_hdr *div_hdr;
  239. pjsip_contact_hdr *contact_hdr;
  240. if ((status.code != 302) && (status.code != 181)) {
  241. return;
  242. }
  243. /* use the diversion header info if there is one. if not one then use the
  244. session caller id info. if that doesn't exist use info from the To hdr*/
  245. if (!(div_hdr = get_diversion_header(rdata)) && !session->id.number.valid) {
  246. div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
  247. }
  248. contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL);
  249. set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri :
  250. (pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri);
  251. }
  252. /*!
  253. * \internal
  254. * \brief Adds diversion header information to an outbound SIP message
  255. *
  256. * \param tdata The outbound message
  257. * \param data The redirecting data used to fill parts of the diversion header
  258. */
  259. static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
  260. {
  261. pjsip_fromto_hdr *hdr;
  262. pjsip_name_addr *name_addr;
  263. pjsip_sip_uri *uri;
  264. pjsip_param *param;
  265. pjsip_fromto_hdr *old_hdr;
  266. const char *reason_str;
  267. const char *quote_str;
  268. char *reason_buf;
  269. struct ast_party_id *id = &data->from;
  270. pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
  271. if (!id->number.valid || ast_strlen_zero(id->number.str)) {
  272. return;
  273. }
  274. hdr = pjsip_from_hdr_create(tdata->pool);
  275. hdr->type = PJSIP_H_OTHER;
  276. pj_strdup(tdata->pool, &hdr->name, &diversion_name);
  277. hdr->sname = hdr->name;
  278. name_addr = pjsip_uri_clone(tdata->pool, base);
  279. uri = pjsip_uri_get_uri(name_addr->uri);
  280. pj_strdup2(tdata->pool, &name_addr->display, id->name.str);
  281. pj_strdup2(tdata->pool, &uri->user, id->number.str);
  282. param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
  283. param->name = pj_str("reason");
  284. reason_str = reason_code_to_str(&data->reason);
  285. /* Reason is either already quoted or it is a token to not need quotes added. */
  286. quote_str = *reason_str == '\"' || sip_is_token(reason_str) ? "" : "\"";
  287. reason_buf = pj_pool_alloc(tdata->pool, strlen(reason_str) + 3);
  288. sprintf(reason_buf, "%s%s%s", quote_str, reason_str, quote_str);/* Safe */
  289. param->value = pj_str(reason_buf);
  290. pj_list_insert_before(&hdr->other_param, param);
  291. hdr->uri = (pjsip_uri *) name_addr;
  292. old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &diversion_name, NULL);
  293. if (old_hdr) {
  294. pj_list_erase(old_hdr);
  295. }
  296. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
  297. }
  298. static void get_redirecting_add_diversion(struct ast_sip_session *session, pjsip_tx_data *tdata)
  299. {
  300. struct ast_party_redirecting *data;
  301. if (session->channel && session->endpoint->id.send_diversion &&
  302. (data = ast_channel_redirecting(session->channel))->count) {
  303. add_diversion_header(tdata, data);
  304. }
  305. }
  306. /*!
  307. * \internal
  308. * \brief Adds a diversion header to an outgoing INVITE request if
  309. * redirecting information is available.
  310. *
  311. * \param session The session on which the INVITE request is to be sent
  312. * \param tdata The outbound INVITE request
  313. */
  314. static void diversion_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
  315. {
  316. get_redirecting_add_diversion(session, tdata);
  317. }
  318. /*!
  319. * \internal
  320. * \brief Adds a diversion header to an outgoing 3XX response
  321. *
  322. * \param session The session on which the INVITE response is to be sent
  323. * \param tdata The outbound INVITE response
  324. */
  325. static void diversion_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
  326. {
  327. struct pjsip_status_line status = tdata->msg->line.status;
  328. /* add to 302 and 181 */
  329. if (PJSIP_IS_STATUS_IN_CLASS(status.code, 300) || (status.code == 181)) {
  330. get_redirecting_add_diversion(session, tdata);
  331. }
  332. }
  333. static struct ast_sip_session_supplement diversion_supplement = {
  334. .method = "INVITE",
  335. /* this supplement needs to be called after caller id
  336. and after the channel has been created */
  337. .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 100,
  338. .incoming_request = diversion_incoming_request,
  339. .incoming_response = diversion_incoming_response,
  340. .outgoing_request = diversion_outgoing_request,
  341. .outgoing_response = diversion_outgoing_response,
  342. .response_priority = AST_SIP_SESSION_BEFORE_REDIRECTING,
  343. };
  344. static int load_module(void)
  345. {
  346. CHECK_PJSIP_SESSION_MODULE_LOADED();
  347. ast_sip_session_register_supplement(&diversion_supplement);
  348. return AST_MODULE_LOAD_SUCCESS;
  349. }
  350. static int unload_module(void)
  351. {
  352. ast_sip_session_unregister_supplement(&diversion_supplement);
  353. return 0;
  354. }
  355. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Add Diversion Header Support",
  356. .support_level = AST_MODULE_SUPPORT_CORE,
  357. .load = load_module,
  358. .unload = unload_module,
  359. .load_pri = AST_MODPRI_APP_DEPEND,
  360. );