Implement XEP-0055 with implicit rewrite rules.

This allows for searching for denormalized phone numbers via
Jabber Search, and the module will use the rewrite rules of
the searching user to normalize to E164. Using this number, the
subscriber is looked up in dbaliases table and is returned as JID.
1.0
Andreas Granig 13 years ago
parent 804143c845
commit 28b5fc52a5

3
debian/control vendored

@ -11,6 +11,7 @@ Architecture: amd64
Depends: lua-dbi-mysql,
lua-dbi-common,
lua-sec,
lua-rex-pcre,
${misc:Depends}, ${shlibs:Depends}
Description: ngcp modules for the prosody Jabber/XMPP server
This package provides modules for the Prosody Jabber/XMPP server
@ -24,3 +25,5 @@ Description: ngcp modules for the prosody Jabber/XMPP server
for phone/video of the requested user
* mod_sipwise_vhosts_sql.lua: load vhosts from DB on startup of
Prosody XMPP server
* mod_sipwise_vjud.lua: implement Jabber Search with implicit number
normalization using the NGCP rewrite rules

@ -0,0 +1,168 @@
local nodeprep = require "util.encodings".stringprep.nodeprep;
local jid_split = require "util.jid".split;
local sql = module:require("sql");
local st = require "util.stanza";
local template = require "util.template";
local array = require "util.array";
local rex = require "rex_pcre";
local get_reply = template[[
<query xmlns='jabber:iq:search'>
<instructions>Please enter a phone number</instructions>
<nick/>
</query>
]].apply({});
local usr_replacements_query = [[
SELECT vrr.match_pattern, vrr.replace_pattern FROM voip_preferences vp
LEFT JOIN voip_usr_preferences vup ON vup.attribute_id = vp.id
LEFT JOIN voip_subscribers vs ON vs.id = vup.subscriber_id
LEFT JOIN voip_domains vd ON vd.id = vs.domain_id
LEFT JOIN voip_rewrite_rule_sets vrrs ON vrrs.callee_in_dpid = vup.value
LEFT JOIN voip_rewrite_rules vrr ON vrr.set_id = vrrs.id AND vrr.direction = 'in' AND vrr.field = 'callee'
WHERE vp.attribute = 'rewrite_callee_in_dpid' AND vs.username = ? AND vd.domain = ?
ORDER BY vrr.priority ASC;
]];
local dom_replacements_query = [[
SELECT vrr.match_pattern, vrr.replace_pattern FROM voip_preferences vp
LEFT JOIN voip_dom_preferences vdp ON vdp.attribute_id = vp.id
LEFT JOIN voip_domains vd ON vd.id = vdp.domain_id
LEFT JOIN voip_rewrite_rule_sets vrrs ON vrrs.callee_in_dpid = vdp.value
LEFT JOIN voip_rewrite_rules vrr ON vrr.set_id = vrrs.id AND vrr.direction = 'in' AND vrr.field = 'callee'
WHERE vp.attribute = 'rewrite_callee_in_dpid' AND vd.domain = ?
ORDER BY vrr.priority ASC;
]];
local locale_query = [[
SELECT vp.attribute, vup.value FROM voip_preferences vp
LEFT JOIN voip_usr_preferences vup ON vup.attribute_id = vp.id
LEFT JOIN voip_subscribers vs ON vs.id = vup.subscriber_id
LEFT JOIN voip_domains vd ON vd.id = vs.domain_id
WHERE (vp.attribute = 'ac' or vp.attribute = 'cc')
AND vs.username = ?
AND vd.domain = ?;
]];
local lookup_query = [[
SELECT username,domain FROM kamailio.dbaliases
WHERE alias_username=?;
]];
local mod_sql = module:require("sql");
local params = module:get_option("voip_sql", {
driver = "MySQL",
database = "provisioning",
username = "prosody",
password = "PW_PROSODY",
host = "localhost"
});
engine = mod_sql:create_engine(params);
engine:execute("SET NAMES 'utf8' COLLATE 'utf8_bin';");
function normalize_number(user, host, number)
local locale_info = {};
for row in engine:select(locale_query, user, host) do
locale_info["caller_"..row[1]] = row[2];
end
local replacement_regexes = {};
local usr_pref = 0;
for row in engine:select(usr_replacements_query, user, host) do
usr_pref = 1;
local patt, repl = row[1], row[2]
:gsub("%$avp%(s:([a-zA-Z_]+)%)", locale_info)
:gsub("\\", "%%"):gsub("%%%%", "\\");
table.insert(replacement_regexes, { patt, repl });
end
if usr_pref == 0 then
for row in engine:select(dom_replacements_query, host) do
local patt, repl = row[1], row[2]
:gsub("%$avp%(s:([a-zA-Z_]+)%)", locale_info)
:gsub("\\", "%%"):gsub("%%%%", "\\");
table.insert(replacement_regexes, { patt, repl });
end
end
for _, rule in ipairs(replacement_regexes) do
local new_number, n_matches = rex.gsub(number, rule[1], rule[2]);
if n_matches > 0 then
number = new_number;
break;
end
end
return number;
end
function search_by_number(number)
local results = {};
for result in engine:select(lookup_query, number) do
table.insert(results, result[1].."@"..result[2]);
end
return results;
end
module:depends("disco");
module:add_feature("jabber:iq:search");
module:hook("iq/host/jabber:iq:search:query", function(event)
local origin, stanza = event.origin, event.stanza;
if stanza.attr.type == "get" then
return origin.send(st.reply(stanza):add_child(get_reply));
else
local user, host = jid_split(stanza.attr.from);
local number = stanza.tags[1]:get_child_text("nick");
-- Reconnect to DB if necessary
if not engine.conn:ping() then
engine.conn = nil;
engine:connect();
end
number = normalize_number(user, host, number);
local reply = st.reply(stanza):query("jabber:iq:search");
for _, jid in ipairs(search_by_number(number)) do
reply:tag("item", { jid = jid }):up();
end
return origin.send(reply);
end
end);
function module.command(arg)
local jid = require "util.jid";
local warn = prosodyctl.show_warning;
local command = arg[1];
if not command then
warn("Valid subcommands: normalize");
return 0;
end
table.remove(arg, 1);
if command == "normalize" then
if #arg ~= 2 then
warn("Usage: normalize USER@HOST NUMBER");
return 1;
end
local user_jid, number = arg[1], arg[2];
local user, host = jid.prepped_split(user_jid);
if not (user and host) then
warn("Invalid JID: "..user_jid);
return 1;
end
print(normalize_number(user, host, number));
elseif command == "query" then
if #arg ~= 1 then
warn("Usage: query NUMBER");
warn(" NUMBER must be normalized (see 'normalize' command)");
return 1;
end
local results = search_by_number(arg[1]);
for _, jid in ipairs(results) do
print("", jid);
end
end
return 0;
end
Loading…
Cancel
Save