summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
Diffstat (limited to 'misc')
-rw-r--r--misc/freeswitch/conf/freeswitch.xml16
-rw-r--r--misc/freeswitch/scripts/common/call_forwarding.lua55
-rw-r--r--misc/freeswitch/scripts/common/conference.lua6
-rw-r--r--misc/freeswitch/scripts/common/group.lua88
-rw-r--r--misc/freeswitch/scripts/common/phone_number.lua55
-rw-r--r--misc/freeswitch/scripts/common/str.lua34
-rw-r--r--misc/freeswitch/scripts/configuration.lua3
-rw-r--r--misc/freeswitch/scripts/dialplan/call_parking.lua16
-rw-r--r--misc/freeswitch/scripts/dialplan/dialplan.lua136
-rw-r--r--misc/freeswitch/scripts/dialplan/dtmf.lua8
-rw-r--r--misc/freeswitch/scripts/dialplan/fax.lua8
-rw-r--r--misc/freeswitch/scripts/dialplan/functions.lua141
-rw-r--r--misc/freeswitch/scripts/dialplan/sip_call.lua26
-rw-r--r--misc/freeswitch/scripts/dialplan/user.lua17
-rw-r--r--misc/freeswitch/scripts/dialplan/voicemail.lua2
-rw-r--r--misc/freeswitch/scripts/send_fax.lua5
16 files changed, 410 insertions, 206 deletions
diff --git a/misc/freeswitch/conf/freeswitch.xml b/misc/freeswitch/conf/freeswitch.xml
index 4969b07..f72651f 100644
--- a/misc/freeswitch/conf/freeswitch.xml
+++ b/misc/freeswitch/conf/freeswitch.xml
@@ -27,6 +27,14 @@
</match>
</input>
</macro>
+ <macro name="voicemail_change_pass_success">
+ <input pattern="(.*)">
+ <match>
+ <action function="play-file" data="voicemail/vm-password_has_been_changed.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
<macro name="voicemail_fail_auth">
<input pattern="(.*)">
<match>
@@ -536,6 +544,14 @@
</match>
</input>
</macro>
+ <macro name="voicemail_change_pass_success">
+ <input pattern="(.*)">
+ <match>
+ <action function="play-file" data="voicemail/vm-password_has_been_changed.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
<macro name="voicemail_fail_auth">
<input pattern="(.*)">
<match>
diff --git a/misc/freeswitch/scripts/common/call_forwarding.lua b/misc/freeswitch/scripts/common/call_forwarding.lua
index 400fcde..192c694 100644
--- a/misc/freeswitch/scripts/common/call_forwarding.lua
+++ b/misc/freeswitch/scripts/common/call_forwarding.lua
@@ -37,6 +37,61 @@ function CallForwarding.find_by_id(self, id)
return nil
end
+
+function CallForwarding.list_by_owner(self, call_forwardable_id, call_forwardable_type, caller_ids)
+ require 'common.str';
+
+ if not tonumber(call_forwardable_id) or common.str.blank(call_forwardable_type) then
+ return {};
+ end
+
+ local sql_query = 'SELECT \
+ `a`.`destination` AS `number`, \
+ `a`.`destinationable_id` AS `id`, \
+ `a`.`destinationable_type` AS `type`, \
+ `a`.`call_forwardable_id`, \
+ `a`.`call_forwardable_type`, \
+ `a`.`timeout`, `a`.`depth`, \
+ `a`.`source`, \
+ `b`.`value` AS `service` \
+ FROM `call_forwards` `a` JOIN `call_forward_cases` `b` ON `a`.`call_forward_case_id` = `b`.`id` \
+ WHERE `a`.`call_forwardable_id`= ' .. tonumber(call_forwardable_id) .. ' \
+ AND `a`.`call_forwardable_type`= ' .. self.database:escape(call_forwardable_type, '"') .. ' \
+ AND `a`.`active` IS TRUE';
+
+ local call_forwarding_entries = {};
+
+ self.database:query(sql_query, function(forwarding_entry)
+ local entry_match = false;
+
+ if common.str.blank(forwarding_entry.source) then
+ entry_match = true;
+ else
+ local sources = common.str.strip_to_a(forwarding_entry.source, ',')
+ for source_index=1, #sources do
+ for caller_id_index=1, #caller_ids do
+ if caller_ids[caller_id_index]:match(sources[source_index]) then
+ entry_match = true;
+ self.log:debug('CALL_FORWARDING - source match: ', sources[source_index], ' ~ ', caller_ids[caller_id_index] );
+ break;
+ end
+ end
+ end
+ end
+
+ if entry_match then
+ call_forwarding_entries[forwarding_entry.service] = forwarding_entry;
+ self.log:debug('CALL_FORWARDING - ', call_forwardable_type, '=', call_forwardable_id,
+ ', service: ', forwarding_entry.service,
+ ', destination: ',forwarding_entry.type, '=', forwarding_entry.id,
+ ', number: ', forwarding_entry.number);
+ end
+ end)
+
+ return call_forwarding_entries;
+end
+
+
function CallForwarding.presence_set(self, presence_state)
require 'dialplan.presence'
local presence = dialplan.presence.Presence:new();
diff --git a/misc/freeswitch/scripts/common/conference.lua b/misc/freeswitch/scripts/common/conference.lua
index f6a4d87..b56cba9 100644
--- a/misc/freeswitch/scripts/common/conference.lua
+++ b/misc/freeswitch/scripts/common/conference.lua
@@ -159,7 +159,7 @@ function Conference.enter(self, caller, domain)
caller:sleep(1000);
caller.session:sayPhrase('conference_welcome');
- if pin and pin ~= "" then
+ if not common.str.blank(pin) then
local digits = "";
for i = 1, 3, 1 do
if digits == pin then
@@ -167,7 +167,7 @@ function Conference.enter(self, caller, domain)
elseif digits ~= "" then
caller.session:sayPhrase('conference_bad_pin');
end
- digits = caller.session:read(PIN_LENGTH_MIN, PIN_LENGTH_MAX, 'conference/conf-enter_conf_pin.wav', PIN_TIMEOUT, '#');
+ digits = caller.session:read(PIN_LENGTH_MIN, PIN_LENGTH_MAX, 'conference/conf-pin.wav', PIN_TIMEOUT, '#');
end
if digits ~= pin then
caller.session:sayPhrase('conference_goodbye');
@@ -191,7 +191,7 @@ function Conference.enter(self, caller, domain)
-- Record caller's name
if common.str.to_b(self.record.announce_new_member_by_name) or common.str.to_b(self.record.announce_left_member_by_name) then
local uid = session:get_uuid();
- name_file = "/tmp/conference_caller_name_" .. uid .. ".wav";
+ name_file = "/var/spool/freeswitch/conference_caller_name_" .. uid .. ".wav";
caller.session:sayPhrase('conference_record_name');
session:recordFile(name_file, ANNOUNCEMENT_MAX_LEN, ANNOUNCEMENT_SILENCE_THRESHOLD, ANNOUNCEMENT_SILENCE_LEN);
caller.session:streamFile(name_file);
diff --git a/misc/freeswitch/scripts/common/group.lua b/misc/freeswitch/scripts/common/group.lua
new file mode 100644
index 0000000..c4125bc
--- /dev/null
+++ b/misc/freeswitch/scripts/common/group.lua
@@ -0,0 +1,88 @@
+-- Gemeinschaft 5 module: group class
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+Group = {}
+
+MAX_GROUP_MEMBERSHIPS = 256;
+
+-- create group object
+function Group.new(self, arg)
+ arg = arg or {}
+ object = arg.object or {}
+ setmetatable(object, self);
+ self.__index = self;
+ self.class = 'group';
+ self.log = arg.log;
+ self.database = arg.database;
+ return object;
+end
+
+-- find group by id
+function Group.find_by_id(self, id)
+ local sql_query = 'SELECT * FROM `groups` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1';
+ local group = nil;
+
+ self.database:query(sql_query, function(account_entry)
+ group = Group:new(self);
+ group.record = account_entry;
+ group.id = tonumber(account_entry.id);
+ group.name = account_entry.name;
+ end);
+
+ return group;
+end
+
+-- list groups by member permissions
+function Group.name_id_by_permission(self, member_id, member_type, permission)
+ if not tonumber(member_id) then
+ return {};
+ end
+
+ local sql_query = 'SELECT DISTINCT `c`.`id`, `c`.`name` \
+ FROM `group_permissions` `a` \
+ JOIN `group_memberships` `b` ON `a`.`target_group_id` = `b`.`group_id` \
+ JOIN `groups` `c` ON `c`.`id` = `b`.`group_id` \
+ WHERE `b`.`item_type` = ' .. self.database:escape(member_type, '"') .. ' \
+ AND `b`.`item_id` = ' .. member_id .. ' \
+ AND `a`.`permission` = ' .. self.database:escape(permission, '"') .. ' \
+ AND `c`.`active` IS TRUE \
+ GROUP BY `b`.`group_id` LIMIT ' .. MAX_GROUP_MEMBERSHIPS;
+
+ local group_names = {};
+ local group_ids = {};
+
+ self.database:query(sql_query, function(account_entry)
+ table.insert(group_names, account_entry.name);
+ table.insert(group_ids, tonumber(account_entry.id));
+ end);
+
+ return group_names, group_ids;
+end
+
+-- list groups by member
+function Group.name_id_by_member(self, member_id, member_type)
+ if not tonumber(member_id) then
+ return {};
+ end
+
+ local sql_query = 'SELECT DISTINCT `c`.`id`, `c`.`name` \
+ FROM `group_memberships` `b` \
+ JOIN `groups` `c` ON `c`.`id` = `b`.`group_id` \
+ WHERE `b`.`item_type` = ' .. self.database:escape(member_type, '"') .. ' \
+ AND `b`.`item_id` = ' .. member_id .. ' \
+ AND `c`.`active` IS TRUE \
+ GROUP BY `b`.`group_id` LIMIT ' .. MAX_GROUP_MEMBERSHIPS;
+
+ local group_names = {};
+ local group_ids = {};
+
+ self.database:query(sql_query, function(account_entry)
+ table.insert(group_names, account_entry.name);
+ table.insert(group_ids, tonumber(account_entry.id));
+ end);
+
+ return group_names, group_ids;
+end
diff --git a/misc/freeswitch/scripts/common/phone_number.lua b/misc/freeswitch/scripts/common/phone_number.lua
index 6635296..d6ee42a 100644
--- a/misc/freeswitch/scripts/common/phone_number.lua
+++ b/misc/freeswitch/scripts/common/phone_number.lua
@@ -55,6 +55,8 @@ function PhoneNumber.find_by_number(self, number, phone_numberable_types)
self.database:query(sql_query, function(number_entry)
phone_number = PhoneNumber:new(self);
phone_number.record = number_entry;
+ phone_number.id = tonumber(number_entry.id);
+ phone_number.uuid = number_entry.uuid;
end)
return phone_number;
@@ -68,6 +70,8 @@ function PhoneNumber.find_all_by_owner(self, owner_id, owner_type)
self.database:query(sql_query, function(number_entry)
phone_numbers[tonumber(number_entry.id)] = PhoneNumber:new(self);
phone_numbers[tonumber(number_entry.id)].record = number_entry;
+ phone_numbers[tonumber(number_entry.id)].id = tonumber(number_entry.id);
+ phone_numbers[tonumber(number_entry.id)].uuid = number_entry.uuid;
end)
return phone_numbers;
@@ -94,57 +98,6 @@ function PhoneNumber.list_by_same_owner(self, number, owner_types)
end
end
--- Retrieve call forwarding
-function PhoneNumber.call_forwarding(self, caller_ids)
- require 'common.str'
-
- sources = sources or {};
- table.insert(sources, '');
-
- local sql_query = 'SELECT \
- `a`.`destination` AS `number`, \
- `a`.`call_forwardable_id` AS `id`, \
- `a`.`call_forwardable_type` AS `type`, \
- `a`.`timeout`, `a`.`depth`, \
- `a`.`source`, \
- `b`.`value` AS `service` \
- FROM `call_forwards` `a` JOIN `call_forward_cases` `b` ON `a`.`call_forward_case_id` = `b`.`id` \
- WHERE `a`.`phone_number_id`= ' .. tonumber(self.record.id) .. ' \
- AND `a`.`active` IS TRUE';
-
- local call_forwarding = {}
-
- self.database:query(sql_query, function(forwarding_entry)
- local entry_match = false;
-
- if common.str.blank(forwarding_entry.source) then
- entry_match = true;
- else
- local sources = common.str.strip_to_a(forwarding_entry.source, ',')
- for index, source in ipairs(sources) do
- for index, caller_id in ipairs(caller_ids) do
- if caller_id:match(source) then
- entry_match = true;
- self.log:debug('CALL_FORWARDING_GET - source match: ', source, ' ~ ', caller_id );
- break;
- end
- end
- end
- end
-
- if entry_match then
- call_forwarding[forwarding_entry.service] = forwarding_entry;
- self.log:debug('CALL_FORWARDING_GET - PhoneNumber=', self.record.id, '/', self.record.uuid, '@', self.record.gs_node_id,
- ', number: ', self.record.number,
- ', service: ', forwarding_entry.service,
- ', destination: ',forwarding_entry.type, '=', forwarding_entry.id,
- ', number: ', forwarding_entry.number);
- end
- end)
-
- return call_forwarding;
-end
-
function PhoneNumber.call_forwarding_effective(self, service, source)
local conditions = {}
diff --git a/misc/freeswitch/scripts/common/str.lua b/misc/freeswitch/scripts/common/str.lua
index 72ff388..541199f 100644
--- a/misc/freeswitch/scripts/common/str.lua
+++ b/misc/freeswitch/scripts/common/str.lua
@@ -146,3 +146,37 @@ end
function blank(value)
return (value == nil or to_s(value) == '');
end
+
+-- concatenate string to buffer
+function append(buffer, value, separator, prefix, suffix)
+ separator = separator or '';
+ prefix = prefix or '';
+ suffix = suffix or '';
+ if buffer ~= '' then
+ buffer = buffer .. separator .. prefix .. value .. suffix;
+ else
+ buffer = prefix .. value .. suffix;
+ end
+
+ return buffer;
+end
+
+-- concatenate array values to string
+function concat(array, separator, prefix, suffix)
+ local buffer = '';
+ for key, value in pairs(array) do
+ buffer = append(buffer, value, separator, prefix, suffix);
+ end
+
+ return buffer;
+end
+
+-- concatenate array keys to string
+function concat_keys(array, separator, prefix, suffix)
+ local buffer = '';
+ for key, value in pairs(array) do
+ buffer = append(buffer, key, separator, prefix, suffix);
+ end
+
+ return buffer;
+end
diff --git a/misc/freeswitch/scripts/configuration.lua b/misc/freeswitch/scripts/configuration.lua
index 75d0df3..6660c3d 100644
--- a/misc/freeswitch/scripts/configuration.lua
+++ b/misc/freeswitch/scripts/configuration.lua
@@ -79,6 +79,9 @@ function profile(database, sofia_ini, profile_name, index, domains, node_id)
parameters['odbc-dsn'] = 'gemeinschaft:' .. tostring(database.user_name) .. ':' .. tostring(database.password);
end
+ parameters['username'] = parameters['username'] or 'Gemeinschaft';
+ parameters['user-agent-string'] = parameters['user-agent-string'] or 'Gemeinschaft';
+
-- set local bind address
if domains[index] then
parameters['sip-ip'] = domains[index]['host'];
diff --git a/misc/freeswitch/scripts/dialplan/call_parking.lua b/misc/freeswitch/scripts/dialplan/call_parking.lua
index cc2cf4b..e51eb16 100644
--- a/misc/freeswitch/scripts/dialplan/call_parking.lua
+++ b/misc/freeswitch/scripts/dialplan/call_parking.lua
@@ -39,6 +39,22 @@ function CallParking.find_by_name(self, name)
end
+function CallParking.find_by_owner(self, owner_id, owner_type)
+ local sql_query = 'SELECT * FROM `parking_stalls` WHERE `parking_stallable_id` = '.. owner_id .. ' AND `parking_stallable_type` = "' .. owner_type .. '" ORDER BY `name`';
+ local parking_stalls = {};
+
+ self.database:query(sql_query, function(entry)
+ local parking_stall = CallParking:new(self);
+ parking_stall.record = entry;
+ parking_stall.id = tonumber(entry.id);
+ parking_stall.name = entry.name;
+ table.insert(parking_stalls, parking_stall)
+ end)
+
+ return parking_stalls;
+end
+
+
function CallParking.list_occupied(self, lot)
lot = lot or self.lot;
diff --git a/misc/freeswitch/scripts/dialplan/dialplan.lua b/misc/freeswitch/scripts/dialplan/dialplan.lua
index b27bb9d..7d9ac58 100644
--- a/misc/freeswitch/scripts/dialplan/dialplan.lua
+++ b/misc/freeswitch/scripts/dialplan/dialplan.lua
@@ -148,6 +148,9 @@ 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;
@@ -158,7 +161,8 @@ function Dialplan.object_find(self, class, identifier, auth_name)
end
if user then
- user.groups = user:list_groups();
+ user.user_groups = user:list_groups();
+ user.groups = group_class:name_id_by_member(user.id, user.class);
end
return user;
@@ -171,6 +175,10 @@ function Dialplan.object_find(self, class, identifier, auth_name)
tenant = dialplan.tenant.Tenant:new{ log = self.log, database = self.database }:find_by_uuid(identifier);
end
+ if tenant then
+ tenant.groups = group_class:name_id_by_member(tenant.id, tenant.class);
+ end
+
return tenant;
elseif class == 'sipaccount' then
require 'common.sip_account'
@@ -184,6 +192,7 @@ function Dialplan.object_find(self, class, identifier, auth_name)
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 = group_class:name_id_by_member(sip_account.id, sip_account.class);
end
return sip_account;
elseif class == 'huntgroup' then
@@ -198,6 +207,7 @@ function Dialplan.object_find(self, class, identifier, auth_name)
if hunt_group then
hunt_group.owner = self:object_find('tenant', tonumber(hunt_group.record.tenant_id));
+ hunt_group.groups = group_class:name_id_by_member(hunt_group.id, hunt_group.class);
end
return hunt_group;
@@ -213,6 +223,7 @@ function Dialplan.object_find(self, class, identifier, auth_name)
if acd then
acd.owner = self:object_find(acd.record.automatic_call_distributorable_type, tonumber(acd.record.automatic_call_distributorable_id));
+ acd.groups = group_class:name_id_by_member(acd.id, acd.class);
end
return acd;
@@ -226,6 +237,7 @@ function Dialplan.object_find(self, class, identifier, auth_name)
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 = group_class:name_id_by_member(fax_account.id, fax_account.class);
end
return fax_account;
@@ -235,7 +247,6 @@ end
function Dialplan.retrieve_caller_data(self)
require 'common.str'
-
self.caller.caller_phone_numbers_hash = {}
-- TODO: Set auth_account on transfer initiated by calling party
@@ -252,9 +263,9 @@ function Dialplan.retrieve_caller_data(self)
end
if self.caller.auth_account then
- self.log:info('CALLER_DATA - auth account: ', self.caller.auth_account.class, '=', self.caller.auth_account.id, '/', self.caller.auth_account.uuid);
+ self.log:info('CALLER_DATA - auth account: ', self.caller.auth_account.class, '=', self.caller.auth_account.id, '/', self.caller.auth_account.uuid, ', groups: ', table.concat(self.caller.auth_account.groups, ','));
if self.caller.auth_account.owner then
- self.log:info('CALLER_DATA - auth owner: ', self.caller.auth_account.owner.class, '=', self.caller.auth_account.owner.id, '/', self.caller.auth_account.owner.uuid);
+ self.log:info('CALLER_DATA - auth owner: ', self.caller.auth_account.owner.class, '=', self.caller.auth_account.owner.id, '/', self.caller.auth_account.owner.uuid, ', groups: ', table.concat(self.caller.auth_account.owner.groups, ','));
else
self.log:error('CALLER_DATA - auth owner not found');
end
@@ -273,9 +284,9 @@ function Dialplan.retrieve_caller_data(self)
if not common.str.blank(self.caller.account.record.language_code) then
self.caller.language = self.caller.account.record.language_code;
end
- self.log:info('CALLER_DATA - caller account: ', self.caller.account.class, '=', self.caller.account.id, '/', self.caller.account.uuid, ', phone_numbers: ', #self.caller.caller_phone_numbers, ', language: ', self.caller.language);
+ self.log:info('CALLER_DATA - caller account: ', self.caller.account.class, '=', self.caller.account.id, '/', self.caller.account.uuid, ', phone_numbers: ', #self.caller.caller_phone_numbers, ', language: ', self.caller.language, ', groups: ', table.concat(self.caller.account.groups, ','));
if self.caller.account.owner then
- self.log:info('CALLER_DATA - caller owner: ', self.caller.account.owner.class, '=', self.caller.account.owner.id, '/', self.caller.account.owner.uuid);
+ self.log:info('CALLER_DATA - caller owner: ', self.caller.account.owner.class, '=', self.caller.account.owner.id, '/', self.caller.account.owner.uuid, ', groups: ', table.concat(self.caller.account.owner.groups, ','));
else
self.log:error('CALLER_DATA - caller owner not found');
end
@@ -319,7 +330,13 @@ function Dialplan.destination_new(self, arg)
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);
if self.caller then
- destination.call_forwarding = destination.phone_number:call_forwarding(self.caller.caller_phone_numbers);
+ require 'common.call_forwarding';
+ local call_forwarding_class = common.call_forwarding.CallForwarding:new{ log = self.log, database = self.database }
+ destination.call_forwarding = call_forwarding_class:list_by_owner(destination.id, destination.type, self.caller.caller_phone_numbers);
+ for service, call_forwarding_entry in pairs(call_forwarding_class:list_by_owner(destination.phone_number.id, destination.phone_number.class, self.caller.caller_phone_numbers)) do
+ destination.call_forwarding[service] = call_forwarding_entry;
+ end
+ -- destination.call_forwarding = destination.phone_number:call_forwarding(self.caller.caller_phone_numbers);
end
elseif destination.type == 'unknown' then
require 'common.sip_account'
@@ -362,64 +379,74 @@ end
function Dialplan.dial(self, destination)
+ local user_id = nil;
+ local tenant_id = nil;
+
require 'common.str'
destination.caller_id_number = destination.caller_id_number or self.caller.caller_phone_numbers[1];
- if not self.caller.clir then
- if destination.node_local and destination.type == 'sipaccount' then
- local user_id = nil;
- local tenant_id = nil;
-
- destination.account = self:object_find(destination.type, destination.id);
- if destination.account then
- if destination.account.class == 'sipaccount' then
- destination.callee_id_name = destination.account.record.caller_name;
- self.caller:set_callee_id(destination.number, destination.account.record.caller_name);
- end
+ if destination.node_local and destination.type == 'sipaccount' then
+ destination.pickup_groups = {};
+
+ destination.account = self:object_find(destination.type, destination.id);
+ if destination.account then
+ if destination.account.class == 'sipaccount' then
+ destination.callee_id_name = destination.account.record.caller_name;
+ self.caller:set_callee_id(destination.number, destination.account.record.caller_name);
+ table.insert(destination.pickup_groups, 's' .. destination.account.id );
end
+ require 'common.group';
+ local group_names, group_ids = common.group.Group:new{ log = self.log, database = self.database }:name_id_by_permission(destination.id, destination.type, 'pickup');
+ self.log:debug('DESTINATION_GROUPS - pickup_groups: ', table.concat(group_names, ','));
+ for index=1, #group_ids do
+ table.insert(destination.pickup_groups, 'g' .. group_ids[index]);
+ end
+ end
- if destination.account and destination.account.owner then
- if destination.account.owner.class == 'user' then
- user_id = destination.account.owner.id;
- tenant_id = tonumber(destination.account.owner.record.current_tenant_id);
- elseif destination.account.owner.class == 'tenant' then
- tenant_id = destination.account.owner.id;
- end
+ if destination.account and destination.account.owner then
+ 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));
+ elseif destination.account.owner.class == 'tenant' then
+ tenant_id = destination.account.owner.id;
end
+ end
+ end
- if user_id or tenant_id then
- require 'common.str'
- local phone_book_entry = nil;
+ if not self.caller.clir then
+ if user_id or tenant_id then
+ require 'common.str'
+ local phone_book_entry = nil;
- if self.phonebook_number_lookup then
- require 'dialplan.phone_book'
- phone_book_entry = dialplan.phone_book.PhoneBook:new{ log = self.log, database = self.database }:find_entry_by_number_user_tenant(self.caller.caller_phone_numbers, user_id, tenant_id);
- end
+ if self.phonebook_number_lookup then
+ require 'dialplan.phone_book'
+ phone_book_entry = dialplan.phone_book.PhoneBook:new{ log = self.log, database = self.database }:find_entry_by_number_user_tenant(self.caller.caller_phone_numbers, user_id, tenant_id);
+ end
- if phone_book_entry then
- self.log:info('PHONE_BOOK_ENTRY - phone_book=', phone_book_entry.phone_book_id, ' (', phone_book_entry.phone_book_name, '), caller_id_name: ', phone_book_entry.caller_id_name, ', ringtone: ', phone_book_entry.bellcore_id);
- destination.caller_id_name = common.str.to_ascii(phone_book_entry.caller_id_name);
- if tonumber(phone_book_entry.bellcore_id) then
- self.log:debug('RINGTONE - phonebookentry, index: ', phone_book_entry.bellcore_id);
- self.caller:export_variable('alert_info', 'http://amooma.de;info=Ringer' .. phone_book_entry.bellcore_id .. ';x-line-id=0');
- end
- if phone_book_entry.image then
- self:set_caller_picture(phone_book_entry.id, 'phonebookentry', phone_book_entry.image);
- elseif self.caller.account and self.caller.account.owner then
- self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class);
- end
+ if phone_book_entry then
+ self.log:info('PHONE_BOOK_ENTRY - phone_book=', phone_book_entry.phone_book_id, ' (', phone_book_entry.phone_book_name, '), caller_id_name: ', phone_book_entry.caller_id_name, ', ringtone: ', phone_book_entry.bellcore_id);
+ destination.caller_id_name = common.str.to_ascii(phone_book_entry.caller_id_name);
+ if tonumber(phone_book_entry.bellcore_id) then
+ self.log:debug('RINGTONE - phonebookentry, index: ', phone_book_entry.bellcore_id);
+ self.caller:export_variable('alert_info', 'http://amooma.de;info=Ringer' .. phone_book_entry.bellcore_id .. ';x-line-id=0');
+ end
+ if phone_book_entry.image then
+ self:set_caller_picture(phone_book_entry.id, 'phonebookentry', phone_book_entry.image);
elseif self.caller.account and self.caller.account.owner then
self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class);
- elseif self.geo_number_lookup then
- require 'dialplan.geo_number'
- local geo_number = dialplan.geo_number.GeoNumber:new{ log = self.log, database = self.database }:find(destination.caller_id_number);
- if geo_number then
- self.log:info('GEO_NUMBER - found: ', geo_number.name, ', ', geo_number.country);
- if geo_number.name then
- destination.caller_id_name = common.str.to_ascii(geo_number.name) .. ', ' .. common.str.to_ascii(geo_number.country);
- else
- destination.caller_id_name = common.str.to_ascii(geo_number.country);
- end
+ end
+ elseif self.caller.account and self.caller.account.owner then
+ self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class);
+ elseif self.geo_number_lookup then
+ require 'dialplan.geo_number'
+ local geo_number = dialplan.geo_number.GeoNumber:new{ log = self.log, database = self.database }:find(destination.caller_id_number);
+ if geo_number then
+ self.log:info('GEO_NUMBER - found: ', geo_number.name, ', ', geo_number.country);
+ if geo_number.name then
+ destination.caller_id_name = common.str.to_ascii(geo_number.name) .. ', ' .. common.str.to_ascii(geo_number.country);
+ else
+ destination.caller_id_name = common.str.to_ascii(geo_number.country);
end
end
end
@@ -997,6 +1024,7 @@ function Dialplan.run(self, destination)
destination = self:destination_new(result.call_forwarding);
self.caller.destination = destination;
+ self.caller.destination_number = destination.number;
if not result.no_cdr and auth_account then
require 'common.call_history'
diff --git a/misc/freeswitch/scripts/dialplan/dtmf.lua b/misc/freeswitch/scripts/dialplan/dtmf.lua
index 4dbd35f..64f538e 100644
--- a/misc/freeswitch/scripts/dialplan/dtmf.lua
+++ b/misc/freeswitch/scripts/dialplan/dtmf.lua
@@ -17,12 +17,17 @@ function Dtmf.new(self, arg)
self.bleg = arg.bleg
self.digit_timeout = arg.digit_timeout or 5;
self.router = arg.router;
+ self.digit_duration_min = arg.digit_duration_min or 500;
return object;
end
function Dtmf.detect(self, caller, sequence, digit, duration, calee)
+ if not tonumber(duration) or duration < self.digit_duration_min then
+ return;
+ end
+
local timestamp = os.time();
if timestamp - sequence.updated > self.digit_timeout then
sequence.digits = digit;
@@ -63,6 +68,9 @@ function Dtmf.transfer(self, caller, destination, calee)
caller:execute('transfer', destination);
fapi:execute('uuid_kill', callee_uuid);
else
+ if caller.account then
+ fapi:execute('uuid_setvar_multi', callee_uuid .. ' gs_auth_account_type=' .. caller.account.class .. ';gs_auth_account_uuid=' .. caller.account.uuid);
+ end
fapi:execute('uuid_transfer', callee_uuid .. ' ' .. destination);
caller.session:hangup();
end
diff --git a/misc/freeswitch/scripts/dialplan/fax.lua b/misc/freeswitch/scripts/dialplan/fax.lua
index 49a45d9..6dce0a9 100644
--- a/misc/freeswitch/scripts/dialplan/fax.lua
+++ b/misc/freeswitch/scripts/dialplan/fax.lua
@@ -4,7 +4,7 @@
module(...,package.seeall)
-FAX_DOCUMENTS_DIRECTORY = '/tmp/'
+FAX_SPOOL_DIRECTORY = '/var/spool/freeswitch/'
FAX_PARALLEL_MAX = 8;
Fax = {}
@@ -18,7 +18,7 @@ function Fax.new(self, arg)
self.log = arg.log;
self.database = arg.database;
self.record = arg.record;
- self.fax_directory = arg.fax_directory or FAX_DOCUMENTS_DIRECTORY;
+ self.fax_spool_directory = arg.fax_spool_directory or FAX_SPOOL_DIRECTORY;
return object;
end
@@ -79,7 +79,7 @@ end
-- List waiting fax documents
function Fax.queued_for_sending(self, limit)
limit = limit or FAX_PARALLEL_MAX;
- local sql_query = 'SELECT * FROM `fax_documents` WHERE `state` IN ("queued_for_sending","unsuccessful") AND `retry_counter` > 0 ORDER BY `sent_at` ASC LIMIT ' .. limit;
+ local sql_query = 'SELECT * FROM `fax_documents` WHERE `state` IN ("queued_for_sending","unsuccessful") AND `retry_counter` > 0 AND `tiff` IS NOT NULL AND `tiff` != "" ORDER BY `sent_at` ASC LIMIT ' .. limit;
local fax_documents = {}
self.database:query(sql_query, function(fax_entry)
fax_entry['destination_numbers'] = Fax:destination_numbers(fax_entry.id)
@@ -136,7 +136,7 @@ end
-- Receive Fax
function Fax.receive(self, caller, file_name)
- file_name = file_name or self.fax_directory .. 'fax_in_' .. caller.uuid .. '.tiff';
+ file_name = file_name or self.fax_spool_directory .. 'fax_in_' .. caller.uuid .. '.tiff';
caller:set_variable('fax_ident', self.record.station_id)
caller:set_variable('fax_verbose', 'false')
diff --git a/misc/freeswitch/scripts/dialplan/functions.lua b/misc/freeswitch/scripts/dialplan/functions.lua
index acfa336..3706872 100644
--- a/misc/freeswitch/scripts/dialplan/functions.lua
+++ b/misc/freeswitch/scripts/dialplan/functions.lua
@@ -35,10 +35,8 @@ function Functions.dialplan_function(self, caller, dialed_number)
if fid == "ta" then
result = self:transfer_all(caller, parameters[3]);
- elseif fid == "in" then
- result = self:intercept_extensions(caller, parameters[3]);
elseif fid == "ia" then
- result = self:intercept_any_extension(caller, parameters[3]);
+ result = self:intercept_any_number(caller, parameters[3]);
elseif fid == "anc" then
result = self:account_node_change(caller);
elseif fid == "li" then
@@ -113,9 +111,11 @@ function Functions.dialplan_function(self, caller, dialed_number)
result = self:hangup(caller, parameters[3], parameters[4]);
elseif fid == "cpa" then
result = self:call_parking_inout(caller, parameters[3], parameters[4]);
+ elseif fid == "cpai" then
+ result = self:call_parking_inout_index(caller, parameters[3]);
end
- return result;
+ return result or { continue = false, code = 505, phrase = 'Error executing function', no_cdr = true };
end
-- Transfer all calls to a conference
@@ -149,94 +149,27 @@ function Functions.transfer_all(self, caller, destination_number)
return destination_number;
end
--- Intercept Extensions
-function Functions.intercept_extensions(self, caller, destination_numbers)
- if type(destination_numbers) == "string" then
- destination_numbers = "\"" .. destination_numbers .. "\"";
- else
- destination_numbers = "\"" .. table.concat(destination_numbers, "\",\"") .. "\"";
- end
-
- self.log:debug("Intercept call to number(s): " .. destination_numbers);
-
- if caller.account_type ~= "SipAccount" then
- self.log:error("caller is not a SipAccount");
- return { continue = false, code = 403, phrase = 'Incompatible caller' }
- end
- local sql_query = 'SELECT * FROM `channels` WHERE `callstate` IN ("EARLY", "ACTIVE") AND `dest` IN (' .. destination_numbers .. ') LIMIT 1';
-
- self.database:query(sql_query, function(call_entry)
- self.log:debug("intercepting call with uid: " .. call_entry.uuid);
- caller:intercept(call_entry.uuid);
- end)
-
- return nil;
-end
+function Functions.intercept_any_number(self, caller, destination_number)
+ require 'common.phone_number'
+ local phone_number = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:find_by_number(destination_number);
--- intercept call to destination (e.g. sip_account)
-function Functions.intercept_destination(self, caller, destination)
- self.log:debug("Intercept call to destination " .. destination);
- local result = false;
- local sql_query = 'SELECT `call_uuid`, `uuid` FROM `channels` WHERE `callstate` = "RINGING" AND `dest` = "' .. destination .. '" LIMIT 1';
+ if not phone_number or not phone_number.record then
+ self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - number not found: ', destination_number);
+ return { continue = false, code = 404, phrase = 'Number not found', no_cdr = true };
+ end
- caller:set_caller_id(caller.caller_phone_numbers[1] ,caller.caller_id_name);
- self.database:query(sql_query, function(call_entry)
- if call_entry.call_uuid and tostring(call_entry.call_uuid) then
- self.log:debug("intercepting call - uuid: " .. call_entry.call_uuid);
- caller:intercept(call_entry.call_uuid);
- result = { continue = false, code = 200, call_service = 'pickup' }
- require 'common.str'
- require 'common.fapi'
- local fapi = common.fapi.FApi:new{ log = self.log, uuid = call_entry.call_uuid }
- if fapi:channel_exists() then
- caller:set_caller_id(
- common.str.to_s(fapi:get_variable('effective_caller_id_number')),
- common.str.to_s(fapi:get_variable('effective_caller_id_name'))
- );
- caller:set_callee_id(
- common.str.to_s(fapi:get_variable('effective_callee_id_number')),
- common.str.to_s(fapi:get_variable('effective_callee_id_name'))
- );
-
- caller:set_variable('gs_destination_type', fapi:get_variable('gs_destination_type'));
- caller:set_variable('gs_destination_id', fapi:get_variable('gs_destination_id'));
- caller:set_variable('gs_destination_uuid', fapi:get_variable('gs_destination_uuid'));
-
- caller:set_variable('gs_caller_account_type', fapi:get_variable('gs_account_type'));
- caller:set_variable('gs_caller_account_id', fapi:get_variable('gs_account_id'));
- caller:set_variable('gs_caller_account_uuid', fapi:get_variable('gs_account_uuid'));
-
- caller:set_variable('gs_auth_account_type', fapi:get_variable('gs_auth_account_type'));
- caller:set_variable('gs_auth_account_id', fapi:get_variable('gs_auth_account_id'));
- caller:set_variable('gs_auth_account_uuid', fapi:get_variable('gs_auth_account_uuid'));
- end
- else
- self.log:error('FUNCTION - failed to intercept call - no caller uuid for callee uuid: ', call_entry.uuid);
- end
- 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 };
+ end
- return result;
-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);
--- intercept call to owner of destination_number
-function Functions.intercept_any_extension(self, caller, destination_number)
- require 'common.phone_number'
- local phone_number_object = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:find_by_number(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);
- if not phone_number_object or not phone_number_object.record then
- self.log:notice("unallocated number: " .. tostring(destination_number));
- return false;
- end
-
- if phone_number_object.record.phone_numberable_type == 'SipAccount' then
- require "common.sip_account"
- local sip_account_class = common.sip_account.SipAccount:new{ log = self.log, database = self.database }
- local sip_account = sip_account_class:find_by_id(phone_number_object.record.phone_numberable_id)
- if sip_account then
- return self:intercept_destination(caller, sip_account.record.auth_name);
- end
- end
+ return { continue = false, code = 200, phrase = 'OK', no_cdr = true }
end
@@ -932,3 +865,39 @@ function Functions.call_parking_inout(self, caller, stall_name, lot_name)
return { continue = false, code = 200, phrase = 'OK', no_cdr = true }
end
+
+
+function Functions.call_parking_inout_index(self, caller, stall_index)
+ if not tonumber(stall_index) then
+ self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - malformed index: ', stall_index);
+ return { continue = false, code = 404, phrase = 'No parkings stall specified', no_cdr = true }
+ end
+
+ require 'common.str';
+ local owner = common.str.try(caller, 'auth_account.owner');
+
+ if not owner then
+ self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - stall owner not specified');
+ return { continue = false, code = 404, phrase = 'No parkings stalls owner' , no_cdr = true }
+ end
+
+ require 'dialplan.call_parking';
+ local parking_stalls = dialplan.call_parking.CallParking:new{ log = self.log, database = self.database, caller = caller }:find_by_owner(owner.id, owner.class);
+
+ if not parking_stalls or #parking_stalls < 1 then
+ self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - no parkings stalls found');
+ return { continue = false, code = 404, phrase = 'No parkings stalls', no_cdr = true }
+ end
+
+ local parking_stall = parking_stalls[tonumber(stall_index)];
+
+ if not parking_stall then
+ self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - no parkings stall found with index: ', stall_index);
+ return { continue = false, code = 404, phrase = 'Parking stall not found', no_cdr = true }
+ end
+
+ self.log:info('FUNCTION_CALL_PARKING_INOUT_INDEX parking/retrieving call - parkingstall=', parking_stall.id, '/', parking_stall.name, ', index: ', stall_index);
+ parking_stall:park_retrieve();
+
+ return { continue = false, code = 200, phrase = 'OK', no_cdr = true }
+end
diff --git a/misc/freeswitch/scripts/dialplan/sip_call.lua b/misc/freeswitch/scripts/dialplan/sip_call.lua
index b56f1b2..5c98792 100644
--- a/misc/freeswitch/scripts/dialplan/sip_call.lua
+++ b/misc/freeswitch/scripts/dialplan/sip_call.lua
@@ -76,7 +76,8 @@ end
function SipCall.fork(self, destinations, arg )
- local dial_strings = {}
+ local dial_strings = {};
+ local pickup_groups = {};
require 'common.sip_account'
require 'common.str'
@@ -135,6 +136,11 @@ function SipCall.fork(self, destinations, arg )
table.insert(origination_variables, "alert_info='" .. destination.alert_info .. "'");
end
table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/' .. sip_account.record.profile_name .. '/' .. sip_account.record.auth_name .. '%' .. sip_account.record.sip_host);
+ if destination.pickup_groups and #destination.pickup_groups > 0 then
+ for key=1, #destination.pickup_groups do
+ pickup_groups[destination.pickup_groups[key]] = true;
+ end
+ end
else
some_destinations_busy = true;
call_result = { code = 486, phrase = 'User busy', disposition = 'USER_BUSY' };
@@ -184,6 +190,10 @@ function SipCall.fork(self, destinations, arg )
self.caller:set_variable('call_timeout', arg.timeout );
self.log:info('FORK DIAL - destinations: ', #dial_strings, ', timeout: ', arg.timeout);
+ for pickup_group, value in pairs(pickup_groups) do
+ table.insert(dial_strings, 'pickup/' .. pickup_group);
+ end
+
if arg.send_ringing then
self.caller:execute('ring_ready');
end
@@ -201,10 +211,20 @@ function SipCall.fork(self, destinations, arg )
fork_index = tonumber(session_callee:getVariable('gs_fork_index')) or 0;
local destination = destinations[fork_index];
- if arg.detect_dtmf_after_bridge_caller then
+ if not destination then
+ destination = {
+ ['type'] = session_callee:getVariable('gs_account_type');
+ id = session_callee:getVariable('gs_account_id');
+ uuid = session_callee:getVariable('gs_account_uuid');
+ pickup_group_pick = session_callee:getVariable('gs_pickup_group_pick');
+ }
+ self.log:notice('FORK - call picked off by: ', destination.type, '=', destination.id, '/', destination.uuid, ', pickup_group: ', destination.pickup_group_pick);
+ end
+
+ if arg.detect_dtmf_after_bridge_caller and self.caller.auth_account then
session:execute('start_dtmf');
end
- if arg.detect_dtmf_after_bridge_callee then
+ if arg.detect_dtmf_after_bridge_callee and destination.type == 'sipaccount' then
session_callee:execute('start_dtmf');
end
if arg.bypass_media_network then
diff --git a/misc/freeswitch/scripts/dialplan/user.lua b/misc/freeswitch/scripts/dialplan/user.lua
index b536600..b6928b4 100644
--- a/misc/freeswitch/scripts/dialplan/user.lua
+++ b/misc/freeswitch/scripts/dialplan/user.lua
@@ -69,6 +69,23 @@ function User.list_groups(self, id)
end
+function User.list_group_ids(self, id)
+ require 'common.str'
+ id = id or self.id;
+ local sql_query = 'SELECT `b`.`id` FROM `user_group_memberships` `a` \
+ JOIN `user_groups` `b` ON `a`.`user_group_id` = `b`.`id` \
+ WHERE `a`.`state` = "active" AND `a`.`user_id`= ' .. tonumber(id) .. ' ORDER BY `b`.`position` LIMIT ' .. MAX_GROUP_MEMBERSHIPS;
+
+ local groups = {};
+
+ self.database:query(sql_query, function(entry)
+ table.insert(groups, common.str.downcase(entry.id));
+ end);
+
+ return groups;
+end
+
+
function User.check_pin(self, pin_to_check)
if not self.record then
return nil
diff --git a/misc/freeswitch/scripts/dialplan/voicemail.lua b/misc/freeswitch/scripts/dialplan/voicemail.lua
index 4c96fbe..ae7d0a1 100644
--- a/misc/freeswitch/scripts/dialplan/voicemail.lua
+++ b/misc/freeswitch/scripts/dialplan/voicemail.lua
@@ -11,7 +11,7 @@ MESSAGE_LENGTH_MAX = 120;
SILENCE_LENGTH_ABORT = 5;
SILENCE_LEVEL = 500;
BEEP = 'tone_stream://%(1000,0,500)';
-RECORD_FILE_PREFIX = '/tmp/voicemail_';
+RECORD_FILE_PREFIX = '/var/spool/freeswitch/voicemail_';
-- create voicemail object
function Voicemail.new(self, arg)
diff --git a/misc/freeswitch/scripts/send_fax.lua b/misc/freeswitch/scripts/send_fax.lua
index 4898cb8..d717f93 100644
--- a/misc/freeswitch/scripts/send_fax.lua
+++ b/misc/freeswitch/scripts/send_fax.lua
@@ -2,7 +2,6 @@
-- (c) AMOOMA GmbH 2012-2013
--
-local FAX_FILE_PATH = "/opt/GS5/public/uploads/fax_document/tiff/";
local FAX_ANSWERING_TIMEOUT = 20;
-- Set logger
@@ -142,13 +141,11 @@ end
if session and session:answered() then
log:info('FAX_SEND - sending fax_document=' .. fax_document.id .. ' (' .. fax_document.tiff .. ')');
- local file_name = FAX_FILE_PATH .. fax_document.id .. "/" .. fax_document.tiff;
-
session:setVariable('fax_ident', fax_account.record.station_id)
session:setVariable('fax_header', fax_account.record.name)
session:setVariable('fax_verbose', 'false')
local start_time = os.time();
- session:execute('txfax', file_name);
+ session:execute('txfax', fax_document.tiff);
fax_state = {
state = nil,