Added possibility to modify parameters in call.route message.

Added option to call alternatives for an account.
Improved reload.


git-svn-id: http://yate.null.ro/svn/yate/trunk@3378 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
andrei 2010-06-15 07:32:09 +00:00
parent 78d100265f
commit 4eb1b4bbfe
2 changed files with 272 additions and 87 deletions

View File

@ -16,10 +16,36 @@
;
; route: int: Priority of the call.route handler
;route=100
;
; file: string. An auxiliary conf file used to save and load from it autocreated and registered entries
; If file don't exists the registered entities will be lost on reload
;file=filename
; you have to put username as a category and password into key password
; if password is missing the module will only register but not authenticate
; if password exists and is empty will blindly authenticate anybody
;[username]
;password=something
; alternatives: list of called party numbers separated by coma
; Note if multiple users share the same party number the call will go to all users.
;alternatives= num1,num2,....
;
; Set/Modify call.route parameters when the caller matches this section
; You can put call.route replacement ${variables} on the right side
; Note: Any parameter except for "password" and "alternatives" will be used for set/modify
;
; Ex:
; Modify caller name
;callername=name
;
; Modify caller number
;caller=number
;
; Replacement example
;callername=John Doe from ${address}
;
;param=value

View File

@ -5,7 +5,7 @@
* Ask for a registration from this module.
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2006 Null Team
* Copyright (C) 2004-2010 Null Team
*
* 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
@ -27,13 +27,6 @@
using namespace TelEngine;
namespace { // anonymous
Mutex lmutex(false,"RegFile");
static Configuration s_cfg(Engine::configFile("regfile"));
static const String s_general = "general";
static bool s_create = false;
class AuthHandler : public MessageHandler
{
@ -62,9 +55,11 @@ public:
class RouteHandler : public MessageHandler
{
public:
RouteHandler(const char *name, unsigned prio = 100)
: MessageHandler(name,prio) { }
RouteHandler(const char *name, unsigned prio = 100);
~RouteHandler();
virtual bool received(Message &msg);
private:
ObjList* m_skip;
};
class StatusHandler : public MessageHandler
@ -75,144 +70,308 @@ public:
virtual bool received(Message &msg);
};
class ExpireHandler : public MessageHandler
{
public:
ExpireHandler()
: MessageHandler("engine.timer",100) { }
virtual bool received(Message &msg);
};
class ExpandedUser : public ObjList
{
public:
inline ExpandedUser(const String& username)
: m_username(username) {}
virtual const String& toString () const
{ return m_username; }
private:
String m_username;
};
class RegfilePlugin : public Plugin
{
public:
RegfilePlugin();
~RegfilePlugin(){}
~RegfilePlugin();
virtual void initialize();
void populate();
private:
AuthHandler *m_authhandler;
bool m_init;
};
Mutex s_mutex(false,"RegFile");
static Configuration s_cfg(Engine::configFile("regfile"));
static Configuration s_accounts;
static bool s_create = false;
static const String s_general = "general";
static ObjList s_expand;
bool expired(const NamedList& list, unsigned int time)
{
// If eTime is 0 the registration will never expire
unsigned int eTime = list.getIntValue("expires",0);
return eTime && eTime < time;
}
bool AuthHandler::received(Message &msg)
{
String username(msg.getValue("username"));
if (username.null() || username == s_general)
return false;
const NamedList* sect = s_cfg.getSection(username);
if (sect) {
const String* pass = sect->getParam("password");
if (!pass)
return false;
msg.retValue() = *pass;
return true;
}
return false;
};
Lock lock(s_mutex);
const NamedList* usr = s_cfg.getSection(username);
if (!usr)
return false;
const String* pass = usr->getParam("password");
if (!pass)
return false;
msg.retValue() = *pass;
return true;
}
bool RegistHandler::received(Message &msg)
{
String username(msg.getValue("username"));
if (username.null() || username == s_general)
return false;
const char *driver = msg.getValue("driver");
const char *data = msg.getValue("data");
const char* driver = msg.getValue("driver");
const char* data = msg.getValue("data");
if (!data)
return false;
Lock lock(lmutex);
Lock lock(s_mutex);
int expire = msg.getIntValue("expires",0);
NamedList* sect = s_cfg.getSection(username);
if (s_create && !sect) {
Debug("RegFile",DebugNote,"Auto creating new user '%s'",username.c_str());
s_cfg.createSection(username);
sect = s_cfg.getSection(username);
sect = new NamedList(username);
Debug("RegFile",DebugInfo,"Auto creating new user %s",username.c_str());
}
if (sect) {
Debug("RegFile",DebugInfo,"Registered '%s' via '%s'",username.c_str(),data);
sect->setParam("driver",driver);
sect->setParam("data",data);
return true;
}
return false;
};
if (!sect)
return false;
s_accounts.createSection(*sect);
NamedList* s = s_accounts.getSection(*sect);
if (driver)
s->setParam("driver",driver);
s->setParam("data",data);
if (expire)
s->setParam("expires",String(msg.msgTime().sec() + expire));
Debug("RegFile",DebugAll,"Registered user %s via %s",username.c_str(),data);
return true;
}
bool UnRegistHandler::received(Message &msg)
{
String username(msg.getValue("username"));
if (username.null() || username == s_general)
return false;
Lock lock(lmutex);
if (s_cfg.getSection(username)) {
Debug("RegFile",DebugInfo,"Unregistered '%s'",username.c_str());
s_cfg.clearKey(username,"data");
return true;
}
return false;
};
Lock lock(s_mutex);
NamedList* nl = s_accounts.getSection(username);
if (!nl)
return false;
Debug("RegFile",DebugAll,"Removing user %s, reson unregistered",username.c_str());
s_accounts.clearSection(username);
return true;
}
RouteHandler::RouteHandler(const char *name, unsigned prio)
: MessageHandler(name,prio)
{
m_skip = String("alternatives,password").split(',');
}
RouteHandler::~RouteHandler()
{
TelEngine::destruct(m_skip);
}
bool RouteHandler::received(Message &msg)
{
String user = msg.getValue("caller");
Lock lock(s_mutex);
NamedList* params = 0;
if (user) {
params = s_cfg.getSection(user);
if (params) {
unsigned int n = params->length();
for (unsigned int i = 0; i < n; i++) {
const NamedString* s = params->getParam(i);
if (s && !m_skip->find(s->name())) {
String value = *s;
msg.replaceParams(value);
msg.setParam(s->name(),value);
}
}
}
}
String username(msg.getValue("called"));
if (username.null() || username == s_general)
return false;
Lock lock(lmutex);
const NamedList* sect = s_cfg.getSection(username);
if (sect) {
const char* data = sect->getValue("data");
if (data) {
Debug("RegFile",DebugInfo,"Routed '%s' via '%s'",username.c_str(),data);
msg.retValue() = data;
msg.setParam("driver",sect->getValue("driver"));
return true;
NamedList* ac = s_accounts.getSection(username);
while (true) {
String data;
if (!ac) {
if (s_cfg.getSection(username))
break;
ObjList* o = s_expand.find(username);
if (!o)
break;
ExpandedUser* eu = static_cast<ExpandedUser*>(o->get());
if (!eu)
break;
String d;
int count = 0;
for (ObjList* ob = eu->skipNull(); ob;ob = ob->skipNext()) {
String* s = static_cast<String*>(ob->get());
if (!s)
continue;
NamedList* n = s_accounts.getSection(*s);
if (!n)
continue;
if (count > 0)
d << " ";
d << n->getValue("data");
count ++;
}
if (count > 1)
data = "fork ";
data << d;
} else {
data = ac->getValue("data");
msg.copyParams(*ac,"driver");
}
// signal to other modules we know about this user but it's offline
msg.setParam("error","offline");
msg.retValue() = data;
Debug("RegFile",DebugInfo,"Routed '%s' via '%s'",username.c_str(),data.c_str());
return true;
}
msg.setParam("error","offline");
return false;
};
}
static int s_count = 0;
bool ExpireHandler::received(Message &msg)
{
if ((s_count = (s_count+1) % 30)) // Check for timeouts once at 30 seconds
return false;
u_int64_t time = msg.msgTime().sec();
Lock lock(s_mutex);
int count = s_accounts.sections();
for (int i = 0;i < count;) {
NamedList* sec = s_accounts.getSection(i);
if (sec && *sec != s_general && expired(*sec,time)) {
Debug("RegFile",DebugAll,"Removing user %s, Reson: Registration expired",sec->c_str());
s_accounts.clearSection(*sec);
count--;
} else
i++;
}
if (s_accounts)
s_accounts.save();
return false;
}
bool StatusHandler::received(Message &msg)
{
bool first = true;
String dest(msg.getValue("module"));
if (dest && (dest != "regfile") && (dest != "misc"))
return false;
Lock lock(lmutex);
unsigned int n = s_cfg.sections();
if (!s_cfg.getSection(0))
--n;
msg.retValue() << "name=regfile,type=misc;users=" << n << ",create=" << s_create;
if (msg.getBoolValue("details",true)) {
msg.retValue() << ";";
bool first = true;
for (unsigned int i=0;i<s_cfg.sections();i++) {
NamedList *user = s_cfg.getSection(i);
if (!user || (*user == s_general))
continue;
const char* data = s_cfg.getValue(*user,"data");
if (first)
first = false;
else
msg.retValue() << ",";
msg.retValue() << *user << "=" << (data ? data : "offline");
}
return false;
Lock lock(s_mutex);
msg.retValue() << "name=regfile,type=misc;users=" << s_accounts.sections() << ";";
unsigned int count = s_accounts.sections();
for (unsigned int i = 0;i < count; i ++) {
NamedList* ac = s_accounts.getSection(i);
if (!ac)
continue;
const String data = ac->getValue("data");
if (first)
first = false;
else
msg.retValue() << ",";
if (data)
msg.retValue() << *ac << "=" << data;
}
msg.retValue() << "\r\n";
return false;
}
RegfilePlugin::RegfilePlugin()
: m_authhandler(0)
: m_init(false)
{
Output("Loaded module Registration from file");
}
RegfilePlugin::~RegfilePlugin()
{
Output("Unload module Registration from file");
if (s_accounts)
s_accounts.save();
}
void RegfilePlugin::initialize()
{
Output("Initializing module Register for file");
if (!m_authhandler) {
s_cfg.load();
s_create = s_cfg.getBoolValue("general","autocreate");
Engine::install(m_authhandler = new AuthHandler("user.auth",s_cfg.getIntValue("general","auth",100)));
Output("Initializing module Register from file");
Lock lock(s_mutex);
s_cfg.load();
if (!m_init) {
m_init = true;
s_create = s_cfg.getBoolValue("general","autocreate",false);
String conf = s_cfg.getValue("general","file");
if (conf) {
s_accounts = conf;
s_accounts.load();
}
Engine::install(new AuthHandler("user.auth",s_cfg.getIntValue("general","auth",100)));
Engine::install(new RegistHandler("user.register",s_cfg.getIntValue("general","register",100)));
Engine::install(new UnRegistHandler("user.unregister",s_cfg.getIntValue("general","register",100)));
Engine::install(new RouteHandler("call.route",s_cfg.getIntValue("general","route",100)));
Engine::install(new StatusHandler("engine.status"));
Engine::install(new ExpireHandler());
}
populate();
}
void RegfilePlugin::populate()
{
s_expand.clear();
int count = s_cfg.sections();
for (int i = 0;i < count; i++) {
NamedList* nl = s_cfg.getSection(i);
if (!nl || *nl == s_general)
continue;
String* ids = nl->getParam("alternatives");
if (!ids)
continue;
ObjList* ob = ids->split(',');
for (ObjList* o = ob->skipNull(); o;o = o->skipNext()) {
String* sec = static_cast<String*>(o->get());
if (!sec)
continue;
ObjList* ret = s_expand.find(*sec);
ExpandedUser* eu = 0;
if (!ret) {
eu = new ExpandedUser(*sec);
s_expand.append(eu);
} else
eu = static_cast<ExpandedUser*>(ret->get());
eu->append(new String(*nl));
}
}
if (s_create)
return;
count = s_accounts.sections();
for (int i = 0;i < count;i++) {
NamedList* nl = s_accounts.getSection(i);
if (!nl)
continue;
if (s_cfg.getSection(*nl))
continue;
s_accounts.clearSection(*nl);
count--;
i--;
}
}