/* * Copyright (C) 2011 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 "AmPlugIn.h" #include "log.h" #include "AmArg.h" #include "SBC.h" #include "CCCtl.h" #include "SBCCallControlAPI.h" #include <string.h> #include <algorithm> class CCCtlFactory : public AmDynInvokeFactory { public: CCCtlFactory(const string& name) : AmDynInvokeFactory(name) {} AmDynInvoke* getInstance(){ return CCCtl::instance(); } int onLoad(){ if (CCCtl::instance()->onLoad()) return -1; DBG("ctl call control loaded.\n"); return 0; } }; EXPORT_PLUGIN_CLASS_FACTORY(CCCtlFactory, "ctl"); CCCtl* CCCtl::_instance=0; CCCtl* CCCtl::instance() { if(!_instance) _instance = new CCCtl(); return _instance; } CCCtl::CCCtl() { } CCCtl::~CCCtl() { } int CCCtl::onLoad() { AmConfigReader cfg; // if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) { // INFO(MOD_NAME "configuration file (%s) not found, " // "assuming default configuration is fine\n", // (AmConfig::ModConfigPath + string(MOD_NAME ".conf")).c_str()); // return 0; // } // syslog_prefix = cfg.hasParameter("cdr_prefix") ? // cfg.getParameter("cdr_prefix") : syslog_prefix; return 0; } void CCCtl::invoke(const string& method, const AmArg& args, AmArg& ret) { DBG("CCCtl: %s(%s)\n", method.c_str(), AmArg::print(args).c_str()); if(method == "start"){ SBCCallProfile* call_profile = dynamic_cast<SBCCallProfile*>(args[CC_API_PARAMS_CALL_PROFILE].asObject()); start(args[CC_API_PARAMS_CC_NAMESPACE].asCStr(), args[CC_API_PARAMS_LTAG].asCStr(), call_profile, args[CC_API_PARAMS_TIMESTAMPS][CC_API_TS_START_SEC].asInt(), args[CC_API_PARAMS_TIMESTAMPS][CC_API_TS_START_USEC].asInt(), args[CC_API_PARAMS_CFGVALUES], args[CC_API_PARAMS_TIMERID].asInt(), ret); } else if(method == "connect"){ // dummy } else if(method == "end"){ // dummy } else if(method == "_list"){ ret.push("start"); ret.push("connect"); ret.push("end"); } else throw AmDynInvoke::NotImplemented(method); } void CCCtl::start(const string& cc_name, const string& ltag, SBCCallProfile* call_profile, int start_ts_sec, int start_ts_usec, const AmArg& values, int timer_id, AmArg& res) { if (!call_profile) { ERROR("internal - call profile not found\n"); return; } #define SET_TO_CALL_PROFILE(cfgparam, member) \ if (values.hasMember(cfgparam)) { \ DBG("setting '%s' to '%s'\n", cfgparam, values[cfgparam].asCStr()); \ call_profile->member = values[cfgparam].asCStr(); \ } #define ADD_TO_CALL_PROFILE(cfgparam, member) \ if (values.hasMember(cfgparam)) { \ DBG("adding '%s' to '%s'\n", values[cfgparam].asCStr(), cfgparam); \ call_profile->member += values[cfgparam].asCStr(); \ } #define ENABLE_IN_CALL_PROFILE(cfgparam, member) \ if (values.hasMember(cfgparam)) { \ call_profile->member = \ string(values[cfgparam].asCStr()) == "yes"; \ DBG("%sabling '%s'\n", call_profile->member?"en":"dis", \ values[cfgparam].asCStr()); \ } SET_TO_CALL_PROFILE("RURI", ruri); SET_TO_CALL_PROFILE("From", from); SET_TO_CALL_PROFILE("To", to); //TODO: SET_TO_CALL_PROFILE("Contact", contact); SET_TO_CALL_PROFILE("Call-ID", callid); SET_TO_CALL_PROFILE("outbound_proxy", outbound_proxy); ENABLE_IN_CALL_PROFILE("force_outbound_proxy", force_outbound_proxy); SET_TO_CALL_PROFILE("next_hop", next_hop); SET_TO_CALL_PROFILE("sst_enabled", sst_enabled); SET_TO_CALL_PROFILE("sst_aleg_enabled", sst_aleg_enabled); ADD_TO_CALL_PROFILE("append_headers", append_headers); if (call_profile->append_headers.size() > 2) assertEndCRLF(call_profile->append_headers); SET_TO_CALL_PROFILE("rtprelay_enabled", rtprelay_enabled); SET_TO_CALL_PROFILE("rtprelay_interface", rtprelay_interface); SET_TO_CALL_PROFILE("aleg_rtprelay_interface", aleg_rtprelay_interface); SET_TO_CALL_PROFILE("outbound_interface", outbound_interface); if (values.hasMember("headerfilter")) { string hf = values["headerfilter"].asCStr(); FilterType t = String2FilterType(hf.c_str()); if (Undefined != t) { call_profile->headerfilter.push_back(FilterEntry()); call_profile->headerfilter.back().filter_type = t; string hl; if (values.hasMember("header_list")) hl = values["header_list"].asCStr(); vector<string> elems = explode(hl, "|"); for (vector<string>::iterator it=elems.begin(); it != elems.end(); it++) { transform(it->begin(), it->end(), it->begin(), ::tolower); call_profile->headerfilter.back().filter_list.insert(*it); } DBG("call control '%s': set header filter '%s', list '%s'\n", cc_name.c_str(), FilterType2String(t), hl.c_str()); } } if (values.hasMember("messagefilter")) { string hf = values["messagefilter"].asCStr(); FilterType t = String2FilterType(hf.c_str()); if (Undefined != t) { call_profile->messagefilter.push_back(FilterEntry()); call_profile->messagefilter.back().filter_type = t; string hl; if (values.hasMember("message_list")) hl = values["message_list"].asCStr(); vector<string> elems = explode(hl, "|"); for (vector<string>::iterator it=elems.begin(); it != elems.end(); it++) { call_profile->messagefilter.back().filter_list.insert(*it); } DBG("call control '%s': set message filter '%s', list '%s'\n", cc_name.c_str(), FilterType2String(t), hl.c_str()); } } }