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:
parent
a95f965a0c
commit
5432a414aa
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue