sip_refer.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /*
  2. * This file is part of the Sofia-SIP package
  3. *
  4. * Copyright (C) 2005 Nokia Corporation.
  5. *
  6. * Contact: Pekka Pessi <pekka.pessi@nokia.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  21. * 02110-1301 USA
  22. *
  23. */
  24. /**@CFILE sip_refer.c
  25. * @brief SIP REFER-related headers.
  26. *
  27. * The file @b sip_refer.c contains implementation of header classes for
  28. * REFER-related SIP headers @ReferTo and @ReferredBy.
  29. *
  30. * @author Pekka Pessi <Pekka.Pessi@nokia.com>
  31. *
  32. * @date Created: Wed Jan 23 13:23:45 EET 2002 ppessi
  33. */
  34. #include "config.h"
  35. /* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
  36. #define MSG_PUB_T struct sip_s
  37. #define MSG_HDR_T union sip_header_u
  38. #include "sofia-sip/sip_parser.h"
  39. #include "sofia-sip/sip_extra.h"
  40. #include <stdio.h>
  41. #include <stddef.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <limits.h>
  45. #include <assert.h>
  46. /* ====================================================================== */
  47. /**@SIP_HEADER sip_refer_to Refer-To Header
  48. *
  49. * The Refer-To header provides a URI to reference. Its syntax is defined in
  50. * @RFC3515 section 2.1 as follows:
  51. *
  52. * @code
  53. * Refer-To = ("Refer-To" / "r") HCOLON ( name-addr / addr-spec )
  54. * *(SEMI generic-param)
  55. * @endcode
  56. *
  57. *
  58. * The parsed Refer-To header is stored in #sip_refer_to_t structure.
  59. */
  60. /**@ingroup sip_refer_to
  61. *
  62. * @typedef typedef struct sip_refer_to_s sip_refer_to_t;
  63. *
  64. * The structure #sip_refer_to_t contains representation of @ReferTo
  65. * header.
  66. *
  67. * The #sip_refer_to_t is defined as follows:
  68. * @code
  69. * typedef struct sip_refer_to_s
  70. * {
  71. * sip_common_t r_common[1]; // Common fragment info
  72. * sip_error_t *r_next; // Link to next (dummy)
  73. * char const r_display; // Display name
  74. * url_t r_url[1]; // URI to reference
  75. * msg_param_t const *r_params; // List of generic parameters
  76. * } sip_refer_to_t;
  77. * @endcode
  78. */
  79. static msg_xtra_f sip_refer_to_dup_xtra;
  80. static msg_dup_f sip_refer_to_dup_one;
  81. #define sip_refer_to_update NULL
  82. msg_hclass_t sip_refer_to_class[] =
  83. SIP_HEADER_CLASS(refer_to, "Refer-To", "r", r_params, single, refer_to);
  84. issize_t sip_refer_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
  85. {
  86. issize_t retval;
  87. sip_refer_to_t *r = (sip_refer_to_t *)h;
  88. retval = sip_name_addr_d(home, &s,
  89. &r->r_display,
  90. r->r_url,
  91. &r->r_params,
  92. NULL);
  93. if (retval < 0)
  94. return retval;
  95. if (*s == '?' && !r->r_display && !r->r_url->url_headers) {
  96. /* Missing <> around URL */
  97. *s++ = '\0';
  98. r->r_url->url_headers = s;
  99. s += strcspn(s, " \t;,");
  100. if (IS_LWS(*s))
  101. *s++ = '\0', skip_lws(&s);
  102. if (*s)
  103. return -1;
  104. r->r_display = s; /* Put empty string in display so that we encode using <> */
  105. }
  106. else if (*s)
  107. return -1;
  108. return retval;
  109. }
  110. issize_t sip_refer_to_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
  111. {
  112. sip_refer_to_t const *r = h->sh_refer_to;
  113. assert(sip_is_refer_to(h));
  114. return sip_name_addr_e(b, bsiz, flags,
  115. r->r_display, MSG_IS_CANONIC(flags),
  116. r->r_url,
  117. r->r_params,
  118. NULL);
  119. }
  120. isize_t sip_refer_to_dup_xtra(sip_header_t const *h, isize_t offset)
  121. {
  122. sip_refer_to_t const *r = h->sh_refer_to;
  123. MSG_PARAMS_SIZE(offset, r->r_params);
  124. offset += MSG_STRING_SIZE(r->r_display);
  125. offset += url_xtra(r->r_url);
  126. return offset;
  127. }
  128. /** Duplicate one #sip_refer_to_t object */
  129. char *sip_refer_to_dup_one(sip_header_t *dst, sip_header_t const *src,
  130. char *b, isize_t xtra)
  131. {
  132. sip_refer_to_t *r_dst = dst->sh_refer_to;
  133. sip_refer_to_t const *r_src = src->sh_refer_to;
  134. char *end = b + xtra;
  135. b = msg_params_dup(&r_dst->r_params, r_src->r_params, b, xtra);
  136. MSG_STRING_DUP(b, r_dst->r_display, r_src->r_display);
  137. URL_DUP(b, end, r_dst->r_url, r_src->r_url);
  138. assert(b <= end);
  139. return b;
  140. }
  141. /* ====================================================================== */
  142. /**@SIP_HEADER sip_referred_by Referred-By Header
  143. *
  144. * The Referred-By header conveys the identity of the original referrer to
  145. * the referred-to party. Its syntax is defined in
  146. * @RFC3892 section 3 as follows:
  147. *
  148. * @code
  149. * Referred-By = ("Referred-By" / "b") HCOLON referrer-uri
  150. * *( SEMI (referredby-id-param / generic-param) )
  151. *
  152. * referrer-uri = ( name-addr / addr-spec )
  153. *
  154. * referredby-id-param = "cid" EQUAL sip-clean-msg-id
  155. *
  156. * sip-clean-msg-id = LDQUOT dot-atom "@" (dot-atom / host) RDQUOT
  157. *
  158. * dot-atom = atom *( "." atom )
  159. *
  160. * atom = 1*( alphanum / "-" / "!" / "%" / "*" /
  161. * "_" / "+" / "'" / "`" / "~" )
  162. * @endcode
  163. *
  164. *
  165. * The parsed Referred-By header is stored in #sip_referred_by_t structure.
  166. */
  167. /**@ingroup sip_referred_by
  168. *
  169. * @typedef typedef struct sip_referred_by_s sip_referred_by_t;
  170. *
  171. * The structure #sip_referred_by_t contains representation of @ReferredBy
  172. * header.
  173. *
  174. * The #sip_referred_by_t is defined as follows:
  175. * @code
  176. * typedef struct sip_referred_by_s
  177. * {
  178. * sip_common_t b_common[1]; // Common fragment info
  179. * sip_error_t *b_next; // Link to next (dummy)
  180. * char const b_display,
  181. * url_t b_url[1]; // Referrer-URI
  182. * msg_param_t const *b_params; // List of parameters
  183. * char const *b_cid;
  184. * } sip_referred_by_t;
  185. * @endcode
  186. */
  187. static msg_xtra_f sip_referred_by_dup_xtra;
  188. static msg_dup_f sip_referred_by_dup_one;
  189. static msg_update_f sip_referred_by_update;
  190. msg_hclass_t sip_referred_by_class[] =
  191. SIP_HEADER_CLASS(referred_by, "Referred-By", "b", b_params, single,
  192. referred_by);
  193. issize_t sip_referred_by_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
  194. {
  195. sip_referred_by_t *b = h->sh_referred_by;
  196. if (sip_name_addr_d(home, &s,
  197. &b->b_display,
  198. b->b_url,
  199. &b->b_params,
  200. NULL) < 0 || *s /* Extra stuff? */)
  201. return -1;
  202. if (b->b_params)
  203. msg_header_update_params(b->b_common, 0);
  204. return 0;
  205. }
  206. issize_t sip_referred_by_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
  207. {
  208. assert(sip_is_referred_by(h));
  209. return sip_name_addr_e(b, bsiz, flags,
  210. h->sh_referred_by->b_display,
  211. MSG_IS_CANONIC(flags), h->sh_referred_by->b_url,
  212. h->sh_referred_by->b_params,
  213. NULL);
  214. }
  215. isize_t sip_referred_by_dup_xtra(sip_header_t const *h, isize_t offset)
  216. {
  217. sip_referred_by_t const *b = h->sh_referred_by;
  218. MSG_PARAMS_SIZE(offset, b->b_params);
  219. offset += MSG_STRING_SIZE(b->b_display);
  220. offset += url_xtra(b->b_url);
  221. return offset;
  222. }
  223. char *sip_referred_by_dup_one(sip_header_t *dst, sip_header_t const *src,
  224. char *b,
  225. isize_t xtra)
  226. {
  227. sip_referred_by_t *nb = dst->sh_referred_by;
  228. sip_referred_by_t const *o = src->sh_referred_by;
  229. char *end = b + xtra;
  230. b = msg_params_dup(&nb->b_params, o->b_params, b, xtra);
  231. MSG_STRING_DUP(b, nb->b_display, o->b_display);
  232. URL_DUP(b, end, nb->b_url, o->b_url);
  233. nb->b_cid = msg_params_find(nb->b_params, "cid=");
  234. assert(b <= end);
  235. return b;
  236. }
  237. static int sip_referred_by_update(msg_common_t *h,
  238. char const *name, isize_t namelen,
  239. char const *value)
  240. {
  241. sip_referred_by_t *b = (sip_referred_by_t *)h;
  242. if (name == NULL) {
  243. b->b_cid = NULL;
  244. }
  245. else if (namelen == strlen("cid") && su_casenmatch(name, "cid", namelen)) {
  246. b->b_cid = value;
  247. }
  248. return 0;
  249. }
  250. /* ====================================================================== */
  251. /**@SIP_HEADER sip_replaces Replaces Header
  252. *
  253. * The Replaces header indicates that a single dialog identified by the
  254. * header field is to be shut down and logically replaced by the incoming
  255. * INVITE in which it is contained. Its syntax is defined in
  256. * @RFC3891 section 6.1 as follows:
  257. *
  258. * @code
  259. * Replaces = "Replaces" HCOLON callid *(SEMI replaces-param)
  260. * replaces-param = to-tag / from-tag / early-flag / generic-param
  261. * to-tag = "to-tag" EQUAL token
  262. * from-tag = "from-tag" EQUAL token
  263. * early-flag = "early-only"
  264. * @endcode
  265. *
  266. * A Replaces header field MUST contain exactly one <to-tag> and exactly
  267. * one <from-tag>, as they are required for unique dialog matching. For
  268. * compatibility with dialogs initiated by @RFC2543 compliant UAs, a
  269. * tag of zero ("0") matches both tags of zero and null. A Replaces header
  270. * field MAY contain the <early-only> flag.
  271. *
  272. * The parsed Replaces header is stored in #sip_replaces_t structure.
  273. *
  274. * @sa @RFC3891, nta_leg_by_replaces(), nta_leg_make_replaces()
  275. */
  276. /**@ingroup sip_replaces
  277. *
  278. * @typedef typedef struct sip_replaces_s sip_replaces_t;
  279. *
  280. * The structure #sip_replaces_t contains representation of @Replaces
  281. * header.
  282. *
  283. * The #sip_replaces_t is defined as follows:
  284. * @code
  285. * typedef struct sip_replaces_s
  286. * {
  287. * sip_common_t rp_common[1]; // Common fragment info
  288. * sip_error_t *rp_next; // Dummy link to next
  289. * char const *rp_call_id; // @CallID of dialog to replace
  290. * msg_param_t const *rp_params; // List of parameters
  291. * char const *rp_to_tag; // Value of "to-tag" parameter
  292. * char const *rp_from_tag; // Value of "from-tag" parameter
  293. * unsigned rp_early_only; // early-only parameter
  294. * } sip_replaces_t;
  295. * @endcode
  296. */
  297. static msg_xtra_f sip_replaces_dup_xtra;
  298. static msg_dup_f sip_replaces_dup_one;
  299. static msg_update_f sip_replaces_update;
  300. msg_hclass_t sip_replaces_class[] =
  301. SIP_HEADER_CLASS(replaces, "Replaces", "", rp_params, single, replaces);
  302. /** Decode (parse) @Replaces header */
  303. issize_t sip_replaces_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
  304. {
  305. sip_replaces_t *rp = h->sh_replaces;
  306. rp->rp_call_id = sip_word_at_word_d(&s);
  307. if (!rp->rp_call_id)
  308. return -1;
  309. if (*s) {
  310. if (msg_params_d(home, &s, &rp->rp_params) == -1)
  311. return -1;
  312. msg_header_update_params(rp->rp_common, 0);
  313. }
  314. return s - rp->rp_call_id;
  315. }
  316. /** Encode (print) @Replaces header */
  317. issize_t sip_replaces_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
  318. {
  319. char *b0 = b, *end = b + bsiz;
  320. sip_replaces_t const *rp = h->sh_replaces;
  321. assert(sip_is_replaces(h));
  322. MSG_STRING_E(b, end, rp->rp_call_id);
  323. MSG_PARAMS_E(b, end, rp->rp_params, flags);
  324. MSG_TERM_E(b, end);
  325. return b - b0;
  326. }
  327. /** Calculate extra storage used by @Replaces header field */
  328. isize_t sip_replaces_dup_xtra(sip_header_t const *h, isize_t offset)
  329. {
  330. sip_replaces_t const *rp = h->sh_replaces;
  331. MSG_PARAMS_SIZE(offset, rp->rp_params);
  332. offset += MSG_STRING_SIZE(rp->rp_call_id);
  333. return offset;
  334. }
  335. /** Duplicate a @Replaces header field */
  336. char *sip_replaces_dup_one(sip_header_t *dst, sip_header_t const *src,
  337. char *b, isize_t xtra)
  338. {
  339. sip_replaces_t *rp_dst = dst->sh_replaces;
  340. sip_replaces_t const *rp_src = src->sh_replaces;
  341. char *end = b + xtra;
  342. b = msg_params_dup(&rp_dst->rp_params, rp_src->rp_params, b, xtra);
  343. MSG_STRING_DUP(b, rp_dst->rp_call_id, rp_src->rp_call_id);
  344. assert(b <= end); (void)end;
  345. return b;
  346. }
  347. /** Update parameters in @Replaces header. */
  348. static int sip_replaces_update(msg_common_t *h,
  349. char const *name, isize_t namelen,
  350. char const *value)
  351. {
  352. sip_replaces_t *rp = (sip_replaces_t *)h;
  353. if (name == NULL) {
  354. rp->rp_to_tag = NULL;
  355. rp->rp_from_tag = NULL;
  356. rp->rp_early_only = 0;
  357. }
  358. #define MATCH(s) (namelen == strlen(#s) && su_casenmatch(name, #s, strlen(#s)))
  359. else if (MATCH(to-tag)) {
  360. rp->rp_to_tag = value;
  361. }
  362. else if (MATCH(from-tag)) {
  363. rp->rp_from_tag = value;
  364. }
  365. else if (MATCH(early-only)) {
  366. rp->rp_early_only = value != NULL;
  367. }
  368. #undef MATCH
  369. return 0;
  370. }
  371. /* ====================================================================== */
  372. /**@SIP_HEADER sip_refer_sub Refer-Sub Header
  373. *
  374. * SIP header field @b Refer-Sub is meaningful and MAY be used with a REFER
  375. * request and the corresponding 2XX response only. This header field set to
  376. * "false" specifies that a REFER-Issuer requests that the REFER-Recipient
  377. * doesn't establish an implicit subscription and the resultant dialog.
  378. *
  379. * Refer-Sub = "Refer-Sub" HCOLON refer-sub-value *(SEMI exten)
  380. * refer-sub-value = "true" / "false"
  381. * exten = generic-param
  382. *
  383. * The parsed Refer-Sub header is stored in #sip_refer_sub_t structure.
  384. *
  385. * @NEW_1_12_5. Note that #sip_t does not contain @a sip_refer_sub field,
  386. * but sip_refer_sub() accessor function should be used for accessing @b
  387. * Refer-Sub header structure.
  388. *
  389. * @sa @RFC4488, nua_refer(), #nua_i_refer
  390. */
  391. /**@ingroup sip_refer_sub
  392. *
  393. * @typedef typedef struct sip_refer_sub_s sip_refer_sub_t;
  394. *
  395. * The structure #sip_refer_sub_t contains representation of @ReferSub
  396. * header.
  397. *
  398. * The #sip_refer_sub_t is defined as follows:
  399. * @code
  400. * typedef struct sip_refer_sub_s
  401. * {
  402. * sip_common_t rs_common[1]; // Common fragment info
  403. * sip_error_t *rs_next; // Dummy link to next
  404. * char const *rs_value; // "true" or "false"
  405. * msg_param_t const *rs_params; // List of extension parameters
  406. * } sip_refer_sub_t;
  407. * @endcode
  408. *
  409. * @NEW_1_12_5.
  410. */
  411. static msg_xtra_f sip_refer_sub_dup_xtra;
  412. static msg_dup_f sip_refer_sub_dup_one;
  413. #define sip_refer_sub_update NULL
  414. msg_hclass_t sip_refer_sub_class[] =
  415. SIP_HEADER_CLASS(refer_sub, "Refer-Sub", "", rs_params, single, refer_sub);
  416. /** Decode (parse) @ReferSub header */
  417. issize_t sip_refer_sub_d(su_home_t *home,
  418. sip_header_t *h,
  419. char *s, isize_t slen)
  420. {
  421. sip_refer_sub_t *rs = (sip_refer_sub_t *)h;
  422. if (msg_token_d(&s, &rs->rs_value) < 0)
  423. return -1;
  424. if (!su_casematch(rs->rs_value, "false") &&
  425. !su_casematch(rs->rs_value, "true"))
  426. return -1;
  427. if (*s)
  428. if (msg_params_d(home, &s, &rs->rs_params) == -1)
  429. return -1;
  430. return s - rs->rs_value;
  431. }
  432. /** Encode (print) @ReferSub header */
  433. issize_t sip_refer_sub_e(char b[], isize_t bsiz,
  434. sip_header_t const *h,
  435. int flags)
  436. {
  437. char *b0 = b, *end = b + bsiz;
  438. sip_refer_sub_t const *rs = (sip_refer_sub_t *)h;
  439. assert(sip_is_refer_sub(h));
  440. MSG_STRING_E(b, end, rs->rs_value);
  441. MSG_PARAMS_E(b, end, rs->rs_params, flags);
  442. MSG_TERM_E(b, end);
  443. return b - b0;
  444. }
  445. /** Calculate extra storage used by @ReferSub header field */
  446. isize_t sip_refer_sub_dup_xtra(sip_header_t const *h, isize_t offset)
  447. {
  448. sip_refer_sub_t const *rs = (sip_refer_sub_t *)h;
  449. MSG_PARAMS_SIZE(offset, rs->rs_params);
  450. offset += MSG_STRING_SIZE(rs->rs_value);
  451. return offset;
  452. }
  453. /** Duplicate a @ReferSub header field */
  454. char *sip_refer_sub_dup_one(sip_header_t *dst, sip_header_t const *src,
  455. char *b, isize_t xtra)
  456. {
  457. sip_refer_sub_t *rs_dst = (sip_refer_sub_t *)dst;
  458. sip_refer_sub_t const *rs_src = (sip_refer_sub_t *)src;
  459. char *end = b + xtra;
  460. b = msg_params_dup(&rs_dst->rs_params, rs_src->rs_params, b, xtra);
  461. MSG_STRING_DUP(b, rs_dst->rs_value, rs_src->rs_value);
  462. assert(b <= end); (void)end;
  463. return b;
  464. }