summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--misc/freeswitch/scripts/common/group.lua46
-rw-r--r--misc/freeswitch/scripts/common/object.lua106
-rw-r--r--misc/freeswitch/scripts/dialplan/dialplan.lua125
-rw-r--r--misc/freeswitch/scripts/dialplan/functions.lua33
-rw-r--r--misc/freeswitch/scripts/dialplan_default.lua2
5 files changed, 187 insertions, 125 deletions
diff --git a/misc/freeswitch/scripts/common/group.lua b/misc/freeswitch/scripts/common/group.lua
index ac2f542..db56129 100644
--- a/misc/freeswitch/scripts/common/group.lua
+++ b/misc/freeswitch/scripts/common/group.lua
@@ -87,6 +87,7 @@ function Group.name_id_by_member(self, member_id, member_type)
return group_names, group_ids;
end
+
function Group.permission_targets(self, group_ids, permission)
if not group_ids or not permission then
return {};
@@ -100,18 +101,36 @@ function Group.permission_targets(self, group_ids, permission)
AND `b`.`active` IS TRUE \
GROUP BY `a`.`target_group_id` LIMIT ' .. MAX_GROUP_MEMBERSHIPS;
-
- local groups = {};
+ local group_names = {};
+ local group_ids = {};
self.database:query(sql_query, function(account_entry)
- groups[account_entry.id] = account_entry.name;
+ table.insert(group_names, account_entry.name);
+ table.insert(group_ids, tonumber(account_entry.id));
end);
- return groups;
+ return group_names, group_ids;
+end
+
+
+function Group.is_target(self, group_id, permission)
+ if not group_id or not permission then
+ return nil;
+ end
+
+ local sql_query = 'SELECT `b`.`name` \
+ FROM `group_permissions` `a` \
+ JOIN `groups` `b` ON `b`.`id` = `a`.`target_group_id` \
+ WHERE `a`.`permission` = ' .. self.database:escape(permission, '"') .. ' \
+ AND `a`.`group_id` = ' .. tonumber(group_id) .. ' \
+ AND `b`.`active` IS TRUE \
+ LIMIT 1';
+
+ return self.database:query_return_value(sql_query);
end
-function Group.combine(self, ...)
+function Group.union(self, ...)
local groups = {};
local group_sets = {...};
for set_index=1, #group_sets do
@@ -130,3 +149,20 @@ function Group.combine(self, ...)
return group_ids;
end
+
+
+function Group.intersection(self, set_one, set_two)
+ local basic_set = {};
+ for index=1, #set_one do
+ basic_set[set_one[index]] = true;
+ end
+
+ local final_set = {};
+ for index=1, #set_two do
+ if basic_set[set_two[index]] then
+ table.insert(final_set, set_two[index]);
+ end
+ end
+
+ return final_set;
+end
diff --git a/misc/freeswitch/scripts/common/object.lua b/misc/freeswitch/scripts/common/object.lua
new file mode 100644
index 0000000..5183b9f
--- /dev/null
+++ b/misc/freeswitch/scripts/common/object.lua
@@ -0,0 +1,106 @@
+-- Gemeinschaft 5 module: object class
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+Object = {}
+
+-- create object object ;)
+function Object.new(self, arg)
+ arg = arg or {}
+ object = arg.object or {}
+ setmetatable(object, self);
+ self.__index = self;
+ self.class = 'object';
+ self.log = arg.log;
+ self.database = arg.database;
+ return object;
+end
+
+-- find object
+function Object.find(self, attributes)
+ if not attributes.class then
+ return nil;
+ end
+
+ local object = nil;
+
+ require 'common.str';
+ local class = common.str.downcase(attributes.class);
+
+ if class == 'user' then
+ require 'dialplan.user';
+ if tonumber(attributes.id) then
+ object = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_id(attributes.id);
+ elseif not common.str.blank(attributes.uuid) then
+ object = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_uuid(attributes.uuid);
+ end
+
+ if object then
+ object.user_groups = object:list_groups();
+ end
+ elseif class == 'tenant' then
+ require 'dialplan.tenant';
+ if tonumber(attributes.id) then
+ object = dialplan.tenant.Tenant:new{ log = self.log, database = self.database }:find_by_id(attributes.id);
+ elseif not common.str.blank(attributes.uuid) then
+ object = dialplan.tenant.Tenant:new{ log = self.log, database = self.database }:find_by_uuid(attributes.uuid);
+ end
+ elseif class == 'sipaccount' then
+ require 'common.sip_account';
+ if not common.str.blank(attributes.auth_name) then
+ object = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_auth_name(attributes.auth_name, attributes.domain);
+ elseif tonumber(attributes.id) then
+ object = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_id(attributes.id);
+ elseif not common.str.blank(attributes.uuid) then
+ object = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_uuid(attributes.uuid);
+ end
+
+ if object then
+ object.owner = self:find{class = object.record.sip_accountable_type, id = tonumber(object.record.sip_accountable_id)};
+ end
+ elseif class == 'huntgroup' then
+ require 'dialplan.hunt_group';
+
+ if tonumber(attributes.id) then
+ object = dialplan.hunt_group.HuntGroup:new{ log = self.log, database = self.database }:find_by_id(attributes.id);
+ elseif not common.str.blank(attributes.uuid) then
+ object = dialplan.hunt_group.HuntGroup:new{ log = self.log, database = self.database }:find_by_uuid(attributes.uuid);
+ end
+
+ if object then
+ object.owner = self:find{class = 'tenant', id = tonumber(object.record.tenant_id)};
+ end
+ elseif class == 'automaticcalldistributor' then
+ require 'dialplan.acd';
+
+ if tonumber(attributes.id) then
+ object = dialplan.acd.AutomaticCallDistributor:new{ log = self.log, database = self.database, domain = self.domain }:find_by_id(attributes.id);
+ elseif not common.str.blank(attributes.uuid) then
+ object = dialplan.acd.AutomaticCallDistributor:new{ log = self.log, database = self.database, domain = self.domain }:find_by_uuid(attributes.uuid);
+ end
+
+ if object then
+ object.owner = self:find{class = object.record.automatic_call_distributorable_type, id = tonumber(object.record.automatic_call_distributorable_id)};
+ end
+ elseif class == 'faxaccount' then
+ require 'dialplan.fax';
+ if tonumber(attributes.id) then
+ fax_account = dialplan.fax.Fax:new{ log = self.log, database = self.database }:find_by_id(attributes.id);
+ elseif not common.str.blank(attributes.uuid) then
+ fax_account = dialplan.fax.Fax:new{ log = self.log, database = self.database }:find_by_uuid(attributes.uuid);
+ end
+
+ if object then
+ object.owner = self:find{class = fax_account.record.fax_accountable_type, id = tonumber(fax_account.record.fax_accountable_id)};
+ end
+ end
+
+ if object then
+ require 'common.group';
+ object.groups, object.group_ids = common.group.Group:new{ log = self.log, database = self.database }:name_id_by_member(object.id, object.class);
+ end
+
+ return object;
+end
diff --git a/misc/freeswitch/scripts/dialplan/dialplan.lua b/misc/freeswitch/scripts/dialplan/dialplan.lua
index 2e15124..ffad4da 100644
--- a/misc/freeswitch/scripts/dialplan/dialplan.lua
+++ b/misc/freeswitch/scripts/dialplan/dialplan.lua
@@ -144,119 +144,24 @@ function Dialplan.auth_gateway(self)
end
-function Dialplan.object_find(self, class, identifier, auth_name)
- require 'common.str'
- class = common.str.downcase(class);
-
- require 'common.group';
- local group_class = common.group.Group:new{ log = self.log, database = self.database };
-
- if class == 'user' then
- require 'dialplan.user'
- local user = nil;
- if type(identifier) == 'number' then
- user = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_id(identifier);
- else
- user = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_uuid(identifier);
- end
-
- if user then
- user.user_groups = user:list_groups();
- user.groups, user.group_ids = group_class:name_id_by_member(user.id, user.class);
- end
-
- return user;
- elseif class == 'tenant' then
- require 'dialplan.tenant'
- local tenant = nil;
- if type(identifier) == 'number' then
- tenant = dialplan.tenant.Tenant:new{ log = self.log, database = self.database }:find_by_id(identifier);
- else
- tenant = dialplan.tenant.Tenant:new{ log = self.log, database = self.database }:find_by_uuid(identifier);
- end
-
- if tenant then
- tenant.groups, tenant.group_ids = group_class:name_id_by_member(tenant.id, tenant.class);
- end
-
- return tenant;
- elseif class == 'sipaccount' then
- require 'common.sip_account'
- local sip_account = nil;
- if auth_name then
- sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_auth_name(auth_name, identifier);
- elseif type(identifier) == 'number' then
- sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_id(identifier);
- else
- sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_uuid(identifier);
- end
- if sip_account then
- sip_account.owner = self:object_find(sip_account.record.sip_accountable_type, tonumber(sip_account.record.sip_accountable_id));
- sip_account.groups, sip_account.group_ids = group_class:name_id_by_member(sip_account.id, sip_account.class);
- end
- return sip_account;
- elseif class == 'huntgroup' then
- require 'dialplan.hunt_group'
-
- local hunt_group = nil;
- if type(identifier) == 'number' then
- hunt_group = dialplan.hunt_group.HuntGroup:new{ log = self.log, database = self.database }:find_by_id(identifier);
- else
- hunt_group = dialplan.hunt_group.HuntGroup:new{ log = self.log, database = self.database }:find_by_uuid(identifier);
- end
-
- if hunt_group then
- hunt_group.owner = self:object_find('tenant', tonumber(hunt_group.record.tenant_id));
- hunt_group.groups, hunt_group.group_ids = group_class:name_id_by_member(hunt_group.id, hunt_group.class);
- end
-
- return hunt_group;
- elseif class == 'automaticcalldistributor' then
- require 'dialplan.acd'
-
- local acd = nil;
- if type(identifier) == 'number' then
- acd = dialplan.acd.AutomaticCallDistributor:new{ log = self.log, database = self.database, domain = self.domain }:find_by_id(identifier);
- else
- acd = dialplan.acd.AutomaticCallDistributor:new{ log = self.log, database = self.database, domain = self.domain }:find_by_uuid(identifier);
- end
-
- if acd then
- acd.owner = self:object_find(acd.record.automatic_call_distributorable_type, tonumber(acd.record.automatic_call_distributorable_id));
- acd.groups, acd.group_ids = group_class:name_id_by_member(acd.id, acd.class);
- end
-
- return acd;
- elseif class == 'faxaccount' then
- require 'dialplan.fax'
- local fax_account = nil;
- if type(identifier) == 'number' then
- fax_account = dialplan.fax.Fax:new{ log = self.log, database = self.database }:find_by_id(identifier);
- else
- fax_account = dialplan.fax.Fax:new{ log = self.log, database = self.database }:find_by_uuid(identifier);
- end
- if fax_account then
- fax_account.owner = self:object_find(fax_account.record.fax_accountable_type, tonumber(fax_account.record.fax_accountable_id));
- fax_account.groups, fax_account.group_ids = group_class:name_id_by_member(fax_account.id, fax_account.class);
- end
-
- return fax_account;
- end
+function Dialplan.object_find(self, arguments)
+ require 'common.object';
+ return common.object.Object:new{ log = self.log, database = self.database}:find(arguments);
end
function Dialplan.retrieve_caller_data(self)
require 'common.str'
- self.caller.caller_phone_numbers_hash = {}
+ self.caller.caller_phone_numbers_hash = {};
-- TODO: Set auth_account on transfer initiated by calling party
if not common.str.blank(self.caller.dialed_sip_user) then
- self.caller.auth_account = self:object_find('sipaccount', self.caller.dialed_domain, self.caller.dialed_sip_user);
+ self.caller.auth_account = self:object_find{class = 'sipaccount', domain = self.caller.dialed_domain, auth_account = self.caller.dialed_sip_user};
if self.caller.set_auth_account then
self.caller:set_auth_account(self.caller.auth_account);
end
elseif not common.str.blank(self.caller.auth_account_type) and not common.str.blank(self.caller.auth_account_uuid) then
- self.caller.auth_account = self:object_find(self.caller.auth_account_type, self.caller.auth_account_uuid);
+ self.caller.auth_account = self:object_find{class = self.caller.auth_account_type, uuid = self.caller.auth_account_uuid};
if self.caller.set_auth_account then
self.caller:set_auth_account(self.caller.auth_account);
end
@@ -274,7 +179,7 @@ function Dialplan.retrieve_caller_data(self)
end
if not common.str.blank(self.caller.account_type) and not common.str.blank(self.caller.account_uuid) then
- self.caller.account = self:object_find(self.caller.account_type, self.caller.account_uuid);
+ self.caller.account = self:object_find{class = self.caller.account_type, uuid = self.caller.account_uuid};
if self.caller.account then
require 'common.phone_number'
self.caller.caller_phone_numbers = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:list_by_owner(self.caller.account.id, self.caller.account.class);
@@ -329,7 +234,7 @@ function Dialplan.destination_new(self, arg)
destination.id = common.str.to_i(destination.phone_number.record.phone_numberable_id);
destination.uuid = common.str.to_s(destination.phone_number.record.phone_numberable_uuid);
destination.node_id = common.str.to_i(destination.phone_number.record.gs_node_id);
- destination.account = self:object_find(destination.type, destination.id);
+ destination.account = self:object_find{ class = destination.type, id = destination.id};
if self.caller then
require 'common.call_forwarding';
local call_forwarding_class = common.call_forwarding.CallForwarding:new{ log = self.log, database = self.database }
@@ -389,7 +294,7 @@ function Dialplan.dial(self, destination)
if destination.node_local and destination.type == 'sipaccount' then
destination.pickup_groups = {};
- destination.account = self:object_find(destination.type, destination.id);
+ destination.account = self:object_find{class = destination.type, id = destination.id};
if destination.account then
if destination.account.class == 'sipaccount' then
destination.callee_id_name = destination.account.record.caller_name;
@@ -408,7 +313,7 @@ function Dialplan.dial(self, destination)
if destination.account.owner.class == 'user' then
user_id = destination.account.owner.id;
tenant_id = tonumber(destination.account.owner.record.current_tenant_id);
- local user = self:object_find(destination.account.owner.class, tonumber(user_id));
+ local user = self:object_find{class = destination.account.owner.class, id = tonumber(user_id)};
elseif destination.account.owner.class == 'tenant' then
tenant_id = destination.account.owner.id;
end
@@ -483,7 +388,7 @@ end
function Dialplan.huntgroup(self, destination)
- local hunt_group = self:object_find('huntgroup', tonumber(destination.id));
+ local hunt_group = self:object_find{class = 'huntgroup', id = tonumber(destination.id)};
if not hunt_group then
self.log:error('DIALPLAN_HUNTGROUP - huntgroup not found');
@@ -514,7 +419,7 @@ end
function Dialplan.acd(self, destination)
- local acd = self:object_find('automaticcalldistributor', tonumber(destination.id));
+ local acd = self:object_find{class = 'automaticcalldistributor', id = tonumber(destination.id)};
if not acd then
self.log:error('DIALPLAN_ACD - acd not found');
@@ -623,7 +528,7 @@ function Dialplan.callthrough(self, destination)
end
if type(authorization) == 'table' and tonumber(authorization.sip_account_id) and tonumber(authorization.sip_account_id) > 0 then
- local auth_account = self:object_find('sipaccount', tonumber(authorization.sip_account_id));
+ local auth_account = self:object_find{class = 'sipaccount', id = tonumber(authorization.sip_account_id)};
self.caller.forwarding_number = destination.number;
self.caller.forwarding_service = 'callthrough';
self.caller:set_variable('gs_forwarding_service', self.caller.forwarding_service);
@@ -699,7 +604,7 @@ end
function Dialplan.dialplanfunction(self, destination)
require 'dialplan.functions'
- return dialplan.functions.Functions:new{ log = self.log, database = self.database, domain = self.domain }:dialplan_function(self.caller, destination.number);
+ return dialplan.functions.Functions:new{ log = self.log, database = self.database, domain = self.domain, parent = self }:dialplan_function(self.caller, destination.number);
end
@@ -1012,7 +917,7 @@ function Dialplan.run(self, destination)
', destination: ', result.call_forwarding.type, '=', result.call_forwarding.id,
', number: ', result.call_forwarding.number);
- local auth_account = self:object_find(destination.type, destination.id);
+ local auth_account = self:object_find{class = destination.type, id = destination.id};
self.caller.forwarding_number = destination.number;
self.caller.forwarding_service = result.call_forwarding.service;
self.caller:set_variable('gs_forwarding_service', self.caller.forwarding_service);
diff --git a/misc/freeswitch/scripts/dialplan/functions.lua b/misc/freeswitch/scripts/dialplan/functions.lua
index e9f9962..780e3be 100644
--- a/misc/freeswitch/scripts/dialplan/functions.lua
+++ b/misc/freeswitch/scripts/dialplan/functions.lua
@@ -161,12 +161,27 @@ function Functions.intercept_any_number(self, caller, destination_number)
return { continue = false, code = 404, phrase = 'Number not found', no_cdr = true };
end
- if not phone_number.record.phone_numberable_type:lower() == 'sipaccount' or not tonumber(phone_number.record.phone_numberable_id) then
- self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - destination: ', phone_number.record.phone_numberable_type:lower(), '=', phone_number.record.phone_numberable_id, ', number: ', destination_number);
- return { continue = false, code = 505, phrase = 'Incompatible destination', no_cdr = true };
+ require 'common.object';
+ local phone_numberable = common.object.Object:new{ log = self.log, database = self.database}:find{class = phone_number.record.phone_numberable_type, id = phone_number.record.phone_numberable_id};
+
+ if not phone_numberable then
+ self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - numberable not found: ', dphone_number.record.phone_numberable_type, '=', phone_number.record.phone_numberable_id);
+ return { continue = false, code = 404, phrase = 'Destination not found', no_cdr = true };
+ end
+
+ require 'common.str';
+ require 'common.group';
+ local group_class = common.group.Group:new{ log = self.log, database = self.database };
+ local group_ids = group_class:union(common.str.try(caller, 'auth_account.group_ids'), common.str.try(caller, 'auth_account.owner.group_ids'));
+ local target_groups, target_group_ids = group_class:permission_targets(group_ids, 'pickup');
+ local destination_group_ids = group_class:union(common.str.try(phone_numberable, 'group_ids'), common.str.try(phone_numberable, 'owner.group_ids'));
+
+ if #group_class:intersection(destination_group_ids, target_group_ids) == 0 then
+ self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - Groups not found or insufficient permissions');
+ return { continue = false, code = 402, phrase = '"Insufficient permissions', no_cdr = true };
end
- self.log:info('FUNCTION_INTERCEPT_ANY_NUMBER intercepting call - to: ', phone_number.record.phone_numberable_type:lower(), '=', phone_number.record.phone_numberable_id, ', number: ', destination_number);
+ self.log:info('FUNCTION_INTERCEPT_ANY_NUMBER intercepting call - to: ', phone_numberable.class, '=',phone_numberable.id, '|', destination_number);
caller:set_variable('gs_pickup_group_pick', 's' .. phone_number.record.phone_numberable_id);
caller:execute('pickup', 's' .. phone_number.record.phone_numberable_id);
@@ -183,15 +198,15 @@ function Functions.group_pickup(self, caller, group_id)
require 'common.str';
require 'common.group';
local group_class = common.group.Group:new{ log = self.log, database = self.database };
- local group_ids = group_class:combine(common.str.try(caller, 'auth_account.group_ids'), common.str.try(caller, 'auth_account.owner.group_ids'));
- local target_groups = group_class:permission_targets(group_ids, 'pickup');
+ local group_ids = group_class:union(common.str.try(caller, 'auth_account.group_ids'), common.str.try(caller, 'auth_account.owner.group_ids'));
+ local target_group = group_class:is_target(group_id, 'pickup');
- if not target_groups[group_id] then
+ if not target_group then
self.log:notice('FUNCTION_GROUP_PICKUP - group=', group_id, ' not found or insufficient permissions');
- return { continue = false, code = 401, phrase = '"Insufficient permissions', no_cdr = true };
+ return { continue = false, code = 402, phrase = '"Insufficient permissions', no_cdr = true };
end
- self.log:notice('FUNCTION_GROUP_PICKUP - group=', group_id, '|', target_groups[group_id]);
+ self.log:notice('FUNCTION_GROUP_PICKUP - group=', group_id, '|', target_group);
caller:set_variable('gs_pickup_group_pick', 'g' .. group_id);
caller:execute('pickup', 'g' .. group_id);
diff --git a/misc/freeswitch/scripts/dialplan_default.lua b/misc/freeswitch/scripts/dialplan_default.lua
index 8fb9057..2b651c5 100644
--- a/misc/freeswitch/scripts/dialplan_default.lua
+++ b/misc/freeswitch/scripts/dialplan_default.lua
@@ -8,7 +8,7 @@ function hangup_hook_caller(s, status, arg)
if tostring(status) == 'transfer' then
if start_caller and start_caller.destination then
log:info('CALL_TRANSFERRED - destination was: ', start_caller.destination.type, '=', start_caller.destination.id,', number: ' .. tostring(start_caller.destination.number) .. ', to: ' .. start_caller:to_s('sip_refer_to'));
- start_caller.auth_account = start_caller.dialplan:object_find(start_caller.destination.type, start_caller.destination.id);
+ start_caller.auth_account = start_caller.dialplan:object_find{class = start_caller.destination.type, id = start_caller.destination.id};
start_caller.forwarding_number = start_caller.destination.number;
start_caller.forwarding_service = 'transfer';
end