1 /*
2 * Copyright (C) 2013 Stefan Sayer
3 *
4 * This file is part of SEMS, a free SIP media server.
5 *
6 * SEMS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * For a license to use the SEMS software under conditions
12 * other than those described here, or to purchase support for this
13 * software, please contact iptel.org by e-mail at the following addresses:
14 * info@iptel.org
15 *
16 * SEMS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include "ReplacesMapper.h"
27 #include "AmUtils.h"
28 #include "AmUriParser.h"
29 #include "AmSipHeaders.h"
30
31 bool findTag(const string replaces, const string& tag, size_t& p1, size_t& len);
32
fixReplaces(string & req_hdrs,bool is_invite)33 void fixReplaces(string& req_hdrs, bool is_invite) {
34
35 string replaces;
36 string refer_to;
37 AmUriParser refer_target;
38 vector<string> hdrs; // headers from Refer-To URI
39 vector<string>::iterator replaces_hdr_it; // Replaces header from Refer-To URI
40
41 DBG("Replaces handler: fixing %s request\n", is_invite?"INVITE":"REFER");
42
43 if (is_invite) {
44 replaces = getHeader(req_hdrs, SIP_HDR_REPLACES, true);
45 if (replaces.empty()) {
46 DBG("Replaces handler: no Replaces in INVITE, ignoring\n");
47 return;
48 }
49 } else {
50 refer_to = getHeader(req_hdrs, SIP_HDR_REFER_TO, SIP_HDR_REFER_TO_COMPACT, true);
51 if (refer_to.empty()) {
52 DBG("Replaces handler: empty Refer-To header, ignoring\n");
53 return;
54 }
55
56 size_t pos=0; size_t end=0;
57 if (!refer_target.parse_contact(refer_to, pos, end)) {
58 DBG("Replaces handler: unable to parse Refer-To name-addr, ignoring\n");
59 return;
60 }
61
62 if (refer_target.uri_headers.empty()) {
63 DBG("Replaces handler: no headers in Refer-To target, ignoring\n");
64 return;
65 }
66
67 hdrs = explode(refer_target.uri_headers, ";");
68 for (replaces_hdr_it=hdrs.begin(); replaces_hdr_it != hdrs.end(); replaces_hdr_it++) {
69
70 string s = URL_decode(*replaces_hdr_it);
71 const char* Replaces_str = "Replaces";
72 if ((s.length() >= 8) &&
73 !strncmp(Replaces_str, s.c_str(), 8)) {
74 size_t pos = 8;
75 while (s.length()>pos && (s[pos] == ' ' || s[pos] == '\t')) pos++;
76 if (s[pos] != '=')
77 continue;
78 pos++;
79 while (s.length()>pos && (s[pos] == ' ' || s[pos] == '\t')) pos++;
80 replaces = s.substr(pos);
81 break;
82 }
83 }
84
85 if (replaces_hdr_it == hdrs.end()) {
86 DBG("Replaces handler: no Replaces headers in Refer-To target, ignoring\n");
87 return;
88 }
89 }
90
91 DBG("Replaces found: '%s'\n", replaces.c_str());
92 size_t ftag_begin; size_t ftag_len;
93 size_t ttag_begin; size_t ttag_len;
94 size_t cid_len=0;
95
96 // todo: parse full replaces header and reconstruct including unknown params
97 if (!findTag(replaces, "from-tag=", ftag_begin, ftag_len)) {
98 WARN("Replaces missing 'from-tag', ignoring\n");
99 return;
100 }
101
102 if (!findTag(replaces, "to-tag=", ttag_begin, ttag_len)) {
103 WARN("Replaces missing 'to-tag', ignoring\n");
104 return;
105 }
106 while (cid_len < replaces.size() && replaces[cid_len] != ';')
107 cid_len++;
108
109 string ftag = replaces.substr(ftag_begin, ftag_len);
110 string ttag = replaces.substr(ttag_begin, ttag_len);
111 string callid = replaces.substr(0, cid_len);
112 bool early_only = replaces.find("early-only") != string::npos;
113
114 DBG("Replaces handler: found callid='%s', ftag='%s', ttag='%s'\n",
115 callid.c_str(), ftag.c_str(), ttag.c_str());
116
117 SBCCallRegistryEntry other_dlg;
118 if (SBCCallRegistry::lookupCall(ttag, other_dlg)) {
119 replaces = other_dlg.callid+
120 ";from-tag="+other_dlg.ltag+";to-tag="+other_dlg.rtag;
121 if (early_only)
122 replaces += ";early_only";
123 DBG("Replaces handler: mapped Replaces to: '%s'\n", replaces.c_str());
124
125 if (is_invite) {
126 removeHeader(req_hdrs, SIP_HDR_REPLACES);
127 req_hdrs+=SIP_HDR_COLSP(SIP_HDR_REPLACES)+replaces+CRLF;
128 } else {
129 string replaces_enc = SIP_HDR_REPLACES "="+URL_encode(replaces);
130 string new_hdrs;
131 for (vector<string>::iterator it = hdrs.begin(); it != hdrs.end(); it++) {
132 if (it != hdrs.begin())
133 new_hdrs+=";";
134
135 if (it != replaces_hdr_it) {
136 // different hdr, just add it
137 new_hdrs+=*it;
138 } else {
139 //reconstructed replaces hdr
140 new_hdrs+=replaces_enc;
141 }
142 }
143 refer_target.uri_headers=new_hdrs;
144 removeHeader(req_hdrs, SIP_HDR_REFER_TO);
145 removeHeader(req_hdrs, SIP_HDR_REFER_TO_COMPACT);
146 req_hdrs+=SIP_HDR_COLSP(SIP_HDR_REFER_TO)+refer_target.nameaddr_str()+CRLF;
147 }
148
149 } else {
150 DBG("Replaces handler: call with tag '%s' not found\n", ttag.c_str());
151 }
152
153
154 }
155
findTag(const string replaces,const string & tag,size_t & p1,size_t & len)156 bool findTag(const string replaces, const string& tag, size_t& p1, size_t& len)
157 {
158 size_t i = replaces.find(tag);
159 if (i == string::npos) return false;
160
161 p1 = i+tag.length();
162 size_t j = replaces.find(';', p1);
163
164 if (j != string::npos) {
165 len = j - p1;
166 } else {
167 len = replaces.size() - i;
168 }
169 return true;
170 }
171
172