diff --git a/apps/ivr/Ivr.cpp b/apps/ivr/Ivr.cpp index 71624add..988028c6 100644 --- a/apps/ivr/Ivr.cpp +++ b/apps/ivr/Ivr.cpp @@ -534,6 +534,10 @@ int IvrDialog::transfer(const string& target) return dlg.transfer(target); } +int IvrDialog::refer(const string& target, int expires) { + return dlg.refer(target, expires); +} + int IvrDialog::drop() { int res = dlg.drop(); diff --git a/apps/ivr/Ivr.h b/apps/ivr/Ivr.h index bc0ed9b6..10543466 100644 --- a/apps/ivr/Ivr.h +++ b/apps/ivr/Ivr.h @@ -141,6 +141,7 @@ class IvrDialog : public AmB2BCallerSession void setPyPtrs(PyObject *mod, PyObject *dlg); int transfer(const string& target); + int refer(const string& target, int expires); int drop(); void onSessionStart(const AmSipRequest& req); diff --git a/apps/ivr/IvrDialogBase.cpp b/apps/ivr/IvrDialogBase.cpp index 578e4867..f258e9e2 100644 --- a/apps/ivr/IvrDialogBase.cpp +++ b/apps/ivr/IvrDialogBase.cpp @@ -495,6 +495,26 @@ IvrDialogBase_redirect(IvrDialogBase *self, PyObject* args) } +static PyObject* +IvrDialogBase_refer(IvrDialogBase *self, PyObject* args) +{ + assert(self->p_dlg); + + char* refer_to=0; + int expires; + if(!PyArg_ParseTuple(args,"si",&refer_to, &expires)) + return NULL; + + if(self->p_dlg->refer(refer_to, expires)){ + ERROR("REFER failed\n"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; + +} + static PyMethodDef IvrDialogBase_methods[] = { @@ -528,6 +548,9 @@ static PyMethodDef IvrDialogBase_methods[] = { "Send a BYE" }, {"redirect", (PyCFunction)IvrDialogBase_redirect, METH_VARARGS, + "Transfers the remote party to some third party." + }, + {"refer", (PyCFunction)IvrDialogBase_refer, METH_VARARGS, "Refers the remote party to some third party." }, {"dropSession", (PyCFunction)IvrDialogBase_dropSession, METH_NOARGS, diff --git a/apps/pin_collect/etc/pin_collect.conf b/apps/pin_collect/etc/pin_collect.conf index 85efb711..a22aec62 100644 --- a/apps/pin_collect/etc/pin_collect.conf +++ b/apps/pin_collect/etc/pin_collect.conf @@ -2,6 +2,8 @@ # authentication mode: # XMLRPC : authenticate against XMLRPC server # REFER : add pin to REFER sent out to be checked at proxy +# TRANSFER : add pin to R-URI, transfer call flow (see Readme.pin_collect.txt) + auth_mode=XMLRPC # XMLRPC url to authenticate against if auth_mode==XMLRPC diff --git a/apps/pin_collect/pin_collect.py b/apps/pin_collect/pin_collect.py index a2c10c8f..af53173a 100644 --- a/apps/pin_collect/pin_collect.py +++ b/apps/pin_collect/pin_collect.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from log import * from ivr import * @@ -101,6 +102,12 @@ class IvrDialog(IvrDialogBase): self.fail_msg.open(config['fail_msg'],AUDIO_READ) self.enqueue(self.fail_msg,None) + elif config['auth_mode'] == 'REFER': + self.state = connect + self.removeTimer(HINT_TIMER) + self.transfer_cseq = self.dialog.cseq + self.refer("sip:" + self.dialog.user + "+" + self.keys + "@" + \ + self.dialog.domain, 20) else: self.state = connect self.removeTimer(HINT_TIMER) diff --git a/apps/sbc/CMakeLists.txt b/apps/sbc/CMakeLists.txt index 5f015239..d25693e8 100644 --- a/apps/sbc/CMakeLists.txt +++ b/apps/sbc/CMakeLists.txt @@ -1,5 +1,6 @@ set (sbc_SRCS SBC.cpp +SBCCallProfile.cpp HeaderFilter.cpp ParamReplacer.cpp SDPFilter.cpp diff --git a/apps/sbc/SBC.cpp b/apps/sbc/SBC.cpp index 3fad5a43..0c66bb42 100644 --- a/apps/sbc/SBC.cpp +++ b/apps/sbc/SBC.cpp @@ -52,7 +52,6 @@ SBC - feature-wishlist #include "ParamReplacer.h" #include "SDPFilter.h" -#include using std::map; string SBCFactory::user; @@ -64,186 +63,6 @@ AmSessionEventHandlerFactory* SBCFactory::session_timer_fact = NULL; EXPORT_SESSION_FACTORY(SBCFactory,MOD_NAME); -bool SBCCallProfile::readFromConfiguration(const string& name, - const string profile_file_name) { - if (cfg.loadFile(profile_file_name)) { - ERROR("reading SBC call profile from '%s'\n", profile_file_name.c_str()); - return false; - } - - ruri = cfg.getParameter("RURI"); - from = cfg.getParameter("From"); - to = cfg.getParameter("To"); - - callid = cfg.getParameter("Call-ID"); - - force_outbound_proxy = cfg.getParameter("force_outbound_proxy") == "yes"; - outbound_proxy = cfg.getParameter("outbound_proxy"); - - next_hop_ip = cfg.getParameter("next_hop_ip"); - next_hop_port = cfg.getParameter("next_hop_port"); - - string hf_type = cfg.getParameter("header_filter", "transparent"); - if (hf_type=="transparent") - headerfilter = Transparent; - else if (hf_type=="whitelist") - headerfilter = Whitelist; - else if (hf_type=="blacklist") - headerfilter = Blacklist; - else { - ERROR("invalid header_filter mode '%s'\n", hf_type.c_str()); - return false; - } - - vector elems = explode(cfg.getParameter("header_list"), ","); - for (vector::iterator it=elems.begin(); it != elems.end(); it++) - headerfilter_list.insert(*it); - - string mf_type = cfg.getParameter("message_filter", "transparent"); - if (mf_type=="transparent") - messagefilter = Transparent; - else if (mf_type=="whitelist") - messagefilter = Whitelist; - else if (hf_type=="blacklist") - messagefilter = Blacklist; - else { - ERROR("invalid message_filter mode '%s'\n", mf_type.c_str()); - return false; - } - - elems = explode(cfg.getParameter("message_list"), ","); - for (vector::iterator it=elems.begin(); it != elems.end(); it++) - messagefilter_list.insert(*it); - - string sdp_filter = cfg.getParameter("sdp_filter"); - if (sdp_filter=="transparent") { - sdpfilter_enabled = true; - sdpfilter = Transparent; - } else if (sdp_filter=="whitelist") { - sdpfilter_enabled = true; - sdpfilter = Whitelist; - } else if (sdp_filter=="blacklist") { - sdpfilter_enabled = true; - sdpfilter = Blacklist; - } else { - sdpfilter_enabled = false; - } - if (sdpfilter_enabled) { - vector c_elems = explode(cfg.getParameter("sdpfilter_list"), ","); - for (vector::iterator it=c_elems.begin(); it != c_elems.end(); it++) { - string c = *it; - std::transform(c.begin(), c.end(), c.begin(), ::tolower); - sdpfilter_list.insert(c); - } - } - - sst_enabled = cfg.getParameter("enable_session_timer", "no") == "yes"; - use_global_sst_config = !cfg.hasParameter("session_expires"); - - auth_enabled = cfg.getParameter("enable_auth", "no") == "yes"; - auth_credentials.user = cfg.getParameter("auth_user"); - auth_credentials.pwd = cfg.getParameter("auth_pwd"); - - call_timer_enabled = cfg.getParameter("enable_call_timer", "no") == "yes"; - call_timer = cfg.getParameter("call_timer"); - - prepaid_enabled = cfg.getParameter("enable_prepaid", "no") == "yes"; - prepaid_accmodule = cfg.getParameter("prepaid_accmodule"); - prepaid_uuid = cfg.getParameter("prepaid_uuid"); - prepaid_acc_dest = cfg.getParameter("prepaid_acc_dest"); - - // check for acc module if configured statically - if (prepaid_enabled && - (prepaid_accmodule.find('$') == string::npos) && - (NULL == AmPlugIn::instance()->getFactory4Di(prepaid_accmodule))) { - ERROR("prepaid accounting module '%s' used in call profile " - "'%s' is not loaded\n", prepaid_accmodule.c_str(), name.c_str()); - return false; - } - - vector reply_translations_v = - explode(cfg.getParameter("reply_translations"), "|"); - for (vector::iterator it = - reply_translations_v.begin(); it != reply_translations_v.end(); it++) { - // expected: "603=>488 Not acceptable here" - vector trans_components = explode(*it, "=>"); - if (trans_components.size() != 2) { - ERROR("%s: entry '%s' in reply_translations could not be understood.\n", - name.c_str(), it->c_str()); - ERROR("expected 'from_code=>to_code reason'\n"); - return false; - } - - unsigned int from_code, to_code; - if (str2i(trans_components[0], from_code)) { - ERROR("%s: code '%s' in reply_translations not understood.\n", - name.c_str(), trans_components[0].c_str()); - return false; - } - unsigned int s_pos = 0; - string to_reply = trans_components[1]; - while (s_pos < to_reply.length() && to_reply[s_pos] != ' ') - s_pos++; - if (str2i(to_reply.substr(0, s_pos), to_code)) { - ERROR("%s: code '%s' in reply_translations not understood.\n", - name.c_str(), to_reply.substr(0, s_pos).c_str()); - return false; - } - - if (s_pos < to_reply.length()) - s_pos++; - // DBG("got translation %u => %u %s\n", - // from_code, to_code, to_reply.substr(s_pos).c_str()); - reply_translations[from_code] = make_pair(to_code, to_reply.substr(s_pos)); - } - - INFO("SBC: loaded SBC profile '%s':\n", name.c_str()); - - INFO("SBC: RURI = '%s'\n", ruri.c_str()); - INFO("SBC: From = '%s'\n", from.c_str()); - INFO("SBC: To = '%s'\n", to.c_str()); - if (!callid.empty()) { - INFO("SBC: Call-ID = '%s'\n", callid.c_str()); - } - - INFO("SBC: force outbound proxy: %s\n", force_outbound_proxy?"yes":"no"); - INFO("SBC: outbound proxy = '%s'\n", outbound_proxy.c_str()); - if (!next_hop_ip.empty()) { - INFO("SBC: next hop = %s%s\n", next_hop_ip.c_str(), - next_hop_port.empty()? "" : (":"+next_hop_port).c_str()); - } - - INFO("SBC: header filter is %s, %zd items in list\n", - FilterType2String(headerfilter), headerfilter_list.size()); - INFO("SBC: message filter is %s, %zd items in list\n", - FilterType2String(messagefilter), messagefilter_list.size()); - INFO("SBC: SDP filter is %sabled, %s, %zd items in list\n", - sdpfilter_enabled?"en":"dis", FilterType2String(sdpfilter), - sdpfilter_list.size()); - - INFO("SBC: SST %sabled\n", sst_enabled?"en":"dis"); - INFO("SBC: SIP auth %sabled\n", auth_enabled?"en":"dis"); - INFO("SBC: call timer %sabled\n", call_timer_enabled?"en":"dis"); - if (call_timer_enabled) { - INFO("SBC: %s seconds\n", call_timer.c_str()); - } - INFO("SBC: prepaid %sabled\n", prepaid_enabled?"en":"dis"); - if (prepaid_enabled) { - INFO("SBC: acc_module = '%s'\n", prepaid_accmodule.c_str()); - INFO("SBC: uuid = '%s'\n", prepaid_uuid.c_str()); - INFO("SBC: acc_dest = '%s'\n", prepaid_acc_dest.c_str()); - } - if (reply_translations.size()) { - string reply_trans_codes; - for(map >::iterator it= - reply_translations.begin(); it != reply_translations.end(); it++) - reply_trans_codes += int2str(it->first)+", "; - reply_trans_codes.erase(reply_trans_codes.length()-2); - INFO("SBC: reply translation for %s\n", reply_trans_codes.c_str()); - } - - return true; -} SBCFactory::SBCFactory(const string& _app_name) : AmSessionFactory(_app_name) diff --git a/apps/sbc/SBC.h b/apps/sbc/SBC.h index 960c4ab3..a2acbb12 100644 --- a/apps/sbc/SBC.h +++ b/apps/sbc/SBC.h @@ -27,11 +27,11 @@ #define _SBC_H #include "AmB2BSession.h" -#include "ampi/UACAuthAPI.h" #include "AmConfigReader.h" #include "AmUriParser.h" #include "HeaderFilter.h" +#include "SBCCallProfile.h" #include @@ -40,65 +40,6 @@ using std::string; #define SBC_TIMER_ID_CALL_TIMER 1 #define SBC_TIMER_ID_PREPAID_TIMEOUT 2 -struct SBCCallProfile { - - AmConfigReader cfg; - - string ruri; /* updated if set */ - string from; /* updated if set */ - string to; /* updated if set */ - - string callid; - - string outbound_proxy; - bool force_outbound_proxy; - - string next_hop_ip; - string next_hop_port; - unsigned short next_hop_port_i; - - FilterType headerfilter; - set headerfilter_list; - - FilterType messagefilter; - set messagefilter_list; - - bool sdpfilter_enabled; - FilterType sdpfilter; - set sdpfilter_list; - - bool sst_enabled; - bool use_global_sst_config; - - bool auth_enabled; - UACAuthCred auth_credentials; - - bool call_timer_enabled; - string call_timer; - - bool prepaid_enabled; - string prepaid_accmodule; - string prepaid_uuid; - string prepaid_acc_dest; - - map > reply_translations; - - // todo: RTP forwarding mode - // todo: RTP transcoding mode - - SBCCallProfile() - : headerfilter(Transparent), - messagefilter(Transparent), - sdpfilter_enabled(false), - sdpfilter(Transparent), - sst_enabled(false), - auth_enabled(false), - call_timer_enabled(false), - prepaid_enabled(false) - { } - - bool readFromConfiguration(const string& name, const string profile_file_name); -}; class SBCFactory: public AmSessionFactory { diff --git a/apps/sbc/SBCCallProfile.cpp b/apps/sbc/SBCCallProfile.cpp new file mode 100644 index 00000000..a0fd0a8a --- /dev/null +++ b/apps/sbc/SBCCallProfile.cpp @@ -0,0 +1,189 @@ +#include "SBCCallProfile.h" + +#include + +#include "log.h" +#include "AmUtils.h" +#include "AmPlugIn.h" + + +bool SBCCallProfile::readFromConfiguration(const string& name, + const string profile_file_name) { + if (cfg.loadFile(profile_file_name)) { + ERROR("reading SBC call profile from '%s'\n", profile_file_name.c_str()); + return false; + } + + ruri = cfg.getParameter("RURI"); + from = cfg.getParameter("From"); + to = cfg.getParameter("To"); + + callid = cfg.getParameter("Call-ID"); + + force_outbound_proxy = cfg.getParameter("force_outbound_proxy") == "yes"; + outbound_proxy = cfg.getParameter("outbound_proxy"); + + next_hop_ip = cfg.getParameter("next_hop_ip"); + next_hop_port = cfg.getParameter("next_hop_port"); + + string hf_type = cfg.getParameter("header_filter", "transparent"); + if (hf_type=="transparent") + headerfilter = Transparent; + else if (hf_type=="whitelist") + headerfilter = Whitelist; + else if (hf_type=="blacklist") + headerfilter = Blacklist; + else { + ERROR("invalid header_filter mode '%s'\n", hf_type.c_str()); + return false; + } + + vector elems = explode(cfg.getParameter("header_list"), ","); + for (vector::iterator it=elems.begin(); it != elems.end(); it++) + headerfilter_list.insert(*it); + + string mf_type = cfg.getParameter("message_filter", "transparent"); + if (mf_type=="transparent") + messagefilter = Transparent; + else if (mf_type=="whitelist") + messagefilter = Whitelist; + else if (hf_type=="blacklist") + messagefilter = Blacklist; + else { + ERROR("invalid message_filter mode '%s'\n", mf_type.c_str()); + return false; + } + + elems = explode(cfg.getParameter("message_list"), ","); + for (vector::iterator it=elems.begin(); it != elems.end(); it++) + messagefilter_list.insert(*it); + + string sdp_filter = cfg.getParameter("sdp_filter"); + if (sdp_filter=="transparent") { + sdpfilter_enabled = true; + sdpfilter = Transparent; + } else if (sdp_filter=="whitelist") { + sdpfilter_enabled = true; + sdpfilter = Whitelist; + } else if (sdp_filter=="blacklist") { + sdpfilter_enabled = true; + sdpfilter = Blacklist; + } else { + sdpfilter_enabled = false; + } + if (sdpfilter_enabled) { + vector c_elems = explode(cfg.getParameter("sdpfilter_list"), ","); + for (vector::iterator it=c_elems.begin(); it != c_elems.end(); it++) { + string c = *it; + std::transform(c.begin(), c.end(), c.begin(), ::tolower); + sdpfilter_list.insert(c); + } + } + + sst_enabled = cfg.getParameter("enable_session_timer", "no") == "yes"; + use_global_sst_config = !cfg.hasParameter("session_expires"); + + auth_enabled = cfg.getParameter("enable_auth", "no") == "yes"; + auth_credentials.user = cfg.getParameter("auth_user"); + auth_credentials.pwd = cfg.getParameter("auth_pwd"); + + call_timer_enabled = cfg.getParameter("enable_call_timer", "no") == "yes"; + call_timer = cfg.getParameter("call_timer"); + + prepaid_enabled = cfg.getParameter("enable_prepaid", "no") == "yes"; + prepaid_accmodule = cfg.getParameter("prepaid_accmodule"); + prepaid_uuid = cfg.getParameter("prepaid_uuid"); + prepaid_acc_dest = cfg.getParameter("prepaid_acc_dest"); + + // check for acc module if configured statically + if (prepaid_enabled && + (prepaid_accmodule.find('$') == string::npos) && + (NULL == AmPlugIn::instance()->getFactory4Di(prepaid_accmodule))) { + ERROR("prepaid accounting module '%s' used in call profile " + "'%s' is not loaded\n", prepaid_accmodule.c_str(), name.c_str()); + return false; + } + + vector reply_translations_v = + explode(cfg.getParameter("reply_translations"), "|"); + for (vector::iterator it = + reply_translations_v.begin(); it != reply_translations_v.end(); it++) { + // expected: "603=>488 Not acceptable here" + vector trans_components = explode(*it, "=>"); + if (trans_components.size() != 2) { + ERROR("%s: entry '%s' in reply_translations could not be understood.\n", + name.c_str(), it->c_str()); + ERROR("expected 'from_code=>to_code reason'\n"); + return false; + } + + unsigned int from_code, to_code; + if (str2i(trans_components[0], from_code)) { + ERROR("%s: code '%s' in reply_translations not understood.\n", + name.c_str(), trans_components[0].c_str()); + return false; + } + unsigned int s_pos = 0; + string to_reply = trans_components[1]; + while (s_pos < to_reply.length() && to_reply[s_pos] != ' ') + s_pos++; + if (str2i(to_reply.substr(0, s_pos), to_code)) { + ERROR("%s: code '%s' in reply_translations not understood.\n", + name.c_str(), to_reply.substr(0, s_pos).c_str()); + return false; + } + + if (s_pos < to_reply.length()) + s_pos++; + // DBG("got translation %u => %u %s\n", + // from_code, to_code, to_reply.substr(s_pos).c_str()); + reply_translations[from_code] = make_pair(to_code, to_reply.substr(s_pos)); + } + + INFO("SBC: loaded SBC profile '%s':\n", name.c_str()); + + INFO("SBC: RURI = '%s'\n", ruri.c_str()); + INFO("SBC: From = '%s'\n", from.c_str()); + INFO("SBC: To = '%s'\n", to.c_str()); + if (!callid.empty()) { + INFO("SBC: Call-ID = '%s'\n", callid.c_str()); + } + + INFO("SBC: force outbound proxy: %s\n", force_outbound_proxy?"yes":"no"); + INFO("SBC: outbound proxy = '%s'\n", outbound_proxy.c_str()); + if (!next_hop_ip.empty()) { + INFO("SBC: next hop = %s%s\n", next_hop_ip.c_str(), + next_hop_port.empty()? "" : (":"+next_hop_port).c_str()); + } + + INFO("SBC: header filter is %s, %zd items in list\n", + FilterType2String(headerfilter), headerfilter_list.size()); + INFO("SBC: message filter is %s, %zd items in list\n", + FilterType2String(messagefilter), messagefilter_list.size()); + INFO("SBC: SDP filter is %sabled, %s, %zd items in list\n", + sdpfilter_enabled?"en":"dis", FilterType2String(sdpfilter), + sdpfilter_list.size()); + + INFO("SBC: SST %sabled\n", sst_enabled?"en":"dis"); + INFO("SBC: SIP auth %sabled\n", auth_enabled?"en":"dis"); + INFO("SBC: call timer %sabled\n", call_timer_enabled?"en":"dis"); + if (call_timer_enabled) { + INFO("SBC: %s seconds\n", call_timer.c_str()); + } + INFO("SBC: prepaid %sabled\n", prepaid_enabled?"en":"dis"); + if (prepaid_enabled) { + INFO("SBC: acc_module = '%s'\n", prepaid_accmodule.c_str()); + INFO("SBC: uuid = '%s'\n", prepaid_uuid.c_str()); + INFO("SBC: acc_dest = '%s'\n", prepaid_acc_dest.c_str()); + } + if (reply_translations.size()) { + string reply_trans_codes; + for(map >::iterator it= + reply_translations.begin(); it != reply_translations.end(); it++) + reply_trans_codes += int2str(it->first)+", "; + reply_trans_codes.erase(reply_trans_codes.length()-2); + INFO("SBC: reply translation for %s\n", reply_trans_codes.c_str()); + } + + return true; +} diff --git a/apps/sbc/SBCCallProfile.h b/apps/sbc/SBCCallProfile.h new file mode 100644 index 00000000..f2f59f82 --- /dev/null +++ b/apps/sbc/SBCCallProfile.h @@ -0,0 +1,77 @@ + +#ifndef _SBCCallProfile_h +#define _SBCCallProfile_h + +#include "AmConfigReader.h" +#include "HeaderFilter.h" +#include "ampi/UACAuthAPI.h" + +#include +#include +#include + +using std::string; +using std::map; +using std::set; + +struct SBCCallProfile { + + AmConfigReader cfg; + + string ruri; /* updated if set */ + string from; /* updated if set */ + string to; /* updated if set */ + + string callid; + + string outbound_proxy; + bool force_outbound_proxy; + + string next_hop_ip; + string next_hop_port; + unsigned short next_hop_port_i; + + FilterType headerfilter; + set headerfilter_list; + + FilterType messagefilter; + set messagefilter_list; + + bool sdpfilter_enabled; + FilterType sdpfilter; + set sdpfilter_list; + + bool sst_enabled; + bool use_global_sst_config; + + bool auth_enabled; + UACAuthCred auth_credentials; + + bool call_timer_enabled; + string call_timer; + + bool prepaid_enabled; + string prepaid_accmodule; + string prepaid_uuid; + string prepaid_acc_dest; + + map > reply_translations; + + // todo: RTP forwarding mode + // todo: RTP transcoding mode + + SBCCallProfile() + : headerfilter(Transparent), + messagefilter(Transparent), + sdpfilter_enabled(false), + sdpfilter(Transparent), + sst_enabled(false), + auth_enabled(false), + call_timer_enabled(false), + prepaid_enabled(false) + { } + + bool readFromConfiguration(const string& name, const string profile_file_name); +}; + +#endif // _SBCCallProfile_h diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index a10f3478..1f6f9302 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -743,7 +743,7 @@ int AmSipDialog::transfer(const string& target) string r_set; if(!route.empty()){ - hdrs = PARAM_HDR ": " "Transfer-RR=\"" + route + "\""; + hdrs = PARAM_HDR ": " "Transfer-RR=\"" + route + "\""+CRLF; } int ret = tmp_d.sendRequest("REFER","","",hdrs); diff --git a/doc/Readme.pin_collect.txt b/doc/Readme.pin_collect.txt index 446b90d3..8ce7ceb1 100644 --- a/doc/Readme.pin_collect.txt +++ b/doc/Readme.pin_collect.txt @@ -10,11 +10,14 @@ Authentication Modes: XMLRPC : Authenticate against an XMLRPC server (python example server in test/authserver.py - REFER : the transfer request (REFER) sent out has as user part of + REFER : The Refer-to of the REFER sent in-dialog contains +@domain, + such that this pin can be checked by an upstream app server or + proxy and acted upon (e.g. sent to the proper conference room). + + TRANSFER : the transfer request (Transfer REFER) sent out has as user part of the URI the original user part, a plus sign, and the entered PIN. The PIN can thus be verified by the proxy handling the - transfer REFER. - + transfer REFER. See below for an explanation. "Transfer" REFER: The "Transfer REFER" is a proprietary REFER call flow which transfers a diff --git a/doc/Readme.sbc.txt b/doc/Readme.sbc.txt index 0728e116..088790de 100644 --- a/doc/Readme.sbc.txt +++ b/doc/Readme.sbc.txt @@ -173,7 +173,7 @@ set to transparent, the SDP is parsed and reconstructed (SDP sanity check). Codecs may be filtered out by their payload names in whitelist or blacklist modes. The payload names in the list are case-insensitive (PCMU==pcmu). -Reply code translations +Response code translations ----------------------- Response codes and reasons may be translated, e.g. if some 6xx class replies need to be changed to 4xx class replies. @@ -256,6 +256,7 @@ Example profiles call_timer - call timer (obsoletes call_timer app) prepaid - prepaid accounting (obsoletes sw_prepaid_sip app) codecfilter - let only some low bitrate codecs pass + replytranslate - swap 603 and 488 response code in replies Dependencies ------------ @@ -266,7 +267,7 @@ Roadmap ------- x header filter (whitelist or blacklist) x message filter (whitelist or blacklist) -- SDP filter (reconstructed SDP) +x SDP filter (reconstructed SDP) x remote URI update (host / user / host/user) x From update (displayname / host / host/user) x To update (displayname / host / host/user)