[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "transfer-improvements" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon Jul 25 17:56:56 CDT 2011


branch "transfer-improvements" has been updated
       via  f2ef25b81ccb00782d921aa14e3e891f4744dd09 (commit)
       via  9993515f2d29a0808654f52bf981e488b2be42aa (commit)
       via  c4e9de5a78ef48217e9104205fe875f400c9f553 (commit)
       via  1ed569652e73a9ed71484baee8f0e1ac972aa68f (commit)
       via  fcb2a102e93641937a78e8b22b01b1b677c429ca (commit)
       via  df60142aabdb696d31e49ba5c3047e1bbd25e7ff (commit)
       via  822fc2955d56d229e8fffa38fc6209c6228ffb15 (commit)
       via  ca24fcab3d34ddf6a69bc18fe0a769339b2756fe (commit)
       via  e28f2fa146b52be92b5df7640ab6f8df24cfd7c5 (commit)
       via  442b31018e098f0a9135da0f82d76d92d2ae9286 (commit)
       via  b09352f0fe360add36cc1977b6215781a33d42e1 (commit)
       via  25b59a8ab75c40d5f80727357e9d939e827ab150 (commit)
       via  fcac39e702d0f487a386d26ed8277ce6902ce607 (commit)
       via  da14216b9dc0c8f37efd5d3a1a4d5591245b139d (commit)
       via  d5456aa0f5700ef9d53821e9695411fa2e0801fd (commit)
       via  e2a3f36be58aaf8457b09f2aadd7d4e897176532 (commit)
       via  b18bdac4a5042928247a0a708b7e62fe4cec801f (commit)
       via  2b0ba42f2e557f5f5f3e5dba3b41f87a0937d8db (commit)
       via  c1891fda67849e50c553ccbba326ab431c8fa293 (commit)
       via  abc64b8ab827c6e1a59a6440f0c82ed4662cd8cb (commit)
       via  5cc1decf6fbf407a4d477f74f7832af9bf1df66d (commit)
       via  f3ac2038009f50b1ff84d203999dc79f2a0aea56 (commit)
       via  e19711fb128b2538bd793dd6993fa1a89a99909e (commit)
       via  4f79a16c7cb94d0b6aa5ed13c3bfdc81fc764641 (commit)
       via  6577d75e59c8b2f4241103f48fd114da433c8597 (commit)
       via  26ec91cf1ad7ae654b38a57e355d85cd7b2a6495 (commit)
       via  c36e88cc66b3a9f5e5cce710df4359e88079d9d9 (commit)
       via  b41a0dc88850f05a29d0adbf62016e22e625a26e (commit)
       via  1b8c6f710bab05f5864611477838d6b56c673eb5 (commit)
       via  e528d7be81f34ac1789b74ad7415de949a1c19ed (commit)
       via  b61e242edd548a82eb5a492c7ffb16835746ceaa (commit)
       via  32c65526dd56d0bc7e03148dfd407bfa40423fff (commit)
       via  f256218dea09a6d6e3e177b35d333b6881bc6ed7 (commit)
       via  ba77572c9c5e5d5abdff517a1f4e144440d5906f (commit)
       via  bd53a89af2c3104984d46c118e2b7b158155f25c (commit)
       via  c58ab8b3d3623ccd57d63077f902eda632faaf7d (commit)
       via  59ccbfc493c091ebfe6d2a71d61026d9abf5a77c (commit)
       via  ef373b282be4a218a92e9981fc0c3163c181603b (commit)
       via  0a84ba53e4041c3d0afcab7caf954529b60b6f63 (commit)
       via  768256f0d324d42905eb9f3832c054193cd750b2 (commit)
       via  162d8a50bf6df93a6bc24d06e9042b5026c088ee (commit)
       via  41e944174785ff3370b4e165d491e8ff92cc0827 (commit)
       via  f860396ac01e1581dfe5f56ca30434c8b01b4270 (commit)
       via  be2641c8edb8a41556c4a0d9c2d86fb023917792 (commit)
       via  1ea02fa8ec59f386d62f04a0ef3c1adb77fd5319 (commit)
       via  3fa68dd21a3f9a62ca80400e48832d0e6225a2ea (commit)
       via  fc2f64b78c4c57c4c3b8fea3233a9fd3f52147f6 (commit)
       via  575abed0a58ba2e9f321b8ccc121a32356c7288d (commit)
       via  b0d2423c8b01c4432c7289f9648213e16406174a (commit)
       via  1dda9776c5a1f55037ac61f5290593e25a5677cb (commit)
       via  34797f06098f619838f094d9af7ec1a8c3ad4724 (commit)
       via  cfa23a3f19760c5266a9f4be0ad9302c977bfe8a (commit)
       via  a6bfcd47c9f662ac6dd4a2318d96579737a12837 (commit)
       via  57993cd407779a00004dc426cb282f06bccb5bd5 (commit)
       via  413750665895171f8eae4c8d86ff672b04a8f7cd (commit)
       via  b874caeeddf70e7b3911a4312494c8ae6de1ffd4 (commit)
       via  89e5e5522e81f9f9be4351eb6aab5f346a35586d (commit)
       via  448088a4f28ccdf90471cb60642d28bd4fdfd589 (commit)
       via  abbaa0220ce9faf1e97fd4845ee7f78076436193 (commit)
       via  0ffdaa56376184435e2ebb6b59dac42fbde51ab9 (commit)
       via  47ce4d4e87b887297289ff6511bde2feb807a476 (commit)
       via  e2736843dca94388a5ad562b7096a53451e2d037 (commit)
       via  9394b46cf8c83c0cfa83e73a34886aeb9f63913b (commit)
       via  66b54622b2edd8c6f41fb76950e81121813804e2 (commit)
       via  66c548481a50dbbaaa4f886d41af64cc39a5bfa3 (commit)
       via  b694e978ae5146b198914f8e114fff6333a75662 (commit)
       via  1f56ea5e07117170b407e17cc298ea9a79b60860 (commit)
       via  706a6986e046909d0035038412d759ba1e6c199c (commit)
       via  1624b232fe8cd35ab4a88ae0aa7d74498d98e3c9 (commit)
       via  591d2f8183dbed4dce5734ae09e5c2d2cb2de8c3 (commit)
       via  ae5e868cf90a06e489748299eca32564f248d52b (commit)
       via  1a6d54ba8e42b022e2dea6c696ab26ebac0345a2 (commit)
       via  c5ed036baf4b2eea39a2496e8c8267be96766dc2 (commit)
       via  433163526c9c788f53fb52ae4b389e3c77f7dc31 (commit)
       via  fa87159c9237db447843c6523f1daa7da2a67607 (commit)
       via  9ab8adb83f3038c03b8c1619bebcabbffc4e352e (commit)
       via  cb2abe96f218864eb0088c343b3a91ffa6e578e8 (commit)
       via  480dca6e1d5a251dd2ab680f776b46f37a052660 (commit)
       via  871d682ad8f89f934e68326fa6b3d861479321da (commit)
       via  2e6f61b3697981bb4a1af0a4f2738ff786668269 (commit)
       via  f8ba9bd5baffb67df87d1726c8635bb7d5d63ff2 (commit)
       via  49064db0f2c505427f826c7fc9608e39d3a2ffe2 (commit)
       via  72fce78916b051f6d76a4e61de9fb5d26eec10de (commit)
       via  51d7a0addacb9eae0fc88bea5b010a0559b4b887 (commit)
       via  df0ebe1c9b2b5eb5b99f1a5e4140dd13b3a14622 (commit)
       via  68f3e523c1a9ab857a1031926d7dff2760d26df1 (commit)
       via  c5eff00eb9e4e64bac262fbc8f0ff7631c9b5cf8 (commit)
       via  5aa5e56f84e645b9c5238215ef4fdeb0eba28f20 (commit)
       via  dd490ab030f402537f7edac3d1fcd443bc602e68 (commit)
       via  44db9747153ed1c73ff0d95cfc977ea5548403db (commit)
       via  572289496c4142e8cc748cfb641efd846b2a8dc0 (commit)
       via  d4899c06c3c254cdff2ceb2db6d2121dc6ad1f01 (commit)
       via  69d20d88cd1823c628ac51fdb9d5c86f545deede (commit)
       via  65074861612bdb49965f66e09c55ccbec46f960d (commit)
       via  d23a05405132459594db5c41bd4485207a887cce (commit)
       via  18220a9ec61fbb51381e8405c4b9c7e0e1c785a8 (commit)
       via  f63d75ebd26753eed1a2733ecbd21fe8f2a58044 (commit)
       via  b5c03db28904b7ab0b220ca5030a1dd4828169a1 (commit)
       via  e006915bdba4e8dead401dd98c896122e32b8974 (commit)
       via  53b69af9a3afc348e8a00f2ca45ccd1225155c07 (commit)
       via  f3343d7b5205f981b8d4002991f233a4e4e9645e (commit)
       via  53a20db873d9eb943ec65f9a6f10da125108ae94 (commit)
       via  7651845251617268572d954cc1cc94d1c609f7f7 (commit)
       via  529b6387bda5b3287a20d5166638d0ea08901e4d (commit)
       via  a90a0ae0e000a0679619e1dd2d0c065baaa5fb8c (commit)
       via  1e847b293c9f7ec3e6b2f051768f59a07d66f7d7 (commit)
       via  d479d28083104c2f4ec3aa74f232c46a1ad2e231 (commit)
       via  6913f102979144b1203fd032d1afffcf7cd8d09c (commit)
       via  5f9e9fd318c13fa5d58c30a6d2ab85d33fe59866 (commit)
       via  7837bf220f03f26090c509f427c003fc00deae76 (commit)
       via  0910249b0079177bd957635dd46286b16e769247 (commit)
       via  fbfa98d635f3cd6737585691cf82b4e65a0f1570 (commit)
       via  b34fd7b76ef0badf930c078b692a56a8d36b6e23 (commit)
       via  6a20f1ab5164bf1bbca0a3917ed5d3336773feeb (commit)
       via  8635a95c6569029b979ea21c9a4de78f35dac2cb (commit)
       via  41084ebbf79fb23cce9c1581b5f45c6aaffe7410 (commit)
       via  783d705e83c78f171ebd2128c5dadecf8cb9e44d (commit)
       via  8c1955a5240967abe7e74b8b7d5d3bc067c71842 (commit)
       via  aff68781848311763ebb92e299750dfe4b61eb5c (commit)
       via  f0d27ad5ba9caa722ce22b36975d1d4be70be762 (commit)
       via  78914f7922bf4620086eef4a77bead6ff55cf79d (commit)
       via  f4195acb409cf8ecaac3d63e3c85a52e98bbd9b1 (commit)
       via  dc9a45bea83aa73e62865969c445f2a8212be462 (commit)
       via  5a0a9a73584c42a5f188f3a1436512ccb6a01bbe (commit)
       via  acac1d74989f8aa6c28e9a9ef1b0ccb85197e30d (commit)
       via  81ddb566141c01bece3cdb115aaef0727fcc1558 (commit)
      from  4154f52ef1a545783458dcc089d359dab49598b2 (commit)

Summary of changes:
 config/SipConfigurator.py                          |   58 ++-
 config/test_sip.conf                               |    2 +
 .../SipSessionManager/SipConfigurationIf.ice       |  794 ++++++++++---------
 .../SipSessionManager/SipStateReplicationIf.ice    |   17 +
 slice/SipIf.ice                                    |    1 +
 src/AuthManager.cpp                                |  440 +++++++++++
 src/AuthManager.h                                  |  183 +++++
 src/CMakeLists.txt                                 |   29 +
 src/DebugUtil.h                                    |   33 +
 src/{PJSipLoggingModule.h => NATOptions.h}         |   30 +-
 src/PJSipLoggingModule.cpp                         |    1 +
 src/PJSipManager.cpp                               |  327 ++++++---
 src/PJSipManager.h                                 |   83 ++-
 src/PJSipModule.cpp                                |   15 +
 src/PJSipModule.h                                  |   12 +-
 src/PJSipRegistrarModule.cpp                       |  831 ++++++++++++++++++++
 src/PJSipRegistrarModule.h                         |  203 +++++
 src/PJSipRegistrarModuleConstruction.cpp           |  104 +++
 src/PJSipSessionModule.cpp                         |  497 ++++---------
 src/PJSipSessionModule.h                           |   29 +-
 src/PJSipSessionModuleConstruction.cpp             |   30 +-
 src/PJUtil.h                                       |   37 +
 src/STUNModule.cpp                                 |  157 ++++
 src/STUNModule.h                                   |  101 +++
 src/STUNTransport.cpp                              |  416 ++++++++++
 src/STUNTransport.h                                |   44 +
 src/STUNTransportConfig.cpp                        |  131 +++
 src/STUNTransportConfig.h                          |   52 ++
 src/SipConfiguration.cpp                           |  191 ++++-
 src/SipConfiguration.h                             |    2 +-
 src/SipEndpoint.cpp                                |   75 ++-
 src/SipEndpoint.h                                  |   72 ++-
 src/SipEndpointFactory.cpp                         |   17 +-
 src/SipEndpointFactory.h                           |    7 +-
 src/SipModule.h                                    |   68 ++
 src/SipRegistrarListener.cpp                       |  113 +++
 src/SipRegistrarListener.h                         |   46 ++
 src/SipSession.cpp                                 |  429 +++++++++-
 src/SipSession.h                                   |   49 +-
 src/SipSessionManagerApp.cpp                       |  129 +++-
 src/SipSessionManagerEndpointLocator.cpp           |   14 +-
 src/SipStateReplicator.h                           |    3 +-
 src/SipStateReplicatorListener.cpp                 |  185 +++++-
 src/SipTransfer.cpp                                |  339 ++++++++
 src/SipTransfer.h                                  |  138 ++++
 src/TCPTransport.cpp                               |  111 +++
 src/TCPTransport.h                                 |   41 +
 src/TLSTransport.cpp                               |   93 +++
 src/TLSTransport.h                                 |   43 +
 src/Transports.cpp                                 |   71 ++
 src/Transports.h                                   |   74 ++
 src/UDPTransport.cpp                               |  117 +++
 src/UDPTransport.h                                 |   41 +
 53 files changed, 6090 insertions(+), 1035 deletions(-)
 create mode 100644 src/AuthManager.cpp
 create mode 100644 src/AuthManager.h
 create mode 100644 src/DebugUtil.h
 copy src/{PJSipLoggingModule.h => NATOptions.h} (50%)
 create mode 100644 src/PJSipRegistrarModule.cpp
 create mode 100644 src/PJSipRegistrarModule.h
 create mode 100644 src/PJSipRegistrarModuleConstruction.cpp
 create mode 100644 src/PJUtil.h
 create mode 100644 src/STUNModule.cpp
 create mode 100644 src/STUNModule.h
 create mode 100644 src/STUNTransport.cpp
 create mode 100644 src/STUNTransport.h
 create mode 100644 src/STUNTransportConfig.cpp
 create mode 100644 src/STUNTransportConfig.h
 create mode 100644 src/SipModule.h
 create mode 100644 src/SipRegistrarListener.cpp
 create mode 100644 src/SipRegistrarListener.h
 mode change 100644 => 100755 src/SipSession.cpp
 create mode 100644 src/SipTransfer.cpp
 create mode 100644 src/SipTransfer.h
 create mode 100644 src/TCPTransport.cpp
 create mode 100644 src/TCPTransport.h
 create mode 100644 src/TLSTransport.cpp
 create mode 100644 src/TLSTransport.h
 create mode 100644 src/Transports.cpp
 create mode 100644 src/Transports.h
 create mode 100644 src/UDPTransport.cpp
 create mode 100644 src/UDPTransport.h


- Log -----------------------------------------------------------------
commit f2ef25b81ccb00782d921aa14e3e891f4744dd09
Merge: 9993515 4154f52
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jul 25 17:57:26 2011 -0500

    Merge branch 'transfer-improvements' of git.asterisk.org:asterisk-scf/integration/sip into transfer-improvements
    
    Conflicts:
    	src/PJSipSessionModule.cpp


commit 9993515f2d29a0808654f52bf981e488b2be42aa
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jul 25 17:56:20 2011 -0500

    Add some skeleton for the SessionListener and SessionCreationHooks to be used in transfers.

diff --git a/src/SipTransfer.cpp b/src/SipTransfer.cpp
index 75e5470..f67ce78 100644
--- a/src/SipTransfer.cpp
+++ b/src/SipTransfer.cpp
@@ -20,6 +20,7 @@
 #include <IceUtil/UUID.h>
 
 #include <AsteriskSCF/logger.h>
+#include <AsteriskSCF/SessionCommunications/SessionCommunicationsExtensionPointsIf.h>
 
 using namespace AsteriskSCF::System::Logging;
 
@@ -35,7 +36,41 @@ namespace SipSessionManager
 {
 
 using namespace AsteriskSCF::SessionCommunications::V1;
+using namespace AsteriskSCF::SessionCommunications::ExtensionPoints::V1;
 using namespace AsteriskSCF::System::WorkQueue::V1;
+using namespace AsteriskSCF::System::Hook::V1;
+
+class TransferListener : public SessionListener
+{
+    TransferListener()
+    {
+    }
+
+    void indicated(
+            const SessionPrx&,
+            const IndicationPtr&,
+            const SessionCookies&,
+            const Ice::Current&)
+    {
+    }
+};
+
+class TransferSessionCreationHook : public SessionCreationHook
+{
+    TransferSessionCreationHook()
+    {
+    }
+
+    HookResult modifySession(
+            const SessionCreationHookDataPtr&,
+            SessionCreationHookDataPtr&,
+            const Ice::Current&)
+    {
+        HookResult result;
+        result.status = Succeeded;
+        return result;
+    }
+};
 
 HandleReferOperation::HandleReferOperation(
         pjsip_inv_session *inv,

commit c4e9de5a78ef48217e9104205fe875f400c9f553
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jul 25 16:58:21 2011 -0500

    Move logic for transfers to a separate file.
    
    This cleans things up quite a bit and will make adding the temporary session
    listener, etc. much easier to follow once that is done.

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c5b8ec6..81f2bec 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -23,6 +23,8 @@ astscf_component_add_files(SipSessionManager PJSipManager.cpp)
 astscf_component_add_files(SipSessionManager PJSipManager.h)
 astscf_component_add_files(SipSessionManager PJSipModule.cpp)
 astscf_component_add_files(SipSessionManager PJSipModule.h)
+astscf_component_add_files(SipSessionManager SipTransfer.cpp)
+astscf_component_add_files(SipSessionManager SipTransfer.h)
 astscf_component_add_files(SipSessionManager PJSipSessionModule.cpp)
 astscf_component_add_files(SipSessionManager PJSipSessionModuleConstruction.cpp)
 astscf_component_add_files(SipSessionManager PJSipSessionModule.h)
diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 12e75ac..91ce3c1 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "PJSipSessionModule.h"
+#include "SipTransfer.h"
 #include "SipEndpoint.h"
 #include "SipEndpointFactory.h"
 #include "SipSession.h"
@@ -22,7 +23,6 @@
 #include "SipStateReplicator.h"
 
 #include <IceUtil/UUID.h>
-#include <boost/algorithm/string.hpp>
 
 #include <AsteriskSCF/Core/Endpoint/EndpointIf.h>
 #include <AsteriskSCF/Core/Routing/RoutingIf.h>
@@ -719,352 +719,6 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
     sessionWork->enqueueWork(new SessionCreationOperation(this, caller, mSessionRouter, inv_session, tdata, replaced_dlg, destination));
 }
 
-class HandleReferOperation : public SipQueueableOperation 
-{
-public:
-    HandleReferOperation(
-            pjsip_inv_session *inv,
-            pjsip_transaction *tsx,
-            pjsip_tx_data *tdata,
-            pjsip_param *replaces_param,
-            pjsip_param *to_tag_param,
-            pjsip_param *from_tag_param,
-            const std::string& referredBy,
-            const std::string& target,
-            const SipSessionPtr& session,
-            const AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx>& sessionRouter,
-            const int moduleId)
-        : mInv(inv), mTsx(tsx), mTdata(tdata), 
-        mReplacesParam(replaces_param ? new pjsip_param(*replaces_param) : NULL), 
-        mToTagParam(to_tag_param ? new pjsip_param(*to_tag_param) : NULL),
-        mFromTagParam(from_tag_param ? new pjsip_param(*from_tag_param) : NULL),
-        mReferredBy(referredBy),
-        mTarget(target),
-        mSession(session), mSessionRouter(sessionRouter),
-        mModuleId(moduleId), mReferCSeq(tsx->cseq), mWasWithDestination(false) {}
-
-    ~HandleReferOperation()
-    {
-        delete mReplacesParam;
-        delete mToTagParam;
-        delete mFromTagParam;
-    }
-
-protected:
-    /**
-     * This is what is initially called when the operation is queued.
-     *
-     * In this portion, we grab some essential data out of the target URI and use
-     * it to call out to the routing service, either ConnectBridgedSessions or
-     * ConnectBridgedSessionWithDestination.
-     *
-     * When this operation is successful, it will result in work for this session
-     * being suspended until the routing service returns.
-     */
-    SuspendableWorkResult initial(const SuspendableWorkListenerPtr& workListener)
-    {
-        // Determine if this is a blind transfer or an attended transfer
-
-        if (mReplacesParam)
-        {
-            pjsip_dialog *other_dlg = NULL;
-
-            if (mToTagParam && mFromTagParam)
-            {
-                other_dlg = pjsip_ua_find_dialog(&mReplacesParam->value, &mToTagParam->value, &mFromTagParam->value,
-                        PJ_TRUE);
-            }
-            else
-            {
-                // It is possible for the to and from tag value to be present within the Replaces parameter value, so try to
-                // parse it out
-                std::string replaces_value_tmp = std::string(pj_strbuf(&mReplacesParam->value),
-                        pj_strlen(&mReplacesParam->value));
-                std::vector<std::string> params;
-
-                boost::split(params, replaces_value_tmp, boost::is_any_of(";"));
-
-                //The first value will be the actual replaces value.
-                std::string replaces = params.front();
-
-                std::string to;
-                std::string from;
-                std::string fromTagParamName("from-tag=");
-                std::string toTagParamName("to-tag=");
-                for(std::vector<std::string>::iterator iter = params.begin();
-                        iter != params.end(); ++iter)
-                {
-                    if (iter->compare(0, toTagParamName.size(), toTagParamName) == 0)
-                    {
-                        to = iter->substr(toTagParamName.size());
-                    }
-                    if (iter->compare(0, fromTagParamName.size(), fromTagParamName) == 0)
-                    {
-                        from = iter->substr(fromTagParamName.size());
-                    }
-                }
-
-                if (from.empty() || to.empty())
-                {
-                    lg(Debug) << "handleRefer() sending 400 due to From or To missing. ";
-                    pjsip_dlg_modify_response(mInv->dlg, mTdata, 400, NULL);
-                    pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                    return Complete;
-                }
-
-                pj_str_t to_tag_str = pj_str((char*)to.c_str());
-                pj_str_t from_tag_str = pj_str((char*)from.c_str());
-                pj_str_t replaces_tag_str = pj_str((char*)replaces.c_str());
-
-                other_dlg = pjsip_ua_find_dialog(&replaces_tag_str, &to_tag_str, &from_tag_str, PJ_TRUE);
-            }
-
-            if (!other_dlg)
-            {
-                lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to no other_dlg. ";
-                pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
-                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                return Complete;
-            }
-
-            pjsip_inv_session *other_inv = pjsip_dlg_get_inv_session(other_dlg);
-
-            if (!other_inv)
-            {
-                lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to no other_inv. ";
-                pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
-                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                pjsip_dlg_dec_lock(other_dlg);
-                return Complete;
-            }
-
-            if (other_inv->state >= PJSIP_INV_STATE_DISCONNECTED)
-            {
-                lg(Debug) << "handleRefer() sending PJSIP_SC_DECLINE due to state > PJSIP_INV_STATE_DISCONNECTED. ";
-
-                pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_DECLINE, NULL);
-                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                pjsip_dlg_dec_lock(other_dlg);
-                return Complete;
-            }
-
-            if (other_inv->state <= PJSIP_INV_STATE_EARLY && other_inv->role != PJSIP_ROLE_UAC)
-            {
-                lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to other_inv->state < PJSIP_INV_STATE_EARLY and role not UAC. ";
-
-                pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
-                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                pjsip_dlg_dec_lock(other_dlg);
-                return Complete;
-            }
-
-            PJSipSessionModInfo *other_session_mod_info = (PJSipSessionModInfo*)other_inv->mod_data[mModuleId];
-            SipSessionPtr other_session = other_session_mod_info->getSessionPtr();
-
-            //Go ahead and send a 202 for the REFER. We can send a NOTIFY later to indicate if something
-            //on the outbound leg went awry.
-            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-            try
-            {
-                std::string operationId = ::IceUtil::generateUUID();
-                SipAMICallbackPtr cb(new SipAMICallback(workListener, mSession, this, false, true));
-                Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
-
-                lg(Debug) << "handleRefer() calling router connectBridgedSessions(). ";
-                mSessionRouter->begin_connectBridgedSessions(operationId, mSession->getSessionProxy(), other_session->getSessionProxy(), d);
-                pjsip_dlg_dec_lock(other_dlg);
-                return Complete;
-            }
-            catch (const Ice::CommunicatorDestroyedException &)
-            {
-                lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
-                pjsip_dlg_modify_response(mInv->dlg, mTdata, 503, NULL);
-                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                pjsip_dlg_dec_lock(other_dlg);
-                return Complete;
-            }
-        }
-        else
-        {
-            //Go ahead and send a 202 for the REFER. We can send a NOTIFY later to indicate if something
-            //on the outbound leg went awry.
-            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-
-            // Now that we have the target user we can pass this into routing and go on our marry way
-            try
-            {
-                std::string operationId = ::IceUtil::generateUUID();
-                PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)mInv->mod_data[mModuleId];
-                SipSessionPtr session = session_mod_info->getSessionPtr();
-                SipAMICallbackPtr cb(new SipAMICallback(workListener, mSession, this, false, true));
-                Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
-
-                lg(Debug) << "handleRefer() calling router connectBridgedSessionsWithDestination(). ";
-                lg(Debug) << "Session to replace is with endpoint " << session->getEndpoint()->getName();
-                lg(Debug) << "Destination is " << mTarget;
-                mWasWithDestination = true;
-                mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), mTarget, 0, d);
-                return Complete;
-            }
-            catch (const Ice::CommunicatorDestroyedException &)
-            {
-                lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
-                pjsip_dlg_modify_response(mInv->dlg, mTdata, 503, NULL);
-                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                return Complete;
-            }
-        }
-    };
-
-    /**
-     * Once the routing service has allowed for work to be resumed,
-     * this is where the final work is done
-     */
-    SuspendableWorkResult calledBack(const SuspendableWorkListenerPtr&)
-    {
-        assert(mAsyncResult);
-        SessionRouterPrx router = SessionRouterPrx::uncheckedCast(mAsyncResult->getProxy());
-
-        // We need to send a NOTIFY to indicate how things went on the other leg.
-        // XXX Once we have a subscription module written, we can actually use it.
-
-        pjsip_tx_data *tdata = createNotify();
-        
-        try
-        {
-            if (mWasWithDestination)
-            {
-                router->end_connectBridgedSessionsWithDestination(mAsyncResult);
-            }
-            else
-            {
-                router->end_connectBridgedSessions(mAsyncResult);
-            }
-        }
-        catch (const AsteriskSCF::Core::Routing::V1::DestinationNotFoundException &)
-        {
-            lg(Debug) << "ConnectBridgedSessionsWithDestination sending 404 due to destination not found.";
-
-            addNotifyBody(tdata, "SIP/2.0 404 Not Found");
-            pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
-            return Complete;
-        }
-        catch (const std::exception &e)
-        {
-            lg(Debug) << "ConnectBridgedSessionsCallback sending 400 due to exception:  " << e.what();
-
-            addNotifyBody(tdata, "SIP/2.0 400 Bad Request");
-            pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
-            return Complete;
-        }
-
-        addNotifyBody(tdata, "SIP/2.0 200 OK");
-        pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
-        
-        Ice::Current current;
-        lg(Debug) << "ConnectBridgedSessionsCallback calling session->stop(). ";
-        mSession->stop(new ResponseCode(16), current);
-        return Complete;
-    }
-
-private:
-
-    pjsip_tx_data* createNotify()
-    {
-        pjsip_tx_data *tdata;
-        pjsip_dlg_create_request(mInv->dlg, pjsip_get_notify_method(), -1, &tdata);
-
-        pjsip_event_hdr *event = pjsip_event_hdr_create(tdata->pool);
-        pj_strdup2(tdata->pool, &event->event_type, "refer");
-        char idbuf[20];
-        pj_ansi_snprintf(idbuf, sizeof(idbuf), "%d", mReferCSeq);
-        pj_strdup2(tdata->pool, &event->id_param, idbuf);
-        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) event);
-
-        pjsip_sub_state_hdr *subState = pjsip_sub_state_hdr_create(tdata->pool);
-        pj_strdup2(tdata->pool, &subState->sub_state, "terminated");
-        pj_strdup2(tdata->pool, &subState->reason_param, "noresource");
-        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) subState);
-
-        return tdata;
-    }
-    void addNotifyBody(pjsip_tx_data *tdata, const char *bodyText)
-    {
-        pj_str_t type;
-        pj_cstr(&type, "message");
-        pj_str_t subtype;
-        pj_cstr(&subtype, "sipfrag;version=2.0");
-
-        pj_str_t bodyStr;
-        pj_cstr(&bodyStr, bodyText);
-        pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
-        tdata->msg->body = body;
-    }
-    /**
-     * The INVITE session, which contains the dialog on which the
-     * REFER was received.
-     */
-    pjsip_inv_session *mInv;
-    /**
-     * The REFER transaction
-     */
-    pjsip_transaction *mTsx;
-    /**
-     * The transmission data for our REFER response. We set this
-     * up to default to a 200 OK response and alter it if necessary.
-     */
-    pjsip_tx_data *mTdata;
-    /**
-     * The Replaces parameter from the URI in the Refer-To header
-     * of the REFER that triggered this operation.
-     */
-    pjsip_param *mReplacesParam;
-    /**
-     * The to-tag parameter from the URI in the Refer-To header
-     * of the REFER that triggered this operation.
-     */
-    pjsip_param *mToTagParam;
-    /**
-     * The from-tag parameter from the URI in the Refer-To header
-     * of the REFER that triggered this operation.
-     */
-    pjsip_param *mFromTagParam;
-    /**
-     * The content from the Referred-By header, if one existed.
-     * XXX We currently have this handy, but we don't actually do
-     * anything with it. This is because we don't have a way to place
-     * this information in the outgoing INVITE.
-     */
-    const std::string mReferredBy;
-    /**
-     * The user portion of the URI in the Refer-To header of the
-     * REFER that triggered this operation.
-     */
-    const std::string mTarget;
-    /**
-     * The SipSession on which this work is executed
-     */
-    SipSessionPtr mSession;
-    /**
-     * Session router...nothing more to say really
-     */
-    AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx> mSessionRouter;
-    /**
-     * The identifier of the PJSipSessionModule. Used for retrieving module data from mInv
-     */
-    const int mModuleId;
-    /**
-     * The CSeq of the REFER
-     */
-    pj_int32_t mReferCSeq;
-    /**
-     * Helps determine which end_* method to call on the session router when AMI completes.
-     * XXX It may be more elegant to handle this by sending a cookie to the AMI method
-     * instead.
-     */
-    bool mWasWithDestination;
-};
-
 void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata)
 {
     //rdata structures are not safe to shallow copy to a queuable operation. Get
diff --git a/src/SipTransfer.cpp b/src/SipTransfer.cpp
new file mode 100644
index 0000000..75e5470
--- /dev/null
+++ b/src/SipTransfer.cpp
@@ -0,0 +1,304 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+
+#include "SipTransfer.h"
+
+#include <boost/algorithm/string.hpp>
+#include <IceUtil/UUID.h>
+
+#include <AsteriskSCF/logger.h>
+
+using namespace AsteriskSCF::System::Logging;
+
+namespace
+{
+Logger lg = getLoggerFactory().getLogger("AsteriskSCF.SipSessionManager");
+}
+
+namespace AsteriskSCF
+{
+
+namespace SipSessionManager
+{
+
+using namespace AsteriskSCF::SessionCommunications::V1;
+using namespace AsteriskSCF::System::WorkQueue::V1;
+
+HandleReferOperation::HandleReferOperation(
+        pjsip_inv_session *inv,
+        pjsip_transaction *tsx,
+        pjsip_tx_data *tdata,
+        pjsip_param *replaces_param,
+        pjsip_param *to_tag_param,
+        pjsip_param *from_tag_param,
+        const std::string& referredBy,
+        const std::string& target,
+        const SipSessionPtr& session,
+        const AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx>& sessionRouter,
+        const int moduleId)
+    : mInv(inv), mTsx(tsx), mTdata(tdata), 
+    mReplacesParam(replaces_param ? new pjsip_param(*replaces_param) : NULL), 
+    mToTagParam(to_tag_param ? new pjsip_param(*to_tag_param) : NULL),
+    mFromTagParam(from_tag_param ? new pjsip_param(*from_tag_param) : NULL),
+    mReferredBy(referredBy),
+    mTarget(target),
+    mSession(session), mSessionRouter(sessionRouter),
+    mModuleId(moduleId), mReferCSeq(tsx->cseq), mWasWithDestination(false) {}
+
+HandleReferOperation::~HandleReferOperation()
+{
+    delete mReplacesParam;
+    delete mToTagParam;
+    delete mFromTagParam;
+}
+
+SuspendableWorkResult HandleReferOperation::initial(const SuspendableWorkListenerPtr& workListener)
+{
+    // Determine if this is a blind transfer or an attended transfer
+
+    if (mReplacesParam)
+    {
+        pjsip_dialog *other_dlg = NULL;
+
+        if (mToTagParam && mFromTagParam)
+        {
+            other_dlg = pjsip_ua_find_dialog(&mReplacesParam->value, &mToTagParam->value, &mFromTagParam->value,
+                    PJ_TRUE);
+        }
+        else
+        {
+            // It is possible for the to and from tag value to be present within the Replaces parameter value, so try to
+            // parse it out
+            std::string replaces_value_tmp = std::string(pj_strbuf(&mReplacesParam->value),
+                    pj_strlen(&mReplacesParam->value));
+            std::vector<std::string> params;
+
+            boost::split(params, replaces_value_tmp, boost::is_any_of(";"));
+
+            //The first value will be the actual replaces value.
+            std::string replaces = params.front();
+
+            std::string to;
+            std::string from;
+            std::string fromTagParamName("from-tag=");
+            std::string toTagParamName("to-tag=");
+            for(std::vector<std::string>::iterator iter = params.begin();
+                    iter != params.end(); ++iter)
+            {
+                if (iter->compare(0, toTagParamName.size(), toTagParamName) == 0)
+                {
+                    to = iter->substr(toTagParamName.size());
+                }
+                if (iter->compare(0, fromTagParamName.size(), fromTagParamName) == 0)
+                {
+                    from = iter->substr(fromTagParamName.size());
+                }
+            }
+
+            if (from.empty() || to.empty())
+            {
+                lg(Debug) << "handleRefer() sending 400 due to From or To missing. ";
+                pjsip_dlg_modify_response(mInv->dlg, mTdata, 400, NULL);
+                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+                return Complete;
+            }
+
+            pj_str_t to_tag_str = pj_str((char*)to.c_str());
+            pj_str_t from_tag_str = pj_str((char*)from.c_str());
+            pj_str_t replaces_tag_str = pj_str((char*)replaces.c_str());
+
+            other_dlg = pjsip_ua_find_dialog(&replaces_tag_str, &to_tag_str, &from_tag_str, PJ_TRUE);
+        }
+
+        if (!other_dlg)
+        {
+            lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to no other_dlg. ";
+            pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+            return Complete;
+        }
+
+        pjsip_inv_session *other_inv = pjsip_dlg_get_inv_session(other_dlg);
+
+        if (!other_inv)
+        {
+            lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to no other_inv. ";
+            pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+            pjsip_dlg_dec_lock(other_dlg);
+            return Complete;
+        }
+
+        if (other_inv->state >= PJSIP_INV_STATE_DISCONNECTED)
+        {
+            lg(Debug) << "handleRefer() sending PJSIP_SC_DECLINE due to state > PJSIP_INV_STATE_DISCONNECTED. ";
+
+            pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_DECLINE, NULL);
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+            pjsip_dlg_dec_lock(other_dlg);
+            return Complete;
+        }
+
+        if (other_inv->state <= PJSIP_INV_STATE_EARLY && other_inv->role != PJSIP_ROLE_UAC)
+        {
+            lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to other_inv->state < PJSIP_INV_STATE_EARLY and role not UAC. ";
+
+            pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+            pjsip_dlg_dec_lock(other_dlg);
+            return Complete;
+        }
+
+        PJSipSessionModInfo *other_session_mod_info = (PJSipSessionModInfo*)other_inv->mod_data[mModuleId];
+        SipSessionPtr other_session = other_session_mod_info->getSessionPtr();
+
+        //Go ahead and send a 202 for the REFER. We can send a NOTIFY later to indicate if something
+        //on the outbound leg went awry.
+        pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+        try
+        {
+            std::string operationId = ::IceUtil::generateUUID();
+            SipAMICallbackPtr cb(new SipAMICallback(workListener, mSession, this, false, true));
+            Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
+
+            lg(Debug) << "handleRefer() calling router connectBridgedSessions(). ";
+            mSessionRouter->begin_connectBridgedSessions(operationId, mSession->getSessionProxy(), other_session->getSessionProxy(), d);
+            pjsip_dlg_dec_lock(other_dlg);
+            return Complete;
+        }
+        catch (const Ice::CommunicatorDestroyedException &)
+        {
+            lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
+            pjsip_dlg_modify_response(mInv->dlg, mTdata, 503, NULL);
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+            pjsip_dlg_dec_lock(other_dlg);
+            return Complete;
+        }
+    }
+    else
+    {
+        //Go ahead and send a 202 for the REFER. We can send a NOTIFY later to indicate if something
+        //on the outbound leg went awry.
+        pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+
+        // Now that we have the target user we can pass this into routing and go on our marry way
+        try
+        {
+            std::string operationId = ::IceUtil::generateUUID();
+            PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)mInv->mod_data[mModuleId];
+            SipSessionPtr session = session_mod_info->getSessionPtr();
+            SipAMICallbackPtr cb(new SipAMICallback(workListener, mSession, this, false, true));
+            Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
+
+            lg(Debug) << "handleRefer() calling router connectBridgedSessionsWithDestination(). ";
+            lg(Debug) << "Session to replace is with endpoint " << session->getEndpoint()->getName();
+            lg(Debug) << "Destination is " << mTarget;
+            mWasWithDestination = true;
+            mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), mTarget, 0, d);
+            return Complete;
+        }
+        catch (const Ice::CommunicatorDestroyedException &)
+        {
+            lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
+            pjsip_dlg_modify_response(mInv->dlg, mTdata, 503, NULL);
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+            return Complete;
+        }
+    }
+};
+
+SuspendableWorkResult HandleReferOperation::calledBack(const SuspendableWorkListenerPtr&)
+{
+    assert(mAsyncResult);
+    SessionRouterPrx router = SessionRouterPrx::uncheckedCast(mAsyncResult->getProxy());
+
+    // We need to send a NOTIFY to indicate how things went on the other leg.
+    // XXX Once we have a subscription module written, we can actually use it.
+
+    pjsip_tx_data *tdata = createNotify();
+    
+    try
+    {
+        if (mWasWithDestination)
+        {
+            router->end_connectBridgedSessionsWithDestination(mAsyncResult);
+        }
+        else
+        {
+            router->end_connectBridgedSessions(mAsyncResult);
+        }
+    }
+    catch (const AsteriskSCF::Core::Routing::V1::DestinationNotFoundException &)
+    {
+        lg(Debug) << "ConnectBridgedSessionsWithDestination sending 404 due to destination not found.";
+
+        addNotifyBody(tdata, "SIP/2.0 404 Not Found");
+        pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
+        return Complete;
+    }
+    catch (const std::exception &e)
+    {
+        lg(Debug) << "ConnectBridgedSessionsCallback sending 400 due to exception:  " << e.what();
+
+        addNotifyBody(tdata, "SIP/2.0 400 Bad Request");
+        pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
+        return Complete;
+    }
+
+    addNotifyBody(tdata, "SIP/2.0 200 OK");
+    pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
+    
+    Ice::Current current;
+    lg(Debug) << "ConnectBridgedSessionsCallback calling session->stop(). ";
+    mSession->stop(new ResponseCode(16), current);
+    return Complete;
+}
+
+pjsip_tx_data* HandleReferOperation::createNotify()
+{
+    pjsip_tx_data *tdata;
+    pjsip_dlg_create_request(mInv->dlg, pjsip_get_notify_method(), -1, &tdata);
+
+    pjsip_event_hdr *event = pjsip_event_hdr_create(tdata->pool);
+    pj_strdup2(tdata->pool, &event->event_type, "refer");
+    char idbuf[20];
+    pj_ansi_snprintf(idbuf, sizeof(idbuf), "%d", mReferCSeq);
+    pj_strdup2(tdata->pool, &event->id_param, idbuf);
+    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) event);
+
+    pjsip_sub_state_hdr *subState = pjsip_sub_state_hdr_create(tdata->pool);
+    pj_strdup2(tdata->pool, &subState->sub_state, "terminated");
+    pj_strdup2(tdata->pool, &subState->reason_param, "noresource");
+    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) subState);
+
+    return tdata;
+}
+
+void HandleReferOperation::addNotifyBody(pjsip_tx_data *tdata, const char *bodyText)
+{
+    pj_str_t type;
+    pj_cstr(&type, "message");
+    pj_str_t subtype;
+    pj_cstr(&subtype, "sipfrag;version=2.0");
+
+    pj_str_t bodyStr;
+    pj_cstr(&bodyStr, bodyText);
+    pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
+    tdata->msg->body = body;
+}
+
+}; //end namespace SipSessionManager
+}; //end namespace AsteriskSCF
diff --git a/src/SipTransfer.h b/src/SipTransfer.h
new file mode 100644
index 0000000..1cb95b1
--- /dev/null
+++ b/src/SipTransfer.h
@@ -0,0 +1,138 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+
+#include "PJSipSessionModule.h"
+
+#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
+
+namespace AsteriskSCF
+{
+
+namespace SipSessionManager
+{
+
+class HandleReferOperation : public SipQueueableOperation 
+{
+public:
+    HandleReferOperation(
+            pjsip_inv_session *inv,
+            pjsip_transaction *tsx,
+            pjsip_tx_data *tdata,
+            pjsip_param *replaces_param,
+            pjsip_param *to_tag_param,
+            pjsip_param *from_tag_param,
+            const std::string& referredBy,
+            const std::string& target,
+            const SipSessionPtr& session,
+            const AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::SessionCommunications::V1::SessionRouterPrx>& sessionRouter,
+            const int moduleId);
+
+    ~HandleReferOperation();
+
+protected:
+    /**
+     * This is what is initially called when the operation is queued.
+     *
+     * In this portion, we grab some essential data out of the target URI and use
+     * it to call out to the routing service, either ConnectBridgedSessions or
+     * ConnectBridgedSessionWithDestination.
+     *
+     * When this operation is successful, it will result in work for this session
+     * being suspended until the routing service returns.
+     */
+    AsteriskSCF::System::WorkQueue::V1::SuspendableWorkResult initial(
+            const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkListenerPtr& workListener);
+
+    /**
+     * Once the routing service has allowed for work to be resumed,
+     * this is where the final work is done
+     */
+    AsteriskSCF::System::WorkQueue::V1::SuspendableWorkResult calledBack(
+            const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkListenerPtr&);
+
+private:
+
+    pjsip_tx_data* createNotify();
+
+    void addNotifyBody(pjsip_tx_data *tdata, const char *bodyText);
+
+    /**
+     * The INVITE session, which contains the dialog on which the
+     * REFER was received.
+     */
+    pjsip_inv_session *mInv;
+    /**
+     * The REFER transaction
+     */
+    pjsip_transaction *mTsx;
+    /**
+     * The transmission data for our REFER response. We set this
+     * up to default to a 200 OK response and alter it if necessary.
+     */
+    pjsip_tx_data *mTdata;
+    /**
+     * The Replaces parameter from the URI in the Refer-To header
+     * of the REFER that triggered this operation.
+     */
+    pjsip_param *mReplacesParam;
+    /**
+     * The to-tag parameter from the URI in the Refer-To header
+     * of the REFER that triggered this operation.
+     */
+    pjsip_param *mToTagParam;
+    /**
+     * The from-tag parameter from the URI in the Refer-To header
+     * of the REFER that triggered this operation.
+     */
+    pjsip_param *mFromTagParam;
+    /**
+     * The content from the Referred-By header, if one existed.
+     * XXX We currently have this handy, but we don't actually do
+     * anything with it. This is because we don't have a way to place
+     * this information in the outgoing INVITE.
+     */
+    const std::string mReferredBy;
+    /**
+     * The user portion of the URI in the Refer-To header of the
+     * REFER that triggered this operation.
+     */
+    const std::string mTarget;
+    /**
+     * The SipSession on which this work is executed
+     */
+    SipSessionPtr mSession;
+    /**
+     * Session router...nothing more to say really
+     */
+    AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::SessionCommunications::V1::SessionRouterPrx> mSessionRouter;
+    /**
+     * The identifier of the PJSipSessionModule. Used for retrieving module data from mInv
+     */
+    const int mModuleId;
+    /**
+     * The CSeq of the REFER
+     */
+    pj_int32_t mReferCSeq;
+    /**
+     * Helps determine which end_* method to call on the session router when AMI completes.
+     * XXX It may be more elegant to handle this by sending a cookie to the AMI method
+     * instead.
+     */
+    bool mWasWithDestination;
+};
+
+}; //end namespace SipSessionManager
+}; //end namespace AsteriskSCF

commit 1ed569652e73a9ed71484baee8f0e1ac972aa68f
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jul 25 16:29:27 2011 -0500

    Put one-shot hooks into session creation.
    
    This should be all set up now...
    Now to try to create a hook to use during transfers.

diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 989f593..37d7fbe 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -467,7 +467,7 @@ SipSession::SipSession(
         const PJSipManagerPtr& manager,
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
         const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
-        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
         bool /* ipv6 */,
         bool isUAC,
         const NATEndpointOptions& natOptions)
@@ -478,8 +478,6 @@ SipSession::SipSession(
         mImplPriv->mListeners.push_back(listener);
     }
 
-    activateIceObjects(mImplPriv->mManager->getSessionModule()->getSessionCreationHooks());
-
     mImplPriv->mMediaSession = new SipMediaSession(this);
     mImplPriv->mMediaSessionProxy =
         AsteriskSCF::Media::V1::SessionPrx::uncheckedCast(adapter->addWithUUID(mImplPriv->mMediaSession));
@@ -489,6 +487,14 @@ SipSession::SipSession(
         lg(Debug) << "New session is UAC, so we're creating the necessary PJSIP structures";
         initializePJSIPStructs();
     }
+
+    AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookSeq hooks =
+        mImplPriv->mManager->getSessionModule()->getSessionCreationHooks();
+    if (oneShotHook)
+    {
+        hooks.push_back(oneShotHook);
+    }
+    activateIceObjects(hooks);
 }
 
 /**
@@ -505,13 +511,11 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
         const PJSipManagerPtr& manager,
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
         const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
-        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
         bool isUAC,
         const NATEndpointOptions& natOptions)
     : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica, natOptions))
 {
-    activateIceObjects(mImplPriv->mManager->getSessionModule()->getSessionCreationHooks());
-
     mImplPriv->mMediaSession = new SipMediaSession(this);
     mImplPriv->mMediaSessionProxy =
         AsteriskSCF::Media::V1::SessionPrx::uncheckedCast(adapter->add(mImplPriv->mMediaSession, mediaid));
@@ -524,6 +528,14 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
     {
         initializePJSIPStructs();
     }
+
+    AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookSeq hooks =
+        mImplPriv->mManager->getSessionModule()->getSessionCreationHooks();
+    if (oneShotHook)
+    {
+        hooks.push_back(oneShotHook);
+    }
+    activateIceObjects(hooks);
 }
 
 class AddListenerOperation : public SuspendableWork

commit fcb2a102e93641937a78e8b22b01b1b677c429ca
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jul 25 15:56:36 2011 -0500

    Initial changes needed to satisfy one-shot hook slice API changes.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 09bc8d5..12e75ac 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -512,7 +512,7 @@ protected:
                 SuspendableWorkListenerPtr listener = 0;
                 SipAMICallbackPtr cb(new SipAMICallback(listener, mSession, this, false, true));
                 Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
-                mSessionRouter->begin_routeSession(operationId, mSession->getSessionProxy(), mDestination, d);
+                mSessionRouter->begin_routeSession(operationId, mSession->getSessionProxy(), mDestination, 0, d);
             }
         }
         catch (const Ice::CommunicatorDestroyedException &)
@@ -903,7 +903,7 @@ protected:
                 lg(Debug) << "Session to replace is with endpoint " << session->getEndpoint()->getName();
                 lg(Debug) << "Destination is " << mTarget;
                 mWasWithDestination = true;
-                mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), mTarget, d);
+                mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), mTarget, 0, d);
                 return Complete;
             }
             catch (const Ice::CommunicatorDestroyedException &)
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index 8c5465a..0436a1a 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -354,8 +354,11 @@ std::string SipEndpoint::getId(const Ice::Current&)
     return mImplPriv->mEndpointProxy->ice_getIdentity().name;
 }
 
-AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(const std::string& destination,
-        const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current&)
+AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(
+        const std::string& destination,
+        const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
+        const Ice::Current&)
 {
 
     std::cout << "Got call over Ice to create a session for endpoint " << mImplPriv->mName << std::endl;
@@ -367,7 +370,7 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(co
     }
 
     SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, listener, mImplPriv->mManager,
-        mImplPriv->mServiceLocator, mImplPriv->mReplica, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, true, 
+        mImplPriv->mServiceLocator, mImplPriv->mReplica, oneShotHook, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, true, 
         NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
             mImplPriv->mConfig.transportConfig.enableNAT));
     mImplPriv->mSessions.push_back(session);
@@ -378,7 +381,7 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(co
 AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const std::string& destination)
 {
     SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, 0, mImplPriv->mManager,
-        mImplPriv->mServiceLocator, mImplPriv->mReplica, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, false,
+        mImplPriv->mServiceLocator, mImplPriv->mReplica, 0, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, false,
         NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
             mImplPriv->mConfig.transportConfig.enableNAT)
         );
@@ -393,7 +396,7 @@ AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const s
                                                                          const AsteriskSCF::Media::V1::StreamSinkSeq& sinks)
 {
     SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, sessionid, mediaid, mediasessions,
-            sources, sinks, mImplPriv->mManager, mImplPriv->mServiceLocator, mImplPriv->mReplica, false,
+            sources, sinks, mImplPriv->mManager, mImplPriv->mServiceLocator, mImplPriv->mReplica, 0, false,
             NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
                 mImplPriv->mConfig.transportConfig.enableNAT));
     mImplPriv->mSessions.push_back(session);
diff --git a/src/SipEndpoint.h b/src/SipEndpoint.h
index 2ce13ff..ce2e7de 100644
--- a/src/SipEndpoint.h
+++ b/src/SipEndpoint.h
@@ -276,8 +276,11 @@ public:
      * Interface implementation.
      */
     std::string getId(const Ice::Current&);
-    AsteriskSCF::SessionCommunications::V1::SessionPrx createSession(const std::string&,
-            const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&, const Ice::Current&);
+    AsteriskSCF::SessionCommunications::V1::SessionPrx createSession(
+            const std::string&,
+            const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&,
+            const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
+            const Ice::Current&);
     AsteriskSCF::SessionCommunications::V1::SessionSeq getSessions(const Ice::Current&);
 
     /**
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index fd5758e..989f593 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -459,10 +459,18 @@ void SipSession::activateIceObjects(const AsteriskSCF::SessionCommunications::Ex
 /**
  * Default constructor.
  */
-SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPtr& endpoint,
-        const std::string& destination,  const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
-        const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, bool /* ipv6 */, bool isUAC, const NATEndpointOptions& natOptions)
+SipSession::SipSession(
+        const Ice::ObjectAdapterPtr& adapter,
+        const SipEndpointPtr& endpoint,
+        const std::string& destination,
+        const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
+        const PJSipManagerPtr& manager,
+        const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
+        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
+        bool /* ipv6 */,
+        bool isUAC,
+        const NATEndpointOptions& natOptions)
     : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica, natOptions))
 {
     if (listener != 0)
@@ -486,12 +494,20 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPt
 /**
  * Replica constructor.
  */
-SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPtr& endpoint,
-        const std::string& destination, const Ice::Identity& /* sessionid */,
-        const Ice::Identity& mediaid, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq& mediasessions,
-        const AsteriskSCF::Media::V1::StreamSourceSeq& sources, const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
-        const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, bool isUAC, const NATEndpointOptions& natOptions)
+SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
+        const SipEndpointPtr& endpoint,
+        const std::string& destination,
+        const Ice::Identity& /* sessionid */,
+        const Ice::Identity& mediaid,
+        const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq& mediasessions,
+        const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
+        const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
+        const PJSipManagerPtr& manager,
+        const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
+        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
+        bool isUAC,
+        const NATEndpointOptions& natOptions)
     : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica, natOptions))
 {
     activateIceObjects(mImplPriv->mManager->getSessionModule()->getSessionCreationHooks());
diff --git a/src/SipSession.h b/src/SipSession.h
index 165c411..9a88f77 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -109,6 +109,7 @@ public:
         const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&, const PJSipManagerPtr& manager,
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
         const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
         bool ipv6, bool isUAC, const NATEndpointOptions& natOptions);
 
     SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&, const Ice::Identity&,
@@ -116,6 +117,7 @@ public:
         const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&,
         const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
         const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
         bool isUAC, const NATEndpointOptions& natOptions);
 
     bool operator==(const SipSession &other) const;

commit df60142aabdb696d31e49ba5c3047e1bbd25e7ff
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Jul 14 16:04:25 2011 -0500

    Make helper functions for creating NOTIFY requests and their sipfrag bodies.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index d429b2f..09bc8d5 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -812,8 +812,6 @@ protected:
                     return Complete;
                 }
 
-                lg(Debug) << "to: " << to << " from: " << from << " replaces: " << replaces;
-
                 pj_str_t to_tag_str = pj_str((char*)to.c_str());
                 pj_str_t from_tag_str = pj_str((char*)from.c_str());
                 pj_str_t replaces_tag_str = pj_str((char*)replaces.c_str());
@@ -929,23 +927,9 @@ protected:
 
         // We need to send a NOTIFY to indicate how things went on the other leg.
         // XXX Once we have a subscription module written, we can actually use it.
-        pjsip_tx_data *tdata;
-        pjsip_dlg_create_request(mInv->dlg, pjsip_get_notify_method(), -1, &tdata);
-        pjsip_event_hdr *event = pjsip_event_hdr_create(tdata->pool);
-        pj_cstr(&event->event_type, "refer");
-        char idbuf[20];
-        pj_ansi_snprintf(idbuf, sizeof(idbuf), "%d", mReferCSeq);
-        pj_cstr(&event->id_param, idbuf);
-        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) event);
-        pjsip_sub_state_hdr *subState = pjsip_sub_state_hdr_create(tdata->pool);
-        pj_cstr(&subState->sub_state, "terminated");
-        pj_cstr(&subState->reason_param, "noresource");
-        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) subState);
 
-        pj_str_t type;
-        pj_cstr(&type, "message");
-        pj_str_t subtype;
-        pj_cstr(&subtype, "sipfrag;version=2.0");
+        pjsip_tx_data *tdata = createNotify();
+        
         try
         {
             if (mWasWithDestination)
@@ -961,10 +945,7 @@ protected:
         {
             lg(Debug) << "ConnectBridgedSessionsWithDestination sending 404 due to destination not found.";
 
-            pj_str_t bodyStr;
-            pj_cstr(&bodyStr, "SIP/2.0 404 Not Found");
-            pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
-            tdata->msg->body = body;
+            addNotifyBody(tdata, "SIP/2.0 404 Not Found");
             pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
             return Complete;
         }
@@ -972,18 +953,12 @@ protected:
         {
             lg(Debug) << "ConnectBridgedSessionsCallback sending 400 due to exception:  " << e.what();
 
-            pj_str_t bodyStr;
-            pj_cstr(&bodyStr, "SIP/2.0 400 Bad Request");
-            pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
-            tdata->msg->body = body;
+            addNotifyBody(tdata, "SIP/2.0 400 Bad Request");
             pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
             return Complete;
         }
 
-        pj_str_t bodyStr;
-        pj_cstr(&bodyStr, "SIP/2.0 200 OK");
-        pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
-        tdata->msg->body = body;
+        addNotifyBody(tdata, "SIP/2.0 200 OK");
         pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
         
         Ice::Current current;
@@ -993,6 +968,38 @@ protected:
     }
 
 private:
+
+    pjsip_tx_data* createNotify()
+    {
+        pjsip_tx_data *tdata;
+        pjsip_dlg_create_request(mInv->dlg, pjsip_get_notify_method(), -1, &tdata);
+
+        pjsip_event_hdr *event = pjsip_event_hdr_create(tdata->pool);
+        pj_strdup2(tdata->pool, &event->event_type, "refer");
+        char idbuf[20];
+        pj_ansi_snprintf(idbuf, sizeof(idbuf), "%d", mReferCSeq);
+        pj_strdup2(tdata->pool, &event->id_param, idbuf);
+        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) event);
+
+        pjsip_sub_state_hdr *subState = pjsip_sub_state_hdr_create(tdata->pool);
+        pj_strdup2(tdata->pool, &subState->sub_state, "terminated");
+        pj_strdup2(tdata->pool, &subState->reason_param, "noresource");
+        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) subState);
+
+        return tdata;
+    }
+    void addNotifyBody(pjsip_tx_data *tdata, const char *bodyText)
+    {
+        pj_str_t type;
+        pj_cstr(&type, "message");
+        pj_str_t subtype;
+        pj_cstr(&subtype, "sipfrag;version=2.0");
+
+        pj_str_t bodyStr;
+        pj_cstr(&bodyStr, bodyText);
+        pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
+        tdata->msg->body = body;
+    }
     /**
      * The INVITE session, which contains the dialog on which the
      * REFER was received.
@@ -1104,7 +1111,6 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     // We only support SIP URIs, anything else is rubbish to us
     if (!PJSIP_URI_SCHEME_IS_SIP(target_uri) && !PJSIP_URI_SCHEME_IS_SIPS(target_uri))
     {
-        // TODO: Place proper response code in here
         lg(Debug) << "handleRefer() sending 400 due to non-SIP URI. ";
         pjsip_dlg_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
         return;

commit 822fc2955d56d229e8fffa38fc6209c6228ffb15
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Jul 14 15:28:37 2011 -0500

    Use boost::split to get the parameters.
    
    This makes the code a LOT cleaner and also reduces assumptions regarding
    the number of parameters and their placement in the replaces header.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 330d356..d429b2f 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -22,6 +22,7 @@
 #include "SipStateReplicator.h"
 
 #include <IceUtil/UUID.h>
+#include <boost/algorithm/string.hpp>
 
 #include <AsteriskSCF/Core/Endpoint/EndpointIf.h>
 #include <AsteriskSCF/Core/Routing/RoutingIf.h>
@@ -779,12 +780,31 @@ protected:
                 // parse it out
                 std::string replaces_value_tmp = std::string(pj_strbuf(&mReplacesParam->value),
                         pj_strlen(&mReplacesParam->value));
-                std::string fromTagParamName(";from-tag=");
-                std::string toTagParamName(";to-tag=");
-                size_t from_tag_pos = replaces_value_tmp.find(fromTagParamName);
-                size_t to_tag_pos = replaces_value_tmp.find(toTagParamName);
+                std::vector<std::string> params;
 
-                if (from_tag_pos == std::string::npos || to_tag_pos == std::string::npos)
+                boost::split(params, replaces_value_tmp, boost::is_any_of(";"));
+
+                //The first value will be the actual replaces value.
+                std::string replaces = params.front();
+
+                std::string to;
+                std::string from;
+                std::string fromTagParamName("from-tag=");
+                std::string toTagParamName("to-tag=");
+                for(std::vector<std::string>::iterator iter = params.begin();
+                        iter != params.end(); ++iter)
+                {
+                    if (iter->compare(0, toTagParamName.size(), toTagParamName) == 0)
+                    {
+                        to = iter->substr(toTagParamName.size());
+                    }
+                    if (iter->compare(0, fromTagParamName.size(), fromTagParamName) == 0)
+                    {
+                        from = iter->substr(fromTagParamName.size());
+                    }
+                }
+
+                if (from.empty() || to.empty())
                 {
                     lg(Debug) << "handleRefer() sending 400 due to From or To missing. ";
                     pjsip_dlg_modify_response(mInv->dlg, mTdata, 400, NULL);
@@ -792,36 +812,11 @@ protected:
                     return Complete;
                 }
 
-                size_t firstTagPos = std::min(from_tag_pos, to_tag_pos);
-
-                // The position in the string where the value of the from tag starts.
-                size_t fromTagValuePos = from_tag_pos + fromTagParamName.size();
-
-                // The position in the string where the value of the to tag starts
-                size_t toTagValuePos = to_tag_pos + toTagParamName.size();
-
-                // The size of the tags. This isn't so much an accurate size as it is
-                // what we need to pass in to the substr() function in order to extract
-                // the proper value.
-                //
-                // If the from tag comes after the to tag, then the from tag extends until the
-                // end of the string. Otherwise, it only extends as far as the beginning of the
-                // to tag.
-                size_t fromTagValueSize =
-                    from_tag_pos > to_tag_pos ? std::string::npos : to_tag_pos - fromTagValuePos;
-
-                size_t toTagValueSize =
-                    to_tag_pos > from_tag_pos ? std::string::npos : from_tag_pos - toTagValuePos;
-
-                std::string to_tag_value = replaces_value_tmp.substr(toTagValuePos, toTagValueSize);
-                std::string from_tag_value = replaces_value_tmp.substr(fromTagValuePos, fromTagValueSize);
-                std::string replaces_value = replaces_value_tmp.substr(0, firstTagPos);
-
-                lg(Debug) << "to: " << to_tag_value << "from: " << from_tag_value << "replaces: " << replaces_value;
+                lg(Debug) << "to: " << to << " from: " << from << " replaces: " << replaces;
 
-                pj_str_t to_tag_str = pj_str((char*)to_tag_value.c_str());
-                pj_str_t from_tag_str = pj_str((char*)from_tag_value.c_str());
-                pj_str_t replaces_tag_str = pj_str((char*)replaces_value.c_str());
+                pj_str_t to_tag_str = pj_str((char*)to.c_str());
+                pj_str_t from_tag_str = pj_str((char*)from.c_str());
+                pj_str_t replaces_tag_str = pj_str((char*)replaces.c_str());
 
                 other_dlg = pjsip_ua_find_dialog(&replaces_tag_str, &to_tag_str, &from_tag_str, PJ_TRUE);
             }

commit ca24fcab3d34ddf6a69bc18fe0a769339b2756fe
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Jul 14 14:57:47 2011 -0500

    Allow for the to-tag and from-tag parameters in the replaces header to be in any order.
    
    This is my initial try at it, and I don't like it much. I think I'll try again using
    boost's string splitting algorithm.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index cd1bf04..330d356 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -779,8 +779,10 @@ protected:
                 // parse it out
                 std::string replaces_value_tmp = std::string(pj_strbuf(&mReplacesParam->value),
                         pj_strlen(&mReplacesParam->value));
-                size_t from_tag_pos = replaces_value_tmp.find(";from-tag=");
-                size_t to_tag_pos = replaces_value_tmp.find(";to-tag=");
+                std::string fromTagParamName(";from-tag=");
+                std::string toTagParamName(";to-tag=");
+                size_t from_tag_pos = replaces_value_tmp.find(fromTagParamName);
+                size_t to_tag_pos = replaces_value_tmp.find(toTagParamName);
 
                 if (from_tag_pos == std::string::npos || to_tag_pos == std::string::npos)
                 {
@@ -790,9 +792,32 @@ protected:
                     return Complete;
                 }
 
-                std::string to_tag_value = replaces_value_tmp.substr(to_tag_pos + 8, from_tag_pos - to_tag_pos - 8);
-                std::string from_tag_value = replaces_value_tmp.substr(from_tag_pos + 10);
-                std::string replaces_value = replaces_value_tmp.substr(0, to_tag_pos);
+                size_t firstTagPos = std::min(from_tag_pos, to_tag_pos);
+
+                // The position in the string where the value of the from tag starts.
+                size_t fromTagValuePos = from_tag_pos + fromTagParamName.size();
+
+                // The position in the string where the value of the to tag starts
+                size_t toTagValuePos = to_tag_pos + toTagParamName.size();
+
+                // The size of the tags. This isn't so much an accurate size as it is
+                // what we need to pass in to the substr() function in order to extract
+                // the proper value.
+                //
+                // If the from tag comes after the to tag, then the from tag extends until the
+                // end of the string. Otherwise, it only extends as far as the beginning of the
+                // to tag.
+                size_t fromTagValueSize =
+                    from_tag_pos > to_tag_pos ? std::string::npos : to_tag_pos - fromTagValuePos;
+
+                size_t toTagValueSize =
+                    to_tag_pos > from_tag_pos ? std::string::npos : from_tag_pos - toTagValuePos;
+
+                std::string to_tag_value = replaces_value_tmp.substr(toTagValuePos, toTagValueSize);
+                std::string from_tag_value = replaces_value_tmp.substr(fromTagValuePos, fromTagValueSize);
+                std::string replaces_value = replaces_value_tmp.substr(0, firstTagPos);
+
+                lg(Debug) << "to: " << to_tag_value << "from: " << from_tag_value << "replaces: " << replaces_value;
 
                 pj_str_t to_tag_str = pj_str((char*)to_tag_value.c_str());
                 pj_str_t from_tag_str = pj_str((char*)from_tag_value.c_str());

commit e28f2fa146b52be92b5df7640ab6f8df24cfd7c5
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Jul 14 14:18:50 2011 -0500

    Couple of cleanup and error checking additions.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 05bd952..cd1bf04 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -1078,8 +1078,6 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     // So with what we have here, this will work 99.99% of the time. If someone
     // tries to do something like refresh a subscription though, that will fail.
 
-    // TODO: Provide method to send back suitable response
-
     // Now parse the URI to get the actual target they want to refer to
     pjsip_uri *target_uri = static_cast<pjsip_uri *>(pjsip_parse_uri(inv->dlg->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0));
 
@@ -1112,7 +1110,7 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     }
     else
     {
-        target = std::string(pj_strbuf(&target_sip_uri->user), pj_strlen(&target_sip_uri->user));
+        target.assign(pj_strbuf(&target_sip_uri->user), pj_strlen(&target_sip_uri->user));
     }
 
     PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*) inv->mod_data[mModule.id];
@@ -1120,7 +1118,15 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
 
     //Create our initial response that we can modify in the queueable operation.
     pjsip_tx_data *tdata = 0;
-    pjsip_dlg_create_response(inv->dlg, rdata, 202, NULL, &tdata);
+    pj_status_t status = pjsip_dlg_create_response(inv->dlg, rdata, 202, NULL, &tdata);
+
+    if (status != PJ_SUCCESS)
+    {
+        //Hm, we couldn't create a response. Let's hope this actually works...
+        lg(Error) << "Unable to create 202 Accepted response in response to REFER (Out of memory?)";
+        pjsip_dlg_respond(inv->dlg, rdata, 500, NULL, NULL, NULL);
+        return;
+    }
 
     lg(Debug) << "Queuing a HandleReferOperation";
     enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, replaces_param, to_tag_param, from_tag_param, referredByVal, target, session, mSessionRouter, mModule.id), inv);

commit 442b31018e098f0a9135da0f82d76d92d2ae9286
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Jul 14 14:04:22 2011 -0500

    Parse and store the Referred-By header in a REFER.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 65533a6..05bd952 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -728,6 +728,7 @@ public:
             pjsip_param *replaces_param,
             pjsip_param *to_tag_param,
             pjsip_param *from_tag_param,
+            const std::string& referredBy,
             const std::string& target,
             const SipSessionPtr& session,
             const AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx>& sessionRouter,
@@ -735,7 +736,9 @@ public:
         : mInv(inv), mTsx(tsx), mTdata(tdata), 
         mReplacesParam(replaces_param ? new pjsip_param(*replaces_param) : NULL), 
         mToTagParam(to_tag_param ? new pjsip_param(*to_tag_param) : NULL),
-        mFromTagParam(from_tag_param ? new pjsip_param(*from_tag_param) : NULL), mTarget(target),
+        mFromTagParam(from_tag_param ? new pjsip_param(*from_tag_param) : NULL),
+        mReferredBy(referredBy),
+        mTarget(target),
         mSession(session), mSessionRouter(sessionRouter),
         mModuleId(moduleId), mReferCSeq(tsx->cseq), mWasWithDestination(false) {}
 
@@ -1000,6 +1003,13 @@ private:
      */
     pjsip_param *mFromTagParam;
     /**
+     * The content from the Referred-By header, if one existed.
+     * XXX We currently have this handy, but we don't actually do
+     * anything with it. This is because we don't have a way to place
+     * this information in the outgoing INVITE.
+     */
+    const std::string mReferredBy;
+    /**
      * The user portion of the URI in the Refer-To header of the
      * REFER that triggered this operation.
      */
@@ -1046,7 +1056,27 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
         return;
     }
 
+    pj_str_t referredBy;
+    pj_cstr(&referredBy, "Referred-By");
+    pjsip_generic_string_hdr *referredByHdr =
+        static_cast<pjsip_generic_string_hdr*>(pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &referredBy, NULL));
+
+    std::string referredByVal;
+    if (referredByHdr)
+    {
+        referredByVal.assign(pj_strbuf(&referredByHdr->hvalue), pj_strlen(&referredByHdr->hvalue));
+    }
+
     // TODO: Add support for subscription
+    //
+    // Currently, we send a NOTIFY as we are supposed to, but we don't actually
+    // have a full-blown subscription in use. This is for 2 reasons:
+    //
+    // 1. We don't have A subscription API defined yet.
+    // 2. REFERs are sort of fake subscriptions anyway.
+    //
+    // So with what we have here, this will work 99.99% of the time. If someone
+    // tries to do something like refresh a subscription though, that will fail.
 
     // TODO: Provide method to send back suitable response
 
@@ -1093,7 +1123,7 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     pjsip_dlg_create_response(inv->dlg, rdata, 202, NULL, &tdata);
 
     lg(Debug) << "Queuing a HandleReferOperation";
-    enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, replaces_param, to_tag_param, from_tag_param, target, session, mSessionRouter, mModule.id), inv);
+    enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, replaces_param, to_tag_param, from_tag_param, referredByVal, target, session, mSessionRouter, mModule.id), inv);
 }
 
 pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)

commit b09352f0fe360add36cc1977b6215781a33d42e1
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Jul 14 13:02:40 2011 -0500

    Add Subscription-State header to outbound NOTIFY.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index ad22db8..65533a6 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -913,7 +913,11 @@ protected:
         char idbuf[20];
         pj_ansi_snprintf(idbuf, sizeof(idbuf), "%d", mReferCSeq);
         pj_cstr(&event->id_param, idbuf);
-        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) event);
+        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) event);
+        pjsip_sub_state_hdr *subState = pjsip_sub_state_hdr_create(tdata->pool);
+        pj_cstr(&subState->sub_state, "terminated");
+        pj_cstr(&subState->reason_param, "noresource");
+        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) subState);
 
         pj_str_t type;
         pj_cstr(&type, "message");

commit 25b59a8ab75c40d5f80727357e9d939e827ab150
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Jul 14 10:51:15 2011 -0500

    Add the ;id parameter to the event header in the NOTIFY we send.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index d1f552e..ad22db8 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -737,7 +737,7 @@ public:
         mToTagParam(to_tag_param ? new pjsip_param(*to_tag_param) : NULL),
         mFromTagParam(from_tag_param ? new pjsip_param(*from_tag_param) : NULL), mTarget(target),
         mSession(session), mSessionRouter(sessionRouter),
-        mModuleId(moduleId), mWasWithDestination(false) {}
+        mModuleId(moduleId), mReferCSeq(tsx->cseq), mWasWithDestination(false) {}
 
     ~HandleReferOperation()
     {
@@ -910,6 +910,9 @@ protected:
         pjsip_dlg_create_request(mInv->dlg, pjsip_get_notify_method(), -1, &tdata);
         pjsip_event_hdr *event = pjsip_event_hdr_create(tdata->pool);
         pj_cstr(&event->event_type, "refer");
+        char idbuf[20];
+        pj_ansi_snprintf(idbuf, sizeof(idbuf), "%d", mReferCSeq);
+        pj_cstr(&event->id_param, idbuf);
         pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) event);
 
         pj_str_t type;
@@ -1010,6 +1013,10 @@ private:
      */
     const int mModuleId;
     /**
+     * The CSeq of the REFER
+     */
+    pj_int32_t mReferCSeq;
+    /**
      * Helps determine which end_* method to call on the session router when AMI completes.
      * XXX It may be more elegant to handle this by sending a cookie to the AMI method
      * instead.

commit fcac39e702d0f487a386d26ed8277ce6902ce607
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jul 11 15:46:06 2011 -0500

    Add version to sipfrag content type and remove unnecessary CRLFs.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 8883fc5..d1f552e 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -915,7 +915,7 @@ protected:
         pj_str_t type;
         pj_cstr(&type, "message");
         pj_str_t subtype;
-        pj_cstr(&subtype, "sipfrag");
+        pj_cstr(&subtype, "sipfrag;version=2.0");
         try
         {
             if (mWasWithDestination)
@@ -932,7 +932,7 @@ protected:
             lg(Debug) << "ConnectBridgedSessionsWithDestination sending 404 due to destination not found.";
 
             pj_str_t bodyStr;
-            pj_cstr(&bodyStr, "SIP/2.0 404 Not Found\r\n\r\n");
+            pj_cstr(&bodyStr, "SIP/2.0 404 Not Found");
             pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
             tdata->msg->body = body;
             pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
@@ -943,7 +943,7 @@ protected:
             lg(Debug) << "ConnectBridgedSessionsCallback sending 400 due to exception:  " << e.what();
 
             pj_str_t bodyStr;
-            pj_cstr(&bodyStr, "SIP/2.0 400 Bad Request\r\n\r\n");
+            pj_cstr(&bodyStr, "SIP/2.0 400 Bad Request");
             pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
             tdata->msg->body = body;
             pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
@@ -951,7 +951,7 @@ protected:
         }
 
         pj_str_t bodyStr;
-        pj_cstr(&bodyStr, "SIP/2.0 200 OK\r\n\r\n");
+        pj_cstr(&bodyStr, "SIP/2.0 200 OK");
         pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
         tdata->msg->body = body;
         pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);

commit da14216b9dc0c8f37efd5d3a1a4d5591245b139d
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jul 11 15:26:19 2011 -0500

    Send an early 202 and then send a NOTIFY later...like you're supposed to do.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 9f2fe59..8883fc5 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -840,6 +840,9 @@ protected:
             PJSipSessionModInfo *other_session_mod_info = (PJSipSessionModInfo*)other_inv->mod_data[mModuleId];
             SipSessionPtr other_session = other_session_mod_info->getSessionPtr();
 
+            //Go ahead and send a 202 for the REFER. We can send a NOTIFY later to indicate if something
+            //on the outbound leg went awry.
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
             try
             {
                 std::string operationId = ::IceUtil::generateUUID();
@@ -862,6 +865,10 @@ protected:
         }
         else
         {
+            //Go ahead and send a 202 for the REFER. We can send a NOTIFY later to indicate if something
+            //on the outbound leg went awry.
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+
             // Now that we have the target user we can pass this into routing and go on our marry way
             try
             {
@@ -896,6 +903,19 @@ protected:
     {
         assert(mAsyncResult);
         SessionRouterPrx router = SessionRouterPrx::uncheckedCast(mAsyncResult->getProxy());
+
+        // We need to send a NOTIFY to indicate how things went on the other leg.
+        // XXX Once we have a subscription module written, we can actually use it.
+        pjsip_tx_data *tdata;
+        pjsip_dlg_create_request(mInv->dlg, pjsip_get_notify_method(), -1, &tdata);
+        pjsip_event_hdr *event = pjsip_event_hdr_create(tdata->pool);
+        pj_cstr(&event->event_type, "refer");
+        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) event);
+
+        pj_str_t type;
+        pj_cstr(&type, "message");
+        pj_str_t subtype;
+        pj_cstr(&subtype, "sipfrag");
         try
         {
             if (mWasWithDestination)
@@ -911,18 +931,30 @@ protected:
         {
             lg(Debug) << "ConnectBridgedSessionsWithDestination sending 404 due to destination not found.";
 
-            pjsip_dlg_modify_response(mInv->dlg, mTdata, 404, NULL);
-            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+            pj_str_t bodyStr;
+            pj_cstr(&bodyStr, "SIP/2.0 404 Not Found\r\n\r\n");
+            pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
+            tdata->msg->body = body;
+            pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
             return Complete;
         }
         catch (const std::exception &e)
         {
             lg(Debug) << "ConnectBridgedSessionsCallback sending 400 due to exception:  " << e.what();
-            pjsip_dlg_modify_response(mInv->dlg, mTdata, 400, NULL);
-            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+
+            pj_str_t bodyStr;
+            pj_cstr(&bodyStr, "SIP/2.0 400 Bad Request\r\n\r\n");
+            pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
+            tdata->msg->body = body;
+            pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
             return Complete;
         }
-        pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+
+        pj_str_t bodyStr;
+        pj_cstr(&bodyStr, "SIP/2.0 200 OK\r\n\r\n");
+        pjsip_msg_body *body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &bodyStr);
+        tdata->msg->body = body;
+        pjsip_dlg_send_request(mInv->dlg, tdata, -1, NULL);
         
         Ice::Current current;
         lg(Debug) << "ConnectBridgedSessionsCallback calling session->stop(). ";
@@ -1047,7 +1079,7 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
 
     //Create our initial response that we can modify in the queueable operation.
     pjsip_tx_data *tdata = 0;
-    pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
+    pjsip_dlg_create_response(inv->dlg, rdata, 202, NULL, &tdata);
... 13121 lines suppressed ...


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list