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<s.length()) {
    size_t skip_chars = 1;

    if (is_escaped) {
      switch (s[p]) {
      case 'r': res += '\r'; break;
      case 'n': res += '\n'; break;
      case 't': res += '\t'; break;
      default: res += s[p]; break;
      }
      is_escaped = false;
    } else { // not escaped
      if (s[p]=='\\') {
	if (p==s.length()-1) {
	  res += '\\'; // add single \ at the end
	} else {
	  is_escaped = true;
	  is_replaced = true;
	}
      } else if ((s[p]=='$') && (s.length() >= 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 (s[p+1]=='t') { // $ft - from tag
	    res += req.from_tag;
	    break;
	  }

	  if (from_parser.uri.empty()) {
	    size_t end;
	    if (!from_parser.parse_contact(req.from, 0, end)) {
	      WARN("Error parsing From URI '%s'\n", req.from.c_str());
	      break;
	    }
	    from_parser.dump();
	  }

	  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()) {
	    size_t end;
	    if (!to_parser.parse_contact(req.to, 0, end)) {
	      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') { // $Ri received IP address
	    res += req.local_ip.c_str();
	    break;
	  } else if (s[p+1] == 'p') { // $Rp received port
	    res += int2str(req.local_port);
	    break;
	  } else if (s[p+1] == 'f') { // $Rf received interface id
	    res += int2str(req.local_if);
	  } else if (s[p+1] == 'n') { // $Rn received interface name
	    if ((req.local_if >= 0) && req.local_if < AmConfig::Ifs.size()) {
	      res += AmConfig::Ifs[req.local_if].name;
	    }
	  } else if (s[p+1] == 'I') { // $RI received interface public IP
	    if ((req.local_if >= 0) && req.local_if < AmConfig::Ifs.size()) {
	      res += AmConfig::Ifs[req.local_if].PublicIP;
	    }
	  }
	  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;					\
	    string m_uri = getHeader(req.hdrs, hdr_name);		\
	    if ((s.length() == p+1) || (s[p+1] == '.')) {		\
	      res += m_uri;						\
	      break;							\
	    }								\
	    size_t end;							\
	    if (!uri_parser.parse_contact(m_uri, 0, end)) {		\
	      WARN("Error parsing " pv_name " URI '%s'\n", m_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()<p+3) {
	    WARN("Error parsing P param replacement (short string)\n");
	    break;
	  }

	  size_t skip_p = p+2;
	  for (;skip_p<s.length() && s[skip_p] != ')';skip_p++) { }
	  if (skip_p==s.length()) {
	    WARN("Error parsing P param replacement (unclosed brackets)\n");
	    break;
	  }
	  string param_name = s.substr(p+2, skip_p-p-2);
	  // DBG("param_name = '%s' (skip-p - p = %d)\n", param_name.c_str(), skip_p-p);
	  res += get_header_keyvalue(app_param, param_name);
	  skip_chars = skip_p-p;
	} break;

	case 'H': { // header
	  size_t name_offset = 2;
	  if (s[p+1] != '(') {
	    if (s[p+2] != '(') {
	      WARN("Error parsing H header replacement (missing '(')\n");
	      break;
	    }
	    name_offset = 3;
	  }
	  if (s.length()<name_offset+1) {
	    WARN("Error parsing H header replacement (short string)\n");
	    break;
	  }

	  size_t skip_p = p+name_offset;
	  for (;skip_p<s.length() && s[skip_p] != ')';skip_p++) { }
	  if (skip_p==s.length()) {
	    WARN("Error parsing H header replacement (unclosed brackets)\n");
	    break;
	  }
	  string hdr_name = s.substr(p+name_offset, skip_p-p-name_offset);
	  // DBG("param_name = '%s' (skip-p - p = %d)\n", param_name.c_str(), skip_p-p);
	  if (name_offset == 2) {
	    // full header
	    res += getHeader(req.hdrs, hdr_name);
	  } else {
	    // parse URI and use component
	    AmUriParser uri_parser;
	    string m_uri = getHeader(req.hdrs, hdr_name);
	    if ((s[p+1] == '.')) {
	      res += m_uri;
	      break;
	    }

	    size_t end;
	    if (!uri_parser.parse_contact(m_uri, 0, end)) {
	      WARN("Error parsing header %s URI '%s'\n",
		   hdr_name.c_str(), m_uri.c_str());
	      break;
	    }
	    replaceParsedParam(s, p, uri_parser, res);
	  }
	  skip_chars = skip_p-p;
	} break;

	case 'M': { // regex map
	  if (s[p+1] != '(') {
	    WARN("Error parsing $M regex map replacement (missing '(')\n");
	    break;
	  }
	  if (s.length()<p+3) {
	    WARN("Error parsing $M regex map replacement (short string)\n");
	    break;
	  }

	  size_t skip_p = p+2;
	  skip_p = skip_to_end_of_brackets(s, skip_p);

	  if (skip_p==s.length()) {
	    WARN("Error parsing $M regex map replacement (unclosed brackets)\n");
	    skip_chars = skip_p-p;
	    break;
	  }

	  string map_str = s.substr(p+2, skip_p-p-2);
	  size_t spos = map_str.rfind("=>");
	  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;

	case '_': { // modify
	  if (s.length()<p+4) { // $_O()
	    WARN("Error parsing $_ modifier replacement (short string)\n");
	    break;
	  }

	  char operation = s[p+1];
	  if (operation != 'U' && operation != 'l'
	      && operation != 's' && operation != '5') {
	    WARN("Error parsing $_%c string modifier: unknown operator '%c'\n",
		 operation, operation);
	  }

	  if (s[p+2] != '(') {
	    WARN("Error parsing $U upcase replacement (missing '(')\n");
	    break;
	  }

	  size_t skip_p = p+3;
	  skip_p = skip_to_end_of_brackets(s, skip_p);

	  if (skip_p==s.length()) {
	    WARN("Error parsing $_ modifier (unclosed brackets)\n");
	    skip_chars = skip_p-p;
	    break;
	  }

	  string br_str = s.substr(p+3, skip_p-p-3);
	  string br_str_replaced = replaceParameters(br_str, "$_*(...)",
						     req, app_param,
						     ruri_parser, from_parser, to_parser);
	  br_str = br_str_replaced;
	  switch(operation) {
	  case 'u': // uppercase
	    transform(br_str_replaced.begin(), br_str_replaced.end(),
		      br_str_replaced.begin(), ::toupper); break;
	  case 'l': // lowercase
	    transform(br_str_replaced.begin(), br_str_replaced.end(),
		      br_str_replaced.begin(), ::tolower); break;

	  case 's': // size (string length)
	    br_str_replaced = int2str((unsigned int)br_str.length());
	    break;

	  case '5': // md5
	    br_str_replaced = calculateMD5(br_str);
	    break;

	  default: break;
	  }
	  DBG("applied operator '%c': '%s' => '%s'\n", operation,
	      br_str.c_str(), br_str_replaced.c_str());
	  res+=br_str_replaced;

	  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;
}
Beispiel #2
0
void AnnRecorderFactory::getAppParams(const AmSipRequest& req, map<string, string>& params) {
  string language;
  string domain;
  string user;
  string typ;

  if (SimpleMode){
    AmUriParser p;
    p.uri = req.from_uri;
    if (!p.parse_uri()) {
      DBG("parsing From-URI '%s' failed\n", p.uri.c_str());
      throw AmSession::Exception(500, MOD_NAME ": could not parse From-URI");
    }
    user = p.uri_user;
    //domain = p.uri_domain;
    domain = "default";
    typ = DEFAULT_TYPE;
  }
  else {
    string iptel_app_param = getHeader(req.hdrs, PARAM_HDR, true);
    
    if (!iptel_app_param.length()) {
      throw AmSession::Exception(500, MOD_NAME ": parameters not found");
    }
    
    language = get_header_keyvalue(iptel_app_param, "lng", "Language");
    
    user = get_header_keyvalue(iptel_app_param,"uid", "UserID");
    if (user.empty()) {
      user = get_header_keyvalue(iptel_app_param,"usr", "User");
      if (!user.length())
	user = req.user;
    }
    
    domain = get_header_keyvalue(iptel_app_param, "did", "DomainID");
    if (domain.empty()){
      domain = get_header_keyvalue(iptel_app_param, "dom", "Domain");
      if (domain.empty())
	domain = req.domain;
    }
    
    typ = get_header_keyvalue(iptel_app_param, "typ", "Type");
    if (!typ.length())
      typ = DEFAULT_TYPE;
  }
  
  // checks
  if (user.empty()) 
    throw AmSession::Exception(500, MOD_NAME ": user missing");    

  string announce_file = add2path(AnnouncePath,2, domain.c_str(), (user + ".wav").c_str());
  if (file_exists(announce_file)) goto announce_found;

  if (!language.empty()) {
    announce_file = add2path(AnnouncePath,3, domain.c_str(), language.c_str(), DefaultAnnounce.c_str());
    if (file_exists(announce_file)) goto announce_found;
  }

  announce_file = add2path(AnnouncePath,2, domain.c_str(), DefaultAnnounce.c_str());
  if (file_exists(announce_file)) goto announce_found;

  if (!language.empty()) {
    announce_file = add2path(AnnouncePath,2, language.c_str(),  DefaultAnnounce.c_str());
    if (file_exists(announce_file)) goto announce_found;
  }
	
  announce_file = add2path(AnnouncePath,1, DefaultAnnounce.c_str());
  if (!file_exists(announce_file)) 
    announce_file = "";

 announce_found:

  DBG(MOD_NAME " invocation parameters: \n");
  DBG(" User:     <%s> \n", user.c_str());
  DBG(" Domain:   <%s> \n", domain.c_str());
  DBG(" Language: <%s> \n", language.c_str());
  DBG(" Type:     <%s> \n", typ.c_str());
  DBG(" Def. File:<%s> \n", announce_file.c_str());

  params["domain"] = domain;
  params["user"] = user;
  params["defaultfile"] = announce_file;
  params["type"] = typ;
}