[ previous ] [ next ] [ threads ]
 To :  yate@v..., Diana Cionoiu <diana-liste@v...>
 From :  Maciek Kaminski <maciejka@t...>
 Subject :  transfer module
 Date :  Mon, 04 Jul 2005 11:04:09 +0200
Low level transfers implmentation. Module introduces two kinds of messages:
call.transfer - transfers both ends of a call from userData() to 
transferto1 and transferto2. On success sets transferedtargetid1 and 
transferedtargetid2 to ids of destination channels.
call.connect - connects _existing_ channels of ids: id1 and id2

It uses HashTable.cpp. You will find it in rmodule email.

mk



/**
 * transfer.cpp
 * This file is part of the YATE Project http://YATE.null.ro
 *
 * Transfer plugin
 *
 * Copyright (C) 2005 Maciek Kaminski 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include 
#include 

#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace TelEngine;

static HashTable s_disconnects2catch;

struct TransferInfo {
    String m_transferto;
    CallEndpoint* m_de;
    String targetid;
    TransferInfo(const String& transferto, CallEndpoint* de) : m_transferto(transferto), m_de(de), targetid(0) {}
};

class ConnectHandler : public MessageHandler
{
public:
    ConnectHandler() : MessageHandler("call.connect") { }
    virtual bool received(Message &msg);
};

class TransferHandler : public MessageHandler
{
public:
    TransferHandler() : MessageHandler("call.transfer") { }
    virtual bool received(Message &msg);
};

class DisconnectHandler : public MessageHandler
{
public:
    DisconnectHandler() : MessageHandler("chan.disconnected") { }
    virtual bool received(Message &msg);
};

class TransferPlugin : public Plugin
{
public:
    TransferPlugin();
    virtual void initialize();
    static void TransferPlugin::hook(Message &msg, bool result);
private:
    bool m_first;
    TransferHandler* m_transfer_handler;
    DisconnectHandler* m_disconnect_handler;
    ConnectHandler* m_connect_handler;
};

TransferPlugin::TransferPlugin()    
  : m_first(true)
{
    Output("Loaded module Transfer");    
}

bool TransferHandler::received(Message &msg)
{

    CallEndpoint *dd2;
    CallEndpoint *dd1 = static_cast(msg.userData());
    if(dd1) {
        dd2 = dd1->getPeer();
	if(!dd2) {
	  Debug(DebugWarn,"Empty peer data channel in transfer request!");
	  return false;
	}
    } else {
	Debug(DebugWarn,"Empty data channel in transfer request!");
        return false;
    }

    String id = dd1->id();
    String targetid = dd2->id();

    String transferto1(msg.getValue("transferto1"));
    String transferto2(msg.getValue("transferto2"));

    Debug("TransferHandler", DebugAll, "Transfer request channel %s to: %s and channel %s to: %s", 
	  id.c_str(), transferto1.c_str(), targetid.c_str(), transferto2.c_str());

    Message m("call.execute");
    m.addParam("id", id);
    m.addParam("callto", transferto1);
    m.userData(dd1);
    TransferInfo info(transferto2, dd2);
    s_disconnects2catch.put(targetid, &info);
    if(Engine::dispatch(m)) {
      s_disconnects2catch.del(targetid);
      msg.addParam("transferedtargetid1", m.getParam("targetid")->c_str());
      msg.addParam("transferedtargetid2", info.targetid.c_str());
      return true;
    } else {
      Debug("TransferHandler", DebugWarn,"Message 'call.execute' failed while transfering!");
      return false;
    }
}

bool DisconnectHandler::received(Message &msg) {

  String id(msg.getValue("id"));

  TransferInfo *ti = (TransferInfo *) s_disconnects2catch.get(id); 
  if(ti) {
    Debug("TransferModule", DebugAll, "Transfer info for %s found: %s", id.c_str(), ti->m_transferto.c_str());
    Message m("call.execute");
    m.addParam("id", id);
    m.addParam("callto", ti->m_transferto);
    m.userData(ti->m_de);
    if(!Engine::dispatch(m)) {     
      Debug("TransferModule", DebugWarn,"Message 'call.execute' inside disconnect failed while transfering!");
    } else {
      ti->targetid = m.getParam("targetid");
    }
    return true;
  }
  Debug("TransferModule", DebugAll, "Transfer info for %s(%s) not found.", msg.c_str(), id.c_str());
  return false;
}

bool ConnectHandler::received(Message &msg) {
  String id1(msg.getValue("id1"));
  String id2(msg.getValue("id2"));


  Debug("TransferModule", DebugAll, "Connect request for: %s and %s", id1.c_str(), id2.c_str());
  
  Message m("chan.locate");
  m.addParam("id", id1);
  if(!Engine::dispatch(m)) {     
      Debug("TransferModule", DebugWarn,"Can't find channel: %s while connecting.", id1.c_str());
  } else {
    CallEndpoint *dd1 = static_cast(m.userData());
    Message m("chan.locate");
    m.addParam("id", id2);
    if(!Engine::dispatch(m)) {     
      Debug("TransferModule", DebugWarn,"Can't find second channel: %s while connecting.", id2.c_str());
    } else {
      CallEndpoint *dd2 = static_cast(m.userData());
      return dd1->connect(dd2);
    }
  }
  return false;
}

void TransferPlugin::initialize()
{
  if (m_first) {
    m_first = false;
    Output("Initializing module Transfer");
    m_transfer_handler = new TransferHandler;
    Engine::install(m_transfer_handler);
    m_disconnect_handler = new DisconnectHandler;
    Engine::install(m_disconnect_handler);
    m_connect_handler = new ConnectHandler;
    Engine::install(m_connect_handler);
  }
}


INIT_PLUGIN(TransferPlugin);

/* vi: set ts=8 sw=4 sts=4 noet: */