diff options
Diffstat (limited to 'misc/freeswitch/scripts/event/presence_update.lua')
-rw-r--r-- | misc/freeswitch/scripts/event/presence_update.lua | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/misc/freeswitch/scripts/event/presence_update.lua b/misc/freeswitch/scripts/event/presence_update.lua new file mode 100644 index 0000000..01ec17b --- /dev/null +++ b/misc/freeswitch/scripts/event/presence_update.lua @@ -0,0 +1,199 @@ + +module(...,package.seeall) + +function handler_class() + return PresenceUpdate +end + +ACCOUNT_RECORD_TIMEOUT = 120; + +PresenceUpdate = {} + +function PresenceUpdate.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'presenceupdate' + self.database = arg.database; + self.domain = arg.domain; + self.presence_accounts = {} + self.account_record = {} + + return object; +end + + +function PresenceUpdate.event_handlers(self) + return { + PRESENCE_PROBE = { [true] = self.presence_probe }, + CUSTOM = { ['sofia::register'] = self.sofia_register, ['sofia::unregister'] = self.sofia_ungerister }, + PRESENCE_IN = { [true] = self.presence_in }, + } +end + + +function PresenceUpdate.presence_probe(self, event) + local DIALPLAN_FUNCTION_PATTERN = '^f[_%-].*'; + + require 'common.str' + local event_to = event:getHeader('to'); + local event_from = event:getHeader('from'); + local probe_type = event:getHeader('probe-type'); + local account, domain = common.str.partition(event_from, '@'); + local subscription, domain = common.str.partition(event_to, '@'); + + self.log:debug('[', account, '] PRESENCE_UPDATE - subscription: ', subscription,', type: ', probe_type); + if (not self.presence_accounts[account] or not self.presence_accounts[account][subscription]) and subscription:find(DIALPLAN_FUNCTION_PATTERN) then + if not self.presence_accounts[account] then + self.presence_accounts[account] = {}; + end + if not self.presence_accounts[account][subscription] then + self.presence_accounts[account][subscription] = {}; + end + self:update_function_presence(account, domain, subscription); + end +end + + +function PresenceUpdate.sofia_register(self, event) + local account = event:getHeader('from-user'); + self.log:debug('[', account, '] PRESENCE_UPDATE - flushing account cache on register'); + self.presence_accounts[account] = nil; +end + + +function PresenceUpdate.sofia_ungerister(self, event) + local account = event:getHeader('from-user'); + self.log:debug('[', account, '] PRESENCE_UPDATE - flushing account cache on unregister'); + self.presence_accounts[account] = nil; +end + + +function PresenceUpdate.presence_in(self, event) + if not event:getHeader('status') then + return + end + + local account, domain = common.str.partition(event:getHeader('from'), '@'); + local direction = tostring(event:getHeader('presence-call-direction')) + local state = event:getHeader('presence-call-info-state'); + local uuid = event:getHeader('Unique-ID'); + local caller_id = event:getHeader('Caller-Caller-ID-Number'); + + if direction == 'inbound' then + self.log:info('[', uuid,'] PRESENCE_INBOUND: account: ', account, ', state: ', state); + self:sip_account(true, account, domain, state, uuid); + elseif direction == 'outbound' then + self.log:info('[', uuid,'] PRESENCE_OUTBOUND: account: ', account, ', state: ', state, ', caller: ', caller_id); + self:sip_account(false, account, domain, state, uuid, caller_id); + end +end + + +function PresenceUpdate.update_function_presence(self, account, domain, subscription) + local parameters = common.str.to_a(subscription, '_%-'); + local fid = parameters[2]; + local function_parameter = parameters[3]; + + if not fid then + self.log:error('[', account, '] PRESENCE_UPDATE - no function specified'); + return; + end + + if fid == 'cftg' and tonumber(function_parameter) then + self:call_forwarding(account, domain, function_parameter); + elseif fid == 'hgmtg' then + self:hunt_group_membership(account, domain, function_parameter); + elseif fid == 'acdmtg' then + self:acd_membership(account, domain, function_parameter); + end + +end + + +function PresenceUpdate.call_forwarding(self, account, domain, call_forwarding_id) + require 'common.call_forwarding' + local call_forwarding = common.call_forwarding.CallForwarding:new{ log=self.log, database=self.database, domain=domain }:find_by_id(call_forwarding_id); + + require 'common.str' + if call_forwarding and common.str.to_b(call_forwarding.record.active) then + local destination_type = tostring(call_forwarding.record.call_forwardable_type):lower() + + self.log:debug('[', account, '] PRESENCE_UPDATE - updating call forwarding presence - id: ', call_forwarding_id, ', destination: ', destination_type); + + if destination_type == 'voicemail' then + call_forwarding:presence_set('early'); + else + call_forwarding:presence_set('confirmed'); + end + end +end + + +function PresenceUpdate.hunt_group_membership(self, account, domain, member_id) + local sql_query = 'SELECT `active` FROM `hunt_group_members` WHERE `active` IS TRUE AND `id`=' .. tonumber(member_id) .. ' LIMIT 1'; + local status = self.database:query_return_value(sql_query); + + if status then + self.log:debug('[', account, '] PRESENCE_UPDATE - updating hunt group membership presence - id: ', member_id); + require 'dialplan.presence' + local presence_class = dialplan.presence.Presence:new{ + log = self.log, + database = self.database, + domain = domain, + accounts = {'f-hgmtg-' .. member_id}, + uuid = 'hunt_group_member_' .. member_id + }:set('confirmed'); + end +end + + +function PresenceUpdate.acd_membership(self, account, domain, member_id) + local sql_query = 'SELECT `status` FROM `acd_agents` WHERE `status` = "active" AND `id`=' .. tonumber(member_id) .. ' LIMIT 1'; + local status = self.database:query_return_value(sql_query); + + if status then + self.log:debug('[', account, '] PRESENCE_UPDATE - updating ACD membership presence - id: ', member_id); + require 'dialplan.presence' + local presence_class = dialplan.presence.Presence:new{ + log = self.log, + database = self.database, + domain = domain, + accounts = {'f-acdmtg-' .. member_id}, + uuid = 'acd_agent_' .. member_id + }:set(status); + end +end + + +function PresenceUpdate.sip_account(self, inbound, account, domain, status, uuid, caller_id) + local status_map = { progressing = 'early', alerting = 'confirmed', active = 'confirmed' } + + if not self.account_record[account] or ((os.time() - self.account_record[account].created_at) > ACCOUNT_RECORD_TIMEOUT) then + self.log:debug('[', uuid,'] PRESENCE - retrieve account data - account: ', account); + + require 'common.sip_account' + local sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_auth_name(account); + + if not sip_account then + return + end + + require 'common.phone_number' + local phone_numbers = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:list_by_owner(sip_account.id, sip_account.class); + + self.account_record[account] = { id = sip_account.id, class = sip_account.class, phone_numbers = phone_numbers, created_at = os.time() } + end + + require 'dialplan.presence' + local result = dialplan.presence.Presence:new{ + log = self.log, + database = self.database, + inbound = inbound, + domain = domain, + accounts = self.account_record[account].phone_numbers, + uuid = uuid + }:set(status_map[status] or 'terminated', caller_id); +end |