/* * Copyright (C) 2010 Stefan Sayer * * This file is part of SEMS, a free SIP media server. * * SEMS is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * For a license to use the SEMS software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * SEMS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ParamReplacer.h" #include "log.h" #include "AmSipHeaders.h" #include "AmUtils.h" #include "SBC.h" // for RegexMapper SBCFactory::regex_mappings void replaceParsedParam(const string& s, size_t p, AmUriParser& parsed, string& res) { switch (s[p+1]) { case 'u': { // URI res+=parsed.uri_user+"@"+parsed.uri_host; if (!parsed.uri_port.empty()) res+=":"+parsed.uri_port; } break; case 'U': res+=parsed.uri_user; break; // User case 'd': { // domain res+=parsed.uri_host; if (!parsed.uri_port.empty()) res+=":"+parsed.uri_port; } break; case 'h': res+=parsed.uri_host; break; // host case 'p': res+=parsed.uri_port; break; // port case 'H': res+=parsed.uri_headers; break; // Headers case 'P': res+=parsed.uri_param; break; // Params default: WARN("unknown replace pattern $%c%c\n", s[p], s[p+1]); break; }; } string replaceParameters(const string& s, const char* r_type, const AmSipRequest& req, const string& app_param, AmUriParser& ruri_parser, AmUriParser& from_parser, AmUriParser& to_parser) { string res; bool is_replaced = false; size_t p = 0; bool is_escaped = false; // char last_char=' '; while (p= p+1)) { is_replaced = true; p++; switch (s[p]) { case 'f': { // from if ((s.length() == p+1) || (s[p+1] == '.')) { res += req.from; break; } if (from_parser.uri.empty()) { from_parser.uri = req.from; if (!from_parser.parse_uri()) { WARN("Error parsing From URI '%s'\n", req.from.c_str()); break; } } replaceParsedParam(s, p, from_parser, res); }; break; case 't': { // to if ((s.length() == p+1) || (s[p+1] == '.')) { res += req.to; break; } if (to_parser.uri.empty()) { to_parser.uri = req.to; if (!to_parser.parse_uri()) { WARN("Error parsing To URI '%s'\n", req.to.c_str()); break; } } replaceParsedParam(s, p, to_parser, res); }; break; case 'r': { // r-uri if ((s.length() == p+1) || (s[p+1] == '.')) { res += req.r_uri; break; } if (ruri_parser.uri.empty()) { ruri_parser.uri = req.r_uri; if (!ruri_parser.parse_uri()) { WARN("Error parsing R-URI '%s'\n", req.r_uri.c_str()); break; } } replaceParsedParam(s, p, ruri_parser, res); }; break; case 'c': { // call-id if ((s.length() == p+1) || (s[p+1] == 'i')) { res += req.callid; break; } WARN("unknown replacement $c%c\n", s[p+1]); }; break; case 's': { // source (remote) if (s.length() < p+1) { WARN("unknown replacement $s\n"); break; } if (s[p+1] == 'i') { // $si source IP address res += req.remote_ip.c_str(); break; } else if (s[p+1] == 'p') { // $sp source port res += int2str(req.remote_port); break; } WARN("unknown replacement $s%c\n", s[p+1]); }; break; case 'R': { // received (local) if (s.length() < p+1) { WARN("unknown replacement $R\n"); break; } if (s[p+1] == 'i') { // $si source IP address res += req.local_ip.c_str(); break; } else if (s[p+1] == 'p') { // $sp source port res += int2str(req.local_port); break; } WARN("unknown replacement $R%c\n", s[p+1]); }; break; #define case_HDR(pv_char, pv_name, hdr_name) \ case pv_char: { \ AmUriParser uri_parser; \ uri_parser.uri = getHeader(req.hdrs, hdr_name); \ if ((s.length() == p+1) || (s[p+1] == '.')) { \ res += uri_parser.uri; \ break; \ } \ \ if (!uri_parser.parse_uri()) { \ WARN("Error parsing " pv_name " URI '%s'\n", uri_parser.uri.c_str()); \ break; \ } \ if (s[p+1] == 'i') { \ res+=uri_parser.uri_user+"@"+uri_parser.uri_host; \ if (!uri_parser.uri_port.empty()) \ res+=":"+uri_parser.uri_port; \ } else { \ replaceParsedParam(s, p, uri_parser, res); \ } \ }; break; case_HDR('a', "PAI", SIP_HDR_P_ASSERTED_IDENTITY); // P-Asserted-Identity case_HDR('p', "PPI", SIP_HDR_P_PREFERRED_IDENTITY); // P-Preferred-Identity case 'P': { // app-params if (s[p+1] != '(') { WARN("Error parsing P param replacement (missing '(')\n"); break; } if (s.length()"); if (spos == string::npos) { skip_chars = skip_p-p; WARN("Error parsing $M regex map replacement: no => found in '%s'\n", map_str.c_str()); break; } string map_val = map_str.substr(0, spos); string map_val_replaced = replaceParameters(map_val, r_type, req, app_param, ruri_parser, from_parser, to_parser); string mapping_name = map_str.substr(spos+2); string map_res; if (SBCFactory::regex_mappings. mapRegex(mapping_name, map_val_replaced.c_str(), map_res)) { DBG("matched regex mapping '%s' (orig '%s) in '%s'\n", map_val_replaced.c_str(), map_val.c_str(), mapping_name.c_str()); res+=map_res; } else { DBG("no match in regex mapping '%s' (orig '%s') in '%s'\n", map_val_replaced.c_str(), map_val.c_str(), mapping_name.c_str()); } skip_chars = skip_p-p; } break; default: { WARN("unknown replace pattern $%c%c\n", s[p], s[p+1]); }; break; }; p+=skip_chars; // skip $.X } else { res += s[p]; } } // end not escaped p++; } if (is_replaced) { DBG("%s pattern replace: '%s' -> '%s'\n", r_type, s.c_str(), res.c_str()); } return res; }