Added support to enable REFER handling per call leg. Added configurable support (default:disabled) to send a call.update message with operation=transfer before internal handling on REFER.

git-svn-id: http://yate.null.ro/svn/yate/trunk@6527 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2021-11-15 14:19:43 +00:00
parent a95f965a0c
commit 5432a414aa
2 changed files with 175 additions and 67 deletions

View File

@ -133,9 +133,20 @@
; realm: string: Authentication realm to offer in authentication requests ; realm: string: Authentication realm to offer in authentication requests
;realm=Yate ;realm=Yate
; transfer: bool: Allow handling the REFER message to perform transfers ; transfer: bool/keyword: Allow handling the REFER message to perform transfers
; 'chan-disable': Enable global transfer flag (advertise REFER is supported)
; REFER handling is disabled in call legs
; REFER handling MUST be explicitly enabled per call leg when routing
; Parameter: 'enable_refer' for outgoing leg, 'ienable_refer' for incoming leg
;transfer=enable in server mode, disable in client mode ;transfer=enable in server mode, disable in client mode
; refer_update: boolean: Emit a call.update with 'operation'='transfer' when handling REFER
; If enabled the message MUST succeed (must be handled and return value not '-' or 'error')
; REFER will fail if call.update fails
; The handler may set a 'transferred' parameter to boolean 'true' to stop further REFER processing
; and notify success to implicit subscription
;refer_update=no
; registrar: bool: Allow the SIP module to receive registration requests ; registrar: bool: Allow the SIP module to receive registration requests
; OBSOLETE - please use "enable" in section [registar] ; OBSOLETE - please use "enable" in section [registar]
;registrar=enable in server mode, disable in client mode ;registrar=enable in server mode, disable in client mode

View File

@ -897,11 +897,22 @@ class YateSIPRefer : public Thread
public: public:
YateSIPRefer(const String& transferorID, const String& transferredID, YateSIPRefer(const String& transferorID, const String& transferredID,
Driver* transferredDrv, Message* msg, SIPMessage* sipNotify, Driver* transferredDrv, Message* msg, SIPMessage* sipNotify,
SIPTransaction* transaction); SIPTransaction* transaction, Message* validate);
virtual void run(void); virtual void run(void);
virtual void cleanup(void) virtual void cleanup(void)
{ release(true); } { release(true); }
private: private:
inline void setSuccess() {
m_rspCode = 202;
m_notifyCode = 200;
}
inline bool setFailure(int code) {
m_rspCode = m_notifyCode = code;
return false;
}
// Check success after message dispatch
// Return true if succeeded. Set response on failure
bool checkSuccess(const Message& msg, bool ok, void* chan);
// Respond the transaction and deref() it // Respond the transaction and deref() it
void setTrResponse(int code); void setTrResponse(int code);
// Set transaction response. Send the notification message. Notify the // Set transaction response. Send the notification message. Notify the
@ -916,6 +927,7 @@ private:
int m_notifyCode; // The result to send with NOTIFY int m_notifyCode; // The result to send with NOTIFY
SIPTransaction* m_transaction; // The transaction to respond to SIPTransaction* m_transaction; // The transaction to respond to
int m_rspCode; // The transaction response int m_rspCode; // The transaction response
Message* m_validate; // Message to dispatch before further handling
}; };
class YateSIPRegister : public Thread class YateSIPRegister : public Thread
@ -1084,6 +1096,16 @@ private:
m_silent = true; m_silent = true;
clearTransaction(); clearTransaction();
} }
inline void setRefer(const NamedList& params) {
if (isIncoming()) {
m_refer = params.getBoolValue(YSTRING("ienable_refer"),m_refer);
m_referUpdate = m_refer && params.getBoolValue(YSTRING("irefer_update"),m_referUpdate);
}
else {
m_refer = params.getBoolValue(YSTRING("enable_refer"),m_refer);
m_referUpdate = m_refer && params.getBoolValue(YSTRING("refer_update"),m_referUpdate);
}
}
SIPTransaction* m_tr; SIPTransaction* m_tr;
SIPTransaction* m_tr2; SIPTransaction* m_tr2;
@ -1112,8 +1134,9 @@ private:
bool m_missingAllowInfoDefVal; // Default INFO support if Allow header is missing bool m_missingAllowInfoDefVal; // Default INFO support if Allow header is missing
DtmfMethods m_dtmfMethods; DtmfMethods m_dtmfMethods;
bool m_honorDtmfDetect; bool m_honorDtmfDetect;
// REFER already running bool m_referring; // REFER already running
bool m_referring; bool m_refer; // REFER enabled
bool m_referUpdate; // Send call.update on REFER
// reINVITE requested or in progress // reINVITE requested or in progress
int m_reInviting; int m_reInviting;
// sequence number of last transmitted PRACK // sequence number of last transmitted PRACK
@ -1171,7 +1194,7 @@ public:
YateSIPConnection* findCall(const String& callid, bool incRef = false); YateSIPConnection* findCall(const String& callid, bool incRef = false);
YateSIPConnection* findDialog(const SIPDialog& dialog, bool incRef = false); YateSIPConnection* findDialog(const SIPDialog& dialog, bool incRef = false);
YateSIPConnection* findDialog(const String& dialog, const String& fromTag, YateSIPConnection* findDialog(const String& dialog, const String& fromTag,
const String& toTag, bool incRef = false); const String& toTag, bool incRef = false, RefPointer<YateSIPConnection>* conn = 0);
YateSIPLine* findLine(const String& line) const; YateSIPLine* findLine(const String& line) const;
YateSIPLine* findLine(const String& addr, int port, const String& user = String::empty(), YateSIPLine* findLine(const String& addr, int port, const String& user = String::empty(),
SIPParty* party = 0); SIPParty* party = 0);
@ -1260,6 +1283,8 @@ static bool s_1xx_formats = true;
static bool s_sdp_implicit = true; static bool s_sdp_implicit = true;
static bool s_rtp_preserve = false; static bool s_rtp_preserve = false;
static bool s_enable_transfer = false; static bool s_enable_transfer = false;
static bool s_referChan = false; // Handle REFER in channel only
static bool s_refer_update = false; // Send call.update when handling REFER
static bool s_enable_options = false; static bool s_enable_options = false;
static bool s_enable_message = false; static bool s_enable_message = false;
static bool s_enable_register = false; static bool s_enable_register = false;
@ -6033,11 +6058,12 @@ bool YateSIPEndPoint::generic(const SIPMessage* message, SIPTransaction* t, cons
// sipNotify: already populated SIPMessage("NOTIFY") // sipNotify: already populated SIPMessage("NOTIFY")
YateSIPRefer::YateSIPRefer(const String& transferorID, const String& transferredID, YateSIPRefer::YateSIPRefer(const String& transferorID, const String& transferredID,
Driver* transferredDrv, Message* msg, SIPMessage* sipNotify, Driver* transferredDrv, Message* msg, SIPMessage* sipNotify,
SIPTransaction* transaction) SIPTransaction* transaction, Message* validate)
: Thread("YSIP Transfer"), : Thread("YSIP Transfer"),
m_transferorID(transferorID), m_transferredID(transferredID), m_transferorID(transferorID), m_transferredID(transferredID),
m_transferredDrv(transferredDrv), m_msg(msg), m_sipNotify(sipNotify), m_transferredDrv(transferredDrv), m_msg(msg), m_sipNotify(sipNotify),
m_notifyCode(200), m_transaction(0), m_rspCode(500) m_notifyCode(200), m_transaction(0), m_rspCode(500),
m_validate(validate)
{ {
if (transaction && transaction->ref()) if (transaction && transaction->ref())
m_transaction = transaction; m_transaction = transaction;
@ -6058,29 +6084,55 @@ void YateSIPRefer::run()
// Use a while() to break to the end // Use a while() to break to the end
while (m_transferredDrv && m_msg) { while (m_transferredDrv && m_msg) {
RefPointer<YateSIPConnection> attendedConn;
String* from = 0;
String* to = 0;
if (attended) {
from = m_msg->getParam(YSTRING("transfer_fromtag"));
to = m_msg->getParam(YSTRING("transfer_totag"));
if (!(null(from) && null(to)))
plugin.findDialog(*attended,*from,*to,false,&attendedConn);
}
if (m_validate) {
if (attended) {
if (attendedConn) {
m_validate->addParam("attended_id",attendedConn->id());
RefPointer<CallEndpoint> peer = YOBJECT(CallEndpoint,attendedConn->getPeer());
if (peer)
m_validate->addParam("attended_peerid",peer->id());
}
}
bool ok = Engine::dispatch(m_validate);
if (!checkSuccess(*m_validate,ok,plugin.find(m_transferorID)))
break;
// Done ?
if (m_validate->getBoolValue(YSTRING("transferred"))) {
// TODO: Check if request was sent to a remote party
// We may want to wait for notify ...
setSuccess();
break;
}
}
// Attended transfer: check if the requested channel is owned by our plugin // Attended transfer: check if the requested channel is owned by our plugin
// NOTE: Remove the whole 'if' when a routing module will be able to route // NOTE: Remove the whole 'if' when a routing module will be able to route
// attended transfer requests // attended transfer requests
if (attended) { if (attended) {
String* from = m_msg->getParam(YSTRING("transfer_fromtag")); if (attendedConn) {
String* to = m_msg->getParam(YSTRING("transfer_totag"));
if (null(from) || null(to)) {
m_rspCode = m_notifyCode = 487; // Request Terminated
break;
}
YateSIPConnection* conn = plugin.findDialog(*attended,*from,*to,true);
if (conn) {
m_transferredDrv->lock(); m_transferredDrv->lock();
RefPointer<Channel> chan = m_transferredDrv->find(m_transferredID); RefPointer<Channel> chan = m_transferredDrv->find(m_transferredID);
m_transferredDrv->unlock(); m_transferredDrv->unlock();
if (chan && conn->getPeer() && DDebug(&plugin,DebugAll,"%s conn=(%p '%s') found transferred (%p '%s') [%p]",
chan->connect(conn->getPeer(),m_msg->getValue(YSTRING("reason")))) { name(),(void*)attendedConn,attendedConn->id().c_str(),
m_rspCode = 202; (void*)chan,(chan ? chan->id().safe() : ""),this);
m_notifyCode = 200; if (chan && attendedConn->getPeer() &&
} chan->connect(attendedConn->getPeer(),m_msg->getValue(YSTRING("reason"))))
setSuccess();
else else
m_rspCode = m_notifyCode = 487; // Request Terminated setFailure(487);
TelEngine::destruct(conn); break;
}
if (null(from) || null(to)) {
setFailure(487);
break; break;
} }
// Not ours // Not ours
@ -6093,47 +6145,50 @@ void YateSIPRefer::run()
m_transferredDrv->lock(); m_transferredDrv->lock();
RefPointer<Channel> chan = m_transferredDrv->find(m_transferredID); RefPointer<Channel> chan = m_transferredDrv->find(m_transferredID);
m_transferredDrv->unlock(); m_transferredDrv->unlock();
if (!(ok && chan)) { if (!checkSuccess(*m_msg,ok,chan))
#ifdef DEBUG
if (ok)
Debug(&plugin,DebugAll,"%s(%s). Connection vanished while routing! [%p]",
name(),m_transferorID.c_str(),this);
else
Debug(&plugin,DebugAll,"%s(%s). 'call.route' failed [%p]",
name(),m_transferorID.c_str(),this);
#endif
m_rspCode = m_notifyCode = (ok ? 487 : 481);
break; break;
} DDebug(&plugin,DebugAll,"%s(%s). Call succesfully routed [%p]",
name(),m_transferorID.c_str(),this);
m_msg->userData(chan); m_msg->userData(chan);
if ((m_msg->retValue() == "-") || (m_msg->retValue() == YSTRING("error"))) *m_msg = "call.execute";
m_rspCode = m_notifyCode = 603; // Decline m_msg->setParam(YSTRING("callto"),m_msg->retValue());
else if (m_msg->getIntValue(YSTRING("antiloop"),1) <= 0) m_msg->clearParam(YSTRING("error"));
m_rspCode = m_notifyCode = 482; // Loop Detected m_msg->retValue().clear();
else { if (Engine::dispatch(m_msg)) {
DDebug(&plugin,DebugAll,"%s(%s). Call succesfully routed [%p]", DDebug(&plugin,DebugAll,"%s(%s). 'call.execute' succeeded [%p]",
name(),m_transferorID.c_str(),this); name(),m_transferorID.c_str(),this);
*m_msg = "call.execute"; setSuccess();
m_msg->setParam("callto",m_msg->retValue()); }
m_msg->clearParam(YSTRING("error")); else {
m_msg->retValue().clear(); DDebug(&plugin,DebugAll,"%s(%s). 'call.execute' failed [%p]",
if (Engine::dispatch(m_msg)) { name(),m_transferorID.c_str(),this);
DDebug(&plugin,DebugAll,"%s(%s). 'call.execute' succeeded [%p]", setFailure(603); // Decline
name(),m_transferorID.c_str(),this);
m_rspCode = 202;
m_notifyCode = 200;
}
else {
DDebug(&plugin,DebugAll,"%s(%s). 'call.execute' failed [%p]",
name(),m_transferorID.c_str(),this);
m_rspCode = m_notifyCode = 603; // Decline
}
} }
break; break;
} }
release(); release();
} }
bool YateSIPRefer::checkSuccess(const Message& msg, bool ok, void* chan)
{
if (!(ok && chan)) {
#ifdef DEBUG
if (ok)
Debug(&plugin,DebugAll,"%s(%s). Connection vanished while %s [%p]",
name(),m_transferorID.c_str(),msg.c_str(),this);
else
Debug(&plugin,DebugAll,"%s(%s). %s failed [%p]",
name(),m_transferorID.c_str(),msg.c_str(),this);
#endif
return setFailure(ok ? 487 : 481);
}
if ((msg.retValue() == "-") || (msg.retValue() == YSTRING("error")))
return setFailure(msg.getIntValue(YSTRING("code"),dict_errors,603)); // Decline
if (msg.getIntValue(YSTRING("antiloop"),1) <= 0)
return setFailure(482); // Loop Detected
return true;
}
// Respond the transaction and deref() it // Respond the transaction and deref() it
void YateSIPRefer::setTrResponse(int code) void YateSIPRefer::setTrResponse(int code)
{ {
@ -6152,6 +6207,7 @@ void YateSIPRefer::release(bool fromCleanup)
{ {
setTrResponse(m_rspCode); setTrResponse(m_rspCode);
TelEngine::destruct(m_msg); TelEngine::destruct(m_msg);
TelEngine::destruct(m_validate);
// Set NOTIFY response and send it (only if the transaction was accepted) // Set NOTIFY response and send it (only if the transaction was accepted)
if (m_sipNotify) { if (m_sipNotify) {
if (m_rspCode < 300 && plugin.ep() && plugin.ep()->engine()) { if (m_rspCode < 300 && plugin.ep() && plugin.ep()->engine()) {
@ -6189,7 +6245,8 @@ YateSIPConnection::YateSIPConnection(SIPEvent* ev, SIPTransaction* tr)
m_authBye(true), m_autoChangeParty(tr->getEngine()->autoChangeParty()), m_authBye(true), m_autoChangeParty(tr->getEngine()->autoChangeParty()),
m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal), m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal),
m_honorDtmfDetect(s_honorDtmfDetect), m_honorDtmfDetect(s_honorDtmfDetect),
m_referring(false), m_reInviting(ReinviteNone), m_lastRseq(0), m_referring(false), m_refer(s_referChan), m_referUpdate(s_refer_update),
m_reInviting(ReinviteNone), m_lastRseq(0),
m_revert(""), m_silent(false), m_stopOCall(false), m_traceId(tr->traceId()) m_revert(""), m_silent(false), m_stopOCall(false), m_traceId(tr->traceId())
{ {
m_ipv6 = s_ipv6; m_ipv6 = s_ipv6;
@ -6390,13 +6447,15 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char
m_authBye(false), m_autoChangeParty(true), m_authBye(false), m_autoChangeParty(true),
m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal), m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal),
m_honorDtmfDetect(s_honorDtmfDetect), m_honorDtmfDetect(s_honorDtmfDetect),
m_referring(false), m_reInviting(ReinviteNone), m_lastRseq(0), m_referring(false), m_refer(s_referChan), m_referUpdate(s_refer_update),
m_reInviting(ReinviteNone), m_lastRseq(0),
m_revert(""), m_silent(false), m_stopOCall(msg.getBoolValue(YSTRING("stop_call"))), m_revert(""), m_silent(false), m_stopOCall(msg.getBoolValue(YSTRING("stop_call"))),
m_traceId(msg.getValue(YSTRING("trace_id"))) m_traceId(msg.getValue(YSTRING("trace_id")))
{ {
TraceDebug(m_traceId,this,DebugAll,"YateSIPConnection::YateSIPConnection(%p,'%s') [%p]", TraceDebug(m_traceId,this,DebugAll,"YateSIPConnection::YateSIPConnection(%p,'%s') [%p]",
&msg,uri.c_str(),this); &msg,uri.c_str(),this);
setChanParams(msg); setChanParams(msg);
setRefer(msg);
m_autoChangeParty = msg.getBoolValue(YSTRING("oautochangeparty"), m_autoChangeParty = msg.getBoolValue(YSTRING("oautochangeparty"),
plugin.ep()->engine()->autoChangeParty()); plugin.ep()->engine()->autoChangeParty());
m_line = msg.getValue(YSTRING("line")); m_line = msg.getValue(YSTRING("line"));
@ -7762,6 +7821,10 @@ bool YateSIPConnection::doInfo(SIPTransaction* t)
void YateSIPConnection::doRefer(SIPTransaction* t) void YateSIPConnection::doRefer(SIPTransaction* t)
{ {
if (!m_refer) {
t->setResponse(603);
return;
}
if (m_authBye && !checkUser(t)) if (m_authBye && !checkUser(t))
return; return;
DDebug(this,DebugAll,"doRefer(%p) [%p]",t,this); DDebug(this,DebugAll,"doRefer(%p) [%p]",t,this);
@ -7851,15 +7914,30 @@ void YateSIPConnection::doRefer(SIPTransaction* t)
Message* msg = 0; Message* msg = 0;
SIPMessage* sipNotify = 0; SIPMessage* sipNotify = 0;
Channel* ch = YOBJECT(Channel,getPeer()); RefPointer<Channel> ch = YOBJECT(Channel,getPeer());
if (ch && ch->driver() && if (ch && !ch->driver())
initTransfer(msg,sipNotify,t->initialMessage(),refHdr,uri,replaces)) { ch = 0;
(new YateSIPRefer(id(),ch->id(),ch->driver(),msg,sipNotify,t))->startup(); if (!(ch && initTransfer(msg,sipNotify,t->initialMessage(),refHdr,uri,replaces))) {
DDebug(this,DebugAll,"doRefer(%p). Transfer init failed%s [%p]",
t,(ch ? "" : ": no peer or peer has no driver"),this);
t->setResponse(503); // Service Unavailable
m_referring = false;
ch = 0;
return; return;
} }
DDebug(this,DebugAll,"doRefer(%p). No peer or peer has no driver [%p]",t,this); Message* upd = 0;
t->setResponse(503); // Service Unavailable if (m_referUpdate) {
m_referring = false; upd = message("call.update");
upd->setParam(YSTRING("operation"),"transfer");
upd->copyParams(*msg,"transfer_callid,transfer_fromtag,transfer_totag,diverter,divertername");
const SIPMessage& refer = *(t->initialMessage());
copySipHeaders(*upd,refer,false,
static_cast<const YateSIPEngine*>(t->getEngine())->foreignAuth(),s_initialHeaders);
doDecodeIsupBody(&plugin,*upd,refer.body);
copySipBody(*upd,refer);
}
(new YateSIPRefer(id(),ch->id(),ch->driver(),msg,sipNotify,t,upd))->startup();
ch = 0;
} }
void YateSIPConnection::doMessage(SIPTransaction* t) void YateSIPConnection::doMessage(SIPTransaction* t)
@ -8086,6 +8164,12 @@ bool YateSIPConnection::msgUpdate(Message& msg)
Lock lock(driver()); Lock lock(driver());
if (m_hungup) if (m_hungup)
return false; return false;
if (*oper == YSTRING("transfer")) {
// TODO: Forward REFER.
// Build Refer-To: identify requested chan, use its call id and from/to tag instead of requested
Debug(this,DebugNote,"Update 'transfer' not implemented [%p]",this);
return false;
}
if (*oper == YSTRING("request")) { if (*oper == YSTRING("request")) {
if (m_tr || m_tr2) { if (m_tr || m_tr2) {
DDebug(this,DebugWarn,"Update request rejected, pending:%s%s [%p]", DDebug(this,DebugWarn,"Update request rejected, pending:%s%s [%p]",
@ -8365,6 +8449,7 @@ void YateSIPConnection::callAccept(Message& msg)
if (m_tr && !infoAllowed(m_tr->initialMessage())) if (m_tr && !infoAllowed(m_tr->initialMessage()))
m_dtmfMethods.reset(DtmfMethods::Info); m_dtmfMethods.reset(DtmfMethods::Info);
} }
setRefer(msg);
Channel::callAccept(msg); Channel::callAccept(msg);
if ((m_reInviting == ReinviteNone) && !m_rtpForward && !isAnswered() && if ((m_reInviting == ReinviteNone) && !m_rtpForward && !isAnswered() &&
@ -8550,7 +8635,6 @@ bool YateSIPConnection::initTransfer(Message*& msg, SIPMessage*& sipNotify,
// we won't need it if the transfer fails // we won't need it if the transfer fails
// Set notify party from received REFER? // Set notify party from received REFER?
// Remember: createDlgMsg() sets the party from channel's party // Remember: createDlgMsg() sets the party from channel's party
TraceDebug(m_traceId,this,DebugStub,"initTransfer. Possible incomplete NOTIFY party creation [%p]",this);
if (co) { if (co) {
tmp = *co; tmp = *co;
static const Regexp r("^[^<]*<\\([^>]*\\)>.*$"); static const Regexp r("^[^<]*<\\([^>]*\\)>.*$");
@ -9263,15 +9347,19 @@ YateSIPConnection* SIPDriver::findDialog(const SIPDialog& dialog, bool incRef)
} }
YateSIPConnection* SIPDriver::findDialog(const String& dialog, const String& fromTag, YateSIPConnection* SIPDriver::findDialog(const String& dialog, const String& fromTag,
const String& toTag, bool incRef) const String& toTag, bool incRef, RefPointer<YateSIPConnection>* conn)
{ {
XDebug(this,DebugAll,"SIPDriver finding dialog '%s' fromTag='%s' toTag='%s'", XDebug(this,DebugAll,"SIPDriver finding dialog '%s' fromTag='%s' toTag='%s'",
dialog.c_str(),fromTag.c_str(),toTag.c_str()); dialog.c_str(),fromTag.c_str(),toTag.c_str());
Lock mylock(this); Lock mylock(this);
for (ObjList* o = channels().skipNull(); o; o = o->skipNext()) { for (ObjList* o = channels().skipNull(); o; o = o->skipNext()) {
YateSIPConnection* c = static_cast<YateSIPConnection*>(o->get()); YateSIPConnection* c = static_cast<YateSIPConnection*>(o->get());
if (c->isDialog(dialog,fromTag,toTag)) if (!c->isDialog(dialog,fromTag,toTag))
continue;
if (!conn)
return (incRef ? c->ref() : c->alive()) ? c : 0; return (incRef ? c->ref() : c->alive()) ? c : 0;
*conn = c;
return *conn;
} }
return 0; return 0;
} }
@ -9483,7 +9571,9 @@ void SIPDriver::initialize()
s_cfg = Engine::configFile("ysipchan"); s_cfg = Engine::configFile("ysipchan");
s_globalMutex.lock(); s_globalMutex.lock();
s_cfg.load(); s_cfg.load();
NamedList empty("");
NamedList* general = s_cfg.getSection("general"); NamedList* general = s_cfg.getSection("general");
NamedList& gen = general ? *general : empty;
TelEngine::destruct(s_authCopyHeader); TelEngine::destruct(s_authCopyHeader);
if (general) { if (general) {
String* dtmfMethods = general->getParam("dtmfmethods"); String* dtmfMethods = general->getParam("dtmfmethods");
@ -9539,7 +9629,14 @@ void SIPDriver::initialize()
s_defEncoding = s_cfg.getIntValue("general","body_encoding",SipHandler::s_bodyEnc,SipHandler::BodyBase64); s_defEncoding = s_cfg.getIntValue("general","body_encoding",SipHandler::s_bodyEnc,SipHandler::BodyBase64);
s_gen_async = s_cfg.getBoolValue("general","async_generic",true); s_gen_async = s_cfg.getBoolValue("general","async_generic",true);
s_sipt_isup = s_cfg.getBoolValue("sip-t","isup",false); s_sipt_isup = s_cfg.getBoolValue("sip-t","isup",false);
s_enable_transfer = s_cfg.getBoolValue("general","transfer",!Engine::clientMode()); const String& transfer = gen[YSTRING("transfer")];
if (transfer == YSTRING("chan-disable")) {
s_enable_transfer = true;
s_referChan = false;
}
else
s_referChan = s_enable_transfer = transfer.toBoolean(!Engine::clientMode());
s_refer_update = gen.getBoolValue(YSTRING("refer_update"));
s_enable_options = s_cfg.getBoolValue("options","enable", s_enable_options = s_cfg.getBoolValue("options","enable",
s_cfg.getBoolValue("general","options",true)); s_cfg.getBoolValue("general","options",true));
s_enable_message = s_cfg.getBoolValue("message","enable",false); s_enable_message = s_cfg.getBoolValue("message","enable",false);