chore: remove unused mod_vnc_fcm_hin and mod_vnc_muc_fcm_hin modules
Neither _hin variant is enabled in the config (the active push modules are mod_vnc_fcm for 1:1 and mod_vnc_muc_fcm for MUC). Drop the dead files and update AGENTS.md to reference the active modules. Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
This commit is contained in:
@@ -73,6 +73,6 @@ Dockerized Prosody **13.0.6** XMPP server for VNCtalk, built against **Lua 5.4**
|
||||
|
||||
- Lua 5.4. Modules follow Prosody conventions (`module:hook`, `module:open_store`, `module:get_option_string`, `module:provides`).
|
||||
- Authentication is delegated to an external HTTP endpoint via `mod_auth_http_async` (`hybridaAuthUrl`) on the main VirtualHost; the global default is `internal_hashed`.
|
||||
- Push notifications: `mod_vnc_fcm` / `mod_vnc_fcm_hin` over a configurable FCM proxy URL (`fcm_api_url`).
|
||||
- Push notifications: `mod_vnc_fcm` (1:1) / `mod_vnc_muc_fcm` (MUC) over a configurable FCM proxy URL (`fcm_api_url`).
|
||||
- `mod_http_rest` exposes `/rest` accepting `text/xml` bodies, injected as XMPP stanzas (fires `vnc-rest-message`, consumed by the `mod_carbons`/`mod_mam` patches).
|
||||
- The `mod_mam` patch always stores (`shall_store → true`) and only archives stanzas with a `<body>`, because users live in the external HTTP auth backend so Prosody's `user_exists()` can't be trusted.
|
||||
|
||||
@@ -1,932 +0,0 @@
|
||||
--require "socket"
|
||||
--rawset(_G, "PROXY", false); -- socket module accesses global variable PROXY
|
||||
|
||||
local http = require "net.http"
|
||||
local json = require "util.json"
|
||||
-- local ltn12 = require "ltn12"
|
||||
local jid_bare = require "util.jid".bare;
|
||||
local jid_split = require "util.jid".split;
|
||||
local timer = require "util.timer";
|
||||
local st = require "util.stanza";
|
||||
local time_now = os.time;
|
||||
|
||||
local private_storage = module:open_store("private");
|
||||
local vcard_storage = module:open_store("vcard");
|
||||
local config_store = nil;
|
||||
local fcm_token_store = module:open_store("fcmtoken");
|
||||
local fcm_token_map_store = module:open_store("fcmtoken", "map");
|
||||
|
||||
local fcmAPIKey = module:get_option_string("fcm_api_key");
|
||||
local fcmAPIURL = module:get_option_string("fcm_api_url");
|
||||
|
||||
local moduleIsActive = fcmAPIURL and fcmAPIKey;
|
||||
|
||||
local isMUC = module:get_host_type() == "component";
|
||||
local ThisDomain = module.host;
|
||||
|
||||
local xmlns_sm2 = "urn:xmpp:sm:2";
|
||||
local xmlns_sm3 = "urn:xmpp:sm:3";
|
||||
|
||||
local ThisBroadcast = "broadcast@"..ThisDomain;
|
||||
|
||||
module:add_feature("urn:xmpp:vnctalk:fcm");
|
||||
|
||||
local inactive_devices = {};
|
||||
|
||||
local UDomain = ThisDomain;
|
||||
|
||||
if isMUC then
|
||||
local storage_host = module:get_option_string("storage_host");
|
||||
UDomain = storage_host;
|
||||
module:log("debug", "opening stores for host %s", storage_host);
|
||||
timer.add_task(3, function ()
|
||||
private_storage = module:open_store(storage_host, "private");
|
||||
vcard_storage = module:open_store(storage_host, "vcard");
|
||||
fcm_token_store = module:open_store(storage_host, "fcmtoken");
|
||||
fcm_token_map_store = module:open_store(storage_host, "fcmtoken", "map");
|
||||
if not private_storage or not vcard_storage then
|
||||
module:log("debug", "private/vcard_store %s/%s not found? - will try again", private_storage, vcard_storage);
|
||||
return 3;
|
||||
else
|
||||
module:log("debug", "private/vcard_store are now %s/%s", private_storage, vcard_storage);
|
||||
end
|
||||
end
|
||||
);
|
||||
config_store = module:open_store("config");
|
||||
end
|
||||
|
||||
local function contains(list, x)
|
||||
if (list) then
|
||||
for _, v in pairs(list) do
|
||||
if (v == x) then return true end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function starts_with(str, start)
|
||||
return str:sub(1, #start) == start
|
||||
end
|
||||
|
||||
local function dumpTable(t, depth)
|
||||
local result = "";
|
||||
if (not depth) then depth = 0 end;
|
||||
|
||||
local prefix = string.rep(" ", depth);
|
||||
|
||||
if (type(t) ~= "table") then
|
||||
result = result.." "..tostring(t);
|
||||
else
|
||||
for key,value in pairs(t) do
|
||||
result = result..prefix..tostring(key).." => "..dumpTable(value, depth+1).."\n"
|
||||
end
|
||||
end
|
||||
|
||||
return result;
|
||||
end
|
||||
|
||||
|
||||
local function deserializeDataElement(pdElement, expectedName)
|
||||
--module:log("debug", "deserializeDataElement("..expectedName..", "..dumpTable(pdElement)..")");
|
||||
if (not pdElement) then return nil end
|
||||
if (type(pdElement) ~= "table") then return nil end
|
||||
|
||||
if (pdElement[1] and pdElement["attr"] and pdElement["attr"]["key"] and (pdElement["attr"]["key"] == expectedName))
|
||||
then
|
||||
local result = json.decode(pdElement[1]);
|
||||
--module:log("debug", "deserializeDataElement() = '"..dumpTable(result).."'");
|
||||
return result;
|
||||
end
|
||||
return nil;
|
||||
end
|
||||
|
||||
|
||||
local function trim(s)
|
||||
if s and (type(s) == "string") then
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
else
|
||||
return s
|
||||
end
|
||||
end
|
||||
|
||||
local function collapseSpaces(s)
|
||||
if s and (type(s) == "string") then
|
||||
return (s:gsub("%s+", " "))
|
||||
else
|
||||
return s
|
||||
end
|
||||
end
|
||||
|
||||
local function prettyUsername(userName)
|
||||
userName = string.upper(string.sub(userName, 1, 1))..string.sub(userName, 2, -1) -- upcase first char in any case
|
||||
if string.find(userName, "%.") -- contains dot
|
||||
then
|
||||
local i = 1
|
||||
while true do
|
||||
local j = string.find(userName, "%.", i)
|
||||
if j == nil or #userName == i then break end
|
||||
-- replace dot with space and upcase next char
|
||||
userName = string.sub(userName, 1, j-1).." "..string.upper(string.sub(userName, j+1, j+1))..string.sub(userName, j+2, -1)
|
||||
if #userName <= j then break end
|
||||
i = j
|
||||
end
|
||||
end
|
||||
return trim(collapseSpaces(userName));
|
||||
end
|
||||
|
||||
|
||||
local function getDisplayName(userName)
|
||||
local vCard, err = vcard_storage:get(userName);
|
||||
if vCard then
|
||||
vCard = st.deserialize(vCard);
|
||||
end
|
||||
local name = nil;
|
||||
if not vCard or err then
|
||||
module:log("error", "Unable to get vCard for %s : %s ", userName, tostring(err));
|
||||
else
|
||||
name = vCard:find("{vcard-temp}FN#");
|
||||
end
|
||||
if not name then name = prettyUsername(userName) or userName end
|
||||
module:log("debug", "name for %s : %s", userName, name)
|
||||
return name;
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function removeKeyFromUser(userName, fcmId)
|
||||
local pd, pfFetchError = private_storage:get(userName);
|
||||
if (pfFetchError) then
|
||||
module:log(
|
||||
"error",
|
||||
"Fetching private data for '%s' failed : %s", tostring(userName), tostring(pfFetchError)
|
||||
);
|
||||
return 0,{};
|
||||
elseif (pd) then
|
||||
local removed = false;
|
||||
for key,value in pairs(pd)
|
||||
do
|
||||
--module:log("debug", "PDD("..userName..") : "..tostring(key).." => "..tostring(value));
|
||||
if ((key == "documents:stanza:io:json") and (type(value) == "table")) then
|
||||
--module:log("debug", "PDD.stanza("..userName..") : "..json.encode(value));
|
||||
for k2,v2 in pairs(value) do
|
||||
local fcm = deserializeDataElement(v2, "fcm");
|
||||
if (fcm)
|
||||
then
|
||||
module:log("debug", "removing fcmID %s from private data record: %s", fcmId, json.encode(fcm));
|
||||
fcm[fcmId] = nil;
|
||||
v2[1]=json.encode(fcm);
|
||||
removed = true;
|
||||
--module:log("debug", "AFTER PDD.stanza: "..json.encode(v2));
|
||||
--module:log("debug", "AFTER PDD: "..json.encode(value));
|
||||
--module:log("debug", "removed outdated key");
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if (removed)
|
||||
then
|
||||
local ok, errmsg = private_storage:set(userName, pd);
|
||||
if (not ok)
|
||||
then
|
||||
module:log("error", "failed to store private data for %s : '%s'", userName, tostring(errmsg));
|
||||
end
|
||||
else
|
||||
module:log("debug", "unable to remove fcmID %s from %s. Not found in data: %s", fcmId, userName, tostring(pd));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function getPostCallback(_fcmId, _userName)
|
||||
return function(body, code, response)
|
||||
local shortKey = string.sub(_fcmId, 1, 6)
|
||||
if code ~= 200 then
|
||||
module:log("error", "FCM result %s@%s : HTTP %s %s", _userName, shortKey, tostring(code), tostring(body))
|
||||
-- if body then module:log("error", body); end
|
||||
else
|
||||
module:log("debug", "FCM result %s@%s : HTTP %s %s", _userName, shortKey, tostring(code), tostring(body))
|
||||
local response2 = json.decode(body)
|
||||
if response2.results and (type(response2.results) == "table") and response2.results[1] and response2.results[1]["error"] == "NotRegistered"
|
||||
then
|
||||
-- module:log("debug", "%s key %s is outdated", _userName, shortKey);
|
||||
removeKeyFromUser(_userName, _fcmId);
|
||||
end
|
||||
if response2.results and (type(response2.results) == "table") and response2.results[1] and response2.results[1]["error"] == "MissingRegistration"
|
||||
then
|
||||
-- module:log("debug", "%s key %s is never registered", _userName, shortKey);
|
||||
removeKeyFromUser(_userName, _fcmId);
|
||||
end
|
||||
if response2.results and (type(response2.results) == "table") and response2.results[1] and response2.results[1]["error"] == "InvalidRegistration"
|
||||
then
|
||||
-- module:log("debug", "%s key %s is invalid", _userName, shortKey);
|
||||
removeKeyFromUser(_userName, _fcmId);
|
||||
end
|
||||
if response2.results and (type(response2.results) == "table") and response2.results[1] and response2.results[1]["error"] == "InvalidPackageName"
|
||||
then
|
||||
-- module:log("debug", "%s key %s is using invalid FCM package name", _userName, shortKey);
|
||||
removeKeyFromUser(_userName, _fcmId);
|
||||
end
|
||||
if response2.results and (type(response2.results) == "table") and response2.results[1] and response2.results[1]["error"] == "error:MessageTooBig"
|
||||
then
|
||||
-- module:log("debug", "%s key %s : message too big", _userName, shortKey);
|
||||
end
|
||||
if response2.results and (type(response2.results) == "table") and response2.results[1] and response2.results[1]["error"] == "InvalidDataKey"
|
||||
then
|
||||
-- module:log("debug", "%s key %s is using invalid data key", _userName, shortKey);
|
||||
end
|
||||
if response2.results and (type(response2.results) == "table") and response2.results[1] and response2.results[1]["error"] == "InvalidTtl"
|
||||
then
|
||||
--- module:log("debug", "%s key %s is using invalid TTL", _userName, shortKey);
|
||||
end
|
||||
end
|
||||
return false -- close request
|
||||
--return true -- keep request open
|
||||
end
|
||||
end
|
||||
|
||||
local function postFCM(_userName, _fcmId, _source, _body, _type, _senderName, _groupTopic, _attachment_type, _lang, _msgid, _vncTalkConferenceEtype, _vncTalkConferenceId, _nFromJid, _jitsiURL, _jitsiRoom)
|
||||
|
||||
if (not moduleIsActive) then return end;
|
||||
local domainname = "";
|
||||
local v_attachment = "";
|
||||
if isMUC then
|
||||
domainname = module:get_option_string("storage_host");
|
||||
else
|
||||
domainname = module.host;
|
||||
end
|
||||
|
||||
if (_attachment_type ~= "") and (_attachment_type ~=nil) then
|
||||
v_attachment = _attachment_type;
|
||||
end
|
||||
|
||||
local lsource = _source;
|
||||
local ltype = _type;
|
||||
local signal = nil;
|
||||
local nfrom = _source;
|
||||
local nJitsiURL = "";
|
||||
local nJitsiRoom = "";
|
||||
|
||||
if (_vncTalkConferenceId ~= nil) then
|
||||
if string.match(_vncTalkConferenceId, "@") then
|
||||
lsource = _vncTalkConferenceId;
|
||||
end
|
||||
end
|
||||
|
||||
if (_vncTalkConferenceEtype ~=nil) then
|
||||
signal = "1";
|
||||
ltype = _vncTalkConferenceEtype;
|
||||
end
|
||||
|
||||
if (_nFromJid ~= nil) then
|
||||
nfrom = _nFromJid;
|
||||
end
|
||||
|
||||
if (_jitsiURL ~= nil) then
|
||||
nJitsiURL = _jitsiURL;
|
||||
end
|
||||
|
||||
if (_jitsiRoom ~= nil) then
|
||||
nJitsiRoom = _jitsiRoom;
|
||||
end
|
||||
|
||||
local stamp = os.time();
|
||||
|
||||
local fcmRequest = {
|
||||
to = _fcmId,
|
||||
content_available = true,
|
||||
priority = "high",
|
||||
data = {
|
||||
nType = "local_notification", -- notification type
|
||||
eType = ltype, -- event type
|
||||
jid = lsource, -- source jid (room jid or 1:1 chat peer bare jid)
|
||||
nfrom = nfrom,
|
||||
nto = _userName.."@"..domainname,
|
||||
name = _senderName, -- group chat nick name or single chat peer vCard name",
|
||||
gt = _groupTopic, -- topic of room iff groupchat
|
||||
aft = v_attachment,
|
||||
callSignal = signal,
|
||||
jitsiURL = nJitsiURL,
|
||||
jitsiRoom = nJitsiRoom,
|
||||
t = stamp,
|
||||
lang = _lang,
|
||||
msgid = _msgid,
|
||||
body = _body -- notification body/text content
|
||||
}
|
||||
};
|
||||
|
||||
fcmRequest["android"] = { priority = "high", ttl = 345600 };
|
||||
fcmRequest["webpush"] = { headers = { Urgency = "high", TTL = 345600 } };
|
||||
|
||||
local data = json.encode(fcmRequest);
|
||||
|
||||
local httpRequestOptions = {
|
||||
method = "POST",
|
||||
body = data,
|
||||
headers = {
|
||||
["Connection"] = 'close',
|
||||
["Authorization"] = "key="..fcmAPIKey,
|
||||
["Content-Type"] = "application/json; charset=utf-8"
|
||||
}
|
||||
}
|
||||
|
||||
module:log("info", "sending notification to %s for token %s - from: %s - msgid: %s - body: %s", _userName.."@"..domainname, _fcmId, _source, _msgid, _body);
|
||||
-- ssl does not seem to work with net.http, so we proxy it
|
||||
--http.request("https://fcm.googleapis.com/fcm/send", httpRequestOptions, postCallback)
|
||||
module:log("info", "sendingHTTP request to %s", fcmAPIURL);
|
||||
http.request(fcmAPIURL, httpRequestOptions, getPostCallback(_fcmId, _userName))
|
||||
end
|
||||
|
||||
local function postFCMIOS(_userName, _fcmId, _source, _body, _type, _senderName, _groupTopic, _attachment_type, _lang, _msgid, _vncTalkConferenceEtype, _vncTalkConferenceId, _nFromJid, _jitsiURL, _jitsiRoom)
|
||||
|
||||
if (not moduleIsActive) then return end;
|
||||
local domainname = "";
|
||||
local ntitle = "";
|
||||
local nbody = "";
|
||||
local v_attachment = "";
|
||||
local nJitsiURL = "";
|
||||
local nJitsiRoom = "";
|
||||
|
||||
if isMUC then
|
||||
domainname = module:get_option_string("storage_host");
|
||||
if (_groupTopic ~= "") and (_groupTopic ~= nil) then
|
||||
ntitle = _groupTopic;
|
||||
else
|
||||
ntitle = jid_split(_source);
|
||||
end
|
||||
else
|
||||
domainname = module.host;
|
||||
if (_groupTopic ~= "") and (_groupTopic ~=nil) then
|
||||
ntitle = _groupTopic
|
||||
else
|
||||
if (_senderName ~= "") and (_senderName ~= nil) then
|
||||
ntitle = _senderName;
|
||||
else
|
||||
ntitle = _source;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (_attachment_type ~= "") and (_attachment_type ~=nil) then
|
||||
v_attachment = _attachment_type;
|
||||
end
|
||||
|
||||
local _click_action = _type:upper();
|
||||
|
||||
if (_click_action == "NORMAL") then
|
||||
_click_action = "CHAT";
|
||||
end
|
||||
|
||||
local lsource = _source;
|
||||
local ltype = _type;
|
||||
local signal = nil;
|
||||
local nfrom = _source;
|
||||
|
||||
if (_vncTalkConferenceId ~= nil) then
|
||||
if string.match(_vncTalkConferenceId, "@") then
|
||||
lsource = _vncTalkConferenceId;
|
||||
end
|
||||
end
|
||||
|
||||
if (_vncTalkConferenceEtype ~=nil) then
|
||||
signal = "1";
|
||||
ltype = _vncTalkConferenceEtype;
|
||||
end
|
||||
|
||||
if (_nFromJid ~= nil) then
|
||||
nfrom = _nFromJid;
|
||||
end
|
||||
|
||||
if (_jitsiURL ~= nil) then
|
||||
nJitsiURL = _jitsiURL;
|
||||
end
|
||||
|
||||
if (_jitsiRoom ~= nil) then
|
||||
nJitsiRoom = _jitsiRoom;
|
||||
end
|
||||
|
||||
local fcmRequest = {
|
||||
to = _fcmId,
|
||||
priority = "high",
|
||||
notification = {
|
||||
title = ntitle,
|
||||
body = _body,
|
||||
mutable_content = true,
|
||||
sound = "incoming-call-loop.caff",
|
||||
thread_id = lsource,
|
||||
click_action = _click_action
|
||||
},
|
||||
data = {
|
||||
nType = "local_notification", -- notification type
|
||||
eType = ltype, -- event type
|
||||
jid = lsource, -- source jid (room jid or 1:1 chat peer bare jid)
|
||||
nfrom = nfrom,
|
||||
nto = _userName.."@"..domainname,
|
||||
name = _senderName, -- group chat nick name or single chat peer vCard name",
|
||||
gt = ntitle, -- topic of room iff groupchat
|
||||
aft = v_attachment,
|
||||
callSignal = signal,
|
||||
jitsiURL = nJitsiURL,
|
||||
jitsiRoom = nJitsiRoom,
|
||||
lang = _lang,
|
||||
msgid = _msgid,
|
||||
body = _body -- notification body/text content
|
||||
}
|
||||
};
|
||||
|
||||
local data = json.encode(fcmRequest);
|
||||
|
||||
local httpRequestOptions = {
|
||||
method = "POST",
|
||||
body = data,
|
||||
headers = {
|
||||
["Connection"] = 'close',
|
||||
["Authorization"] = "key="..fcmAPIKey,
|
||||
["Content-Type"] = "application/json; charset=utf-8"
|
||||
}
|
||||
}
|
||||
|
||||
-- module:log("debug", "sending notification to %s for token %s - from: %s - msgid: %s - body: %s", _userName.."@"..domainname, _fcmId, _source, _msgid, string.sub(_body, 20).."...");
|
||||
module:log("debug", "sending notification to %s for token %s - from: %s - msgid: %s - body: %s", _userName.."@"..domainname, _fcmId, _source, _msgid, _body.."...");
|
||||
-- ssl does not seem to work with net.http, so we proxy it
|
||||
--http.request("https://fcm.googleapis.com/fcm/send", httpRequestOptions, postCallback)
|
||||
http.request(fcmAPIURL, httpRequestOptions, getPostCallback(_fcmId, _userName))
|
||||
end
|
||||
|
||||
|
||||
local function getNotifyOptionsForUser(userName)
|
||||
--module:log("debug", "getFCMtokenForUser("..userName..")");
|
||||
local pd, pfFetchError = private_storage:get(userName);
|
||||
if (pfFetchError) then
|
||||
module:log(
|
||||
"error",
|
||||
"Fetching private data for '%s' failed : %s", tostring(userName), tostring(pfFetchError)
|
||||
);
|
||||
return 0,{};
|
||||
elseif (pd) then
|
||||
local tokens;
|
||||
local nType;
|
||||
local nLang;
|
||||
for key,value in pairs(pd)
|
||||
do
|
||||
-- module:log("debug", "PD("..userName..") : "..tostring(key).." => "..tostring(value));
|
||||
module:log("debug", "PD( %s) : %s => %s ", userName,tostring(key),tostring(value));
|
||||
if ((key == "documents:stanza:io:json") and (type(value) == "table")) then
|
||||
--module:log("debug", "PD("..userName..") : "..json.encode(value));
|
||||
-- module:log("debug", "PD( %s ) : %s ", userName ,json.encode(value));
|
||||
for k2,v2 in pairs(value) do
|
||||
if (not tokens) then
|
||||
local fcm = deserializeDataElement(v2, "fcm");
|
||||
if (type(fcm) == "table") then
|
||||
tokens = {};
|
||||
for token,x in pairs(fcm) do
|
||||
-- module:log("debug", "token: %s - x[os]: %s", token, x["os"]);
|
||||
if (x["os"] ~= nil) then
|
||||
table.insert(tokens, token.."@"..x["os"])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if (not nType) then
|
||||
local options = deserializeDataElement(v2, "notifyOptions");
|
||||
if (options and (type(options) == "table") and options["type"]) then
|
||||
nType = tonumber(options["type"]);
|
||||
end
|
||||
end
|
||||
if (not nLang) then
|
||||
local options = deserializeDataElement(v2, "lang");
|
||||
-- module:log("debug", "PDLang: %s => %s", userName, json.encode(options));
|
||||
if (options) and (type(options) == "string") then
|
||||
nLang = options;
|
||||
end;
|
||||
-- module:log("debug", "type of options: %s", type(options));
|
||||
end
|
||||
end
|
||||
break; -- we can stop after the documents:stanza:io:json element
|
||||
end
|
||||
end
|
||||
--module:log("debug", "getNotifyOptionsForUser("..userName..") = "..tostring(tokens).." => "..tostring(nType));
|
||||
|
||||
local map_res = fcm_token_store:get(userName);
|
||||
|
||||
-- module:log("debug", "result from map store for %s is: %s", userName, dumpTable(map_res));
|
||||
|
||||
if (map_res) then
|
||||
for _device, _tkr in pairs(map_res) do
|
||||
-- module:log("debug", "got for %s device %s => %s", userName, _device, dumpTable(_tkr));
|
||||
-- module:log("debug", "got for %s device %s => token: %s - os: %s", userName, _device, _tkr.token, _tkr.os);
|
||||
local sessions = prosody.bare_sessions;
|
||||
local ubjid = userName.."@"..UDomain;
|
||||
local u_sessions = sessions[ubjid] or nil;
|
||||
local deviceonline = false;
|
||||
if (u_sessions) then
|
||||
local u_sessions_device = u_sessions["sessions"] or nil;
|
||||
if (u_sessions_device) then
|
||||
module:log("debug", "devise is %s", _device);
|
||||
-- module:log("debug", "u_sessions_device %s", dumpTable(u_sessions_device));
|
||||
local dsession = u_sessions_device[_device] or nil;
|
||||
-- module:log("debug", "dsession %s", dumpTable(dsession));
|
||||
if (dsession) then
|
||||
local hibernated = dsession["hibernated"] or nil;
|
||||
local hibernating = dsession["hibernating"] or nil;
|
||||
local awaiting_ack = dsession["awaiting_ack"] or nil;
|
||||
module:log("info", "found session for _device %s - hibernating: %s, hibernated %s", _device, hibernating, hibernated);
|
||||
if not ((hibernated) or (hibernating)) then
|
||||
local dev_in_background = inactive_devices[_device] or nil;
|
||||
if dev_in_background then
|
||||
if awaiting_ack then
|
||||
module:log("info", "device %s is still connected, but inactive and awaiting_ack", _device);
|
||||
else
|
||||
module:log("info", "device %s is still connected, but inactive", _device);
|
||||
deviceonline = true;
|
||||
end
|
||||
else
|
||||
if awaiting_ack then
|
||||
module:log("info", "device %s is connected and active, but awaiting_ack", _device);
|
||||
else
|
||||
module:log("info", "device %s is connected and active", _device);
|
||||
deviceonline = true;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not(deviceonline) then
|
||||
local already_added = contains(tokens, _tkr.token.."@".._tkr.os);
|
||||
module:log("debug","already_added: %s", _tkr.token.."@".._tkr.os);
|
||||
if not(tokens) then
|
||||
tokens = {};
|
||||
end
|
||||
if not(already_added) then
|
||||
table.insert(tokens, _tkr.token.."@".._tkr.os);
|
||||
end
|
||||
end
|
||||
-- module:log("debug","tokens table is now: %s", dumpTable(tokens));
|
||||
end
|
||||
end
|
||||
|
||||
if (not tokens) then tokens = {}; end;
|
||||
if (not nType) then nType = 0; end;
|
||||
--module:log("debug", "getNotifyOptionsForUser(%s) = %i, %i tokens", userName, nType, table.getn(tokens));
|
||||
-- module:log("debug", "getNotifyOptionsForUser(%s) = %i, %i tokens, lang %s", userName, nType, table.getn(tokens), nLang);
|
||||
local sessions = prosody.bare_sessions;
|
||||
local ubjid = userName.."@"..ThisDomain;
|
||||
for _user, _resdetails in pairs(sessions) do
|
||||
if (_user == ubjid) then
|
||||
for _res, _detail1 in pairs(_resdetails["sessions"]) do
|
||||
local hibernated = _detail1["hibernated"] or _detail1["hibernating"] or nil;
|
||||
if (hibernated) then
|
||||
module:log("info", "for _user: %s and _res: %s got hibernated since: %s", _user, _res, hibernated);
|
||||
else
|
||||
module:log("info", "for _user: %s and _res: %s got active session?", _user, _res);
|
||||
--module:log("debug", "for _user: %s and _res: %s got detail: %s", _user, _res, dumpTable(_detail1));
|
||||
end
|
||||
end
|
||||
-- module:log("debug", "session for _res %s is: %s", _res, dumpTable(_resdetails));
|
||||
end
|
||||
end
|
||||
-- module:log("debug", "sessions: %s", dumpTable(sessions[ubjid]));
|
||||
return nType, tokens, nLang;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function fcm_notify(userName, title, body, type, _senderName, _groupTopic, vnc_attachment_type, msgid, vncTalkConferenceEtype, vncTalkConferenceId, _nFrom, _jitsiURL, _jitsiRoom)
|
||||
if (not moduleIsActive) then return end;
|
||||
local nType, tokens, lang = getNotifyOptionsForUser(userName);
|
||||
if (tokens and (#tokens) > 0) and ((nType == 1) or (nType == 2) or vncTalkConferenceEtype)
|
||||
then
|
||||
module:log(
|
||||
"info", "in fcm_notify(%s, %s, %s) => type=%s, %s tokens",
|
||||
userName, title, body, tostring(nType), tostring((#tokens))
|
||||
);
|
||||
local sName = _senderName;
|
||||
local gTopic = _groupTopic;
|
||||
sName = "Neue Nachricht";
|
||||
gTopic = "Neue Nachricht";
|
||||
|
||||
if (lang == "en") then
|
||||
sName = "new message";
|
||||
gTopic = "new message";
|
||||
end;
|
||||
|
||||
if (lang == "fr") then
|
||||
sName = "Nouveau message";
|
||||
gTopic = "Nouveau message";
|
||||
end;
|
||||
|
||||
body = "";
|
||||
for i,token in pairs(tokens) do
|
||||
if (token)
|
||||
then
|
||||
local rtoken, ros = jid_split(token);
|
||||
-- module:log("debug","got rtoken: %s - os: %s ", rtoken, ros);
|
||||
if (ros == "ios") then
|
||||
-- module:log("debug", "postFCMIOS with (%s, %s, %s, %s, %s, %s, %s, %s, %s)", userName, rtoken, title, body, type, _senderName, _groupTopic, vnc_attachment_type, lang);
|
||||
postFCMIOS(userName, rtoken, title, body, type, sName, gTopic, vnc_attachment_type, lang, msgid, vncTalkConferenceEtype, vncTalkConferenceId, _nFrom, _jitsiURL, _jitsiRoom);
|
||||
else
|
||||
-- module:log("debug", "postFCM with (%s, %s, %s, %s, %s, %s, %s, %s, %s)", userName, rtoken, title, body, type, _senderName, _groupTopic, vnc_attachment_type, lang, _nFrom);
|
||||
postFCM(userName, rtoken, title, body, type, sName, gTopic, vnc_attachment_type, lang, msgid, vncTalkConferenceEtype, vncTalkConferenceId, _nFrom, _jitsiURL, _jitsiRoom);
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
module:log("debug", "fcm_notify(%s, %s, %s) => type=%s, no tokens", userName, title, body, tostring(nType));
|
||||
end
|
||||
end
|
||||
|
||||
-- build map from room nicknames to real JIDs
|
||||
local room_nick_jid = {} -- key1=roomJid, key2=occupantNickname, value=occupantJid
|
||||
local room_afffiliations = {} -- key1=roomJid, key2=occupantNickname, value=occupantJid
|
||||
module:hook("muc-room-changed", function (event)
|
||||
|
||||
--module:log("debug", "muc-room-changed "..event.room.jid.."\n"..tostring(event.room));
|
||||
|
||||
--if not room_nick_jid[event.room.jid]
|
||||
--then
|
||||
-- module:log("debug", "muc: new room "..tostring(event.room))
|
||||
--else
|
||||
-- module:log("debug", "muc: "..tostring(event.room).." changed")
|
||||
--end
|
||||
|
||||
room_nick_jid[event.room.jid] = {} -- reset mapping table for the current room
|
||||
local nick_jid = room_nick_jid[event.room.jid] -- mapping table for the current room
|
||||
|
||||
for nick, odata in pairs(event.room._occupants)
|
||||
do
|
||||
local jid = jid_bare(odata["jid"])
|
||||
nick_jid[nick]=jid
|
||||
-- module:log("debug", "muc nick "..nick.." => "..jid.." in "..event.room.jid);
|
||||
end
|
||||
|
||||
-- copy affiliations table
|
||||
room_afffiliations[event.room.jid] = {}
|
||||
for bareJid, role in pairs(event.room._affiliations)
|
||||
do
|
||||
room_afffiliations[event.room.jid][bareJid] = role;
|
||||
-- module:log("debug", "muc role %s %s %s", event.room.jid, bareJid, role);
|
||||
end
|
||||
end);
|
||||
|
||||
local function message_handler(event, fromLocal)
|
||||
--TODO; use stanza:find here
|
||||
-- module:log("debug", "MH0");
|
||||
local origin, stanza = event.origin, event.stanza;
|
||||
local message_id = event.stanza.attr.id;
|
||||
-- module:log("debug","message id: %s", event.stanza.attr.id);
|
||||
local type = stanza.attr.type or "normal";
|
||||
local from = jid_bare(stanza.attr.from);
|
||||
local to = jid_bare(stanza.attr.to) or from;
|
||||
|
||||
local vncTalkConferenceEtype = stanza:find("{xmpp:vnctalk}vncTalkConference/eventType#") or nil;
|
||||
|
||||
local vnctalk_broadcast = stanza:find("{xmpp:vnctalk}vncTalkBroadcast", "xmpp:vnctalk" ) or false;
|
||||
-- module:log("info", "vnctalk_avatarup broadcast: %s", vnctalk_broadcast);
|
||||
local vnctalk_avatarup = false;
|
||||
if (vnctalk_broadcast) then
|
||||
vnctalk_avatarup = vnctalk_broadcast.attr.avatarup or false;
|
||||
end
|
||||
if (to == ThisBroadcast) then
|
||||
vnctalk_avatarup = true;
|
||||
end
|
||||
|
||||
-- module:log("info", "handling message from=%s, to=%s", from, to);
|
||||
|
||||
if ((to ~= from) or ((to == from) and vncTalkConferenceEtype))
|
||||
then
|
||||
|
||||
local content = trim(stanza:find("body#"));
|
||||
local delayedDelivery = stanza:get_child("delay", "urn:xmpp:delay");
|
||||
|
||||
-- if we have a vncTalk incoming or whiteboard element, it overrides the type
|
||||
local vncTalkIncomingType = stanza:find("{xmpp:vnctalk}vncTalkConference/conferenceType#");
|
||||
|
||||
local vncTalkConferenceId = stanza:find("{xmpp:vnctalk}vncTalkConference/conferenceId#") or nil;
|
||||
local jitsiURL = stanza:find("{xmpp:vnctalk}vncTalkConference/jitsiURL#") or nil;
|
||||
local jitsiRoom = stanza:find("{xmpp:vnctalk}vncTalkConference/jitsiRoom#") or nil;
|
||||
-- module:log("debug", "vncTalkIncomingType: %s", vncTalkIncomingType);
|
||||
local vncTalkWhiteboard = stanza:find("{xmpp:vnctalk}whiteboard");
|
||||
local isSentCarbonMessage = stanza:get_child("sent", "urn:xmpp:carbons:2");
|
||||
local vnc_attachment_type = stanza:find("{xmpp:vnctalk}attachment/fileType#");
|
||||
|
||||
local vnctalk_broadcast = stanza:get_child("vncTalkBroadcast", "xmpp:vnctalk");
|
||||
local vnctalk_broadcast_childid = nil;
|
||||
if vnctalk_broadcast then
|
||||
if starts_with(to, "broadcast") then
|
||||
-- module:log("message is to broadcast - bailing out");
|
||||
return nil;
|
||||
end
|
||||
vnctalk_broadcast_childid = vnctalk_broadcast.attr.id;
|
||||
-- module:log("debug", "this is a broadcast message: %s", tostring(stanza));
|
||||
local vnctalk_broadcast_title = vnctalk_broadcast.attr.title;
|
||||
-- module:log("debug", "this is a broadcast title: %s", vnctalk_broadcast_title);
|
||||
local vnctalk_broadcast_target = vnctalk_broadcast.attr.origtarget;
|
||||
-- module:log("debug", "this is a broadcast target: %s", vnctalk_broadcast_target);
|
||||
local body = stanza:get_child("body");
|
||||
-- module:log("debug", "broadcast body: %s", content);
|
||||
-- module:log("debug", "jid_split(to): %s", jid_split(to));
|
||||
if (not(vnctalk_avatarup)) then
|
||||
fcm_notify(jid_split(to), vnctalk_broadcast_target, content, type, getDisplayName(jid_split(from)), "Broadcast: "..vnctalk_broadcast_title, vnc_attachment_type, message_id, vncTalkConferenceEtype, vncTalkConferenceId, nil, jitsiURL, jitsiRoom);
|
||||
end
|
||||
return nil;
|
||||
end
|
||||
--local isMessageCorrection = stanza:find("{urn:xmpp:message-correct:0}replace@id");
|
||||
|
||||
-- debug from here
|
||||
module:log("debug","continue to process message with body: %s", content);
|
||||
|
||||
local auxType = vncTalkIncomingType or (vncTalkWhiteboard and "whiteboard");
|
||||
|
||||
if (auxType)
|
||||
then
|
||||
content = auxType;
|
||||
type = auxType;
|
||||
end;
|
||||
|
||||
local doNotify = content and (content ~= " ") and (content ~= "") and (not(vnctalk_avatarup)) and (delayedDelivery == nil) and (isSentCarbonMessage == nil) and (
|
||||
(type == "chat") or (type == "groupchat") or (type == "audio") or (type == "video") or (type == "whiteboard") or (type == "screen")
|
||||
);
|
||||
|
||||
if (doNotify)
|
||||
then
|
||||
module:log("debug", "536-doNotify: %s -> %s fl=%s, type=%s, content=%s, carbon=%s, isMUC=%s => doNotify=%s",
|
||||
stanza.attr.from, stanza.attr.to, tostring(fromLocal), type, content, isSentCarbonMessage, tostring(isMUC), tostring(doNotify));
|
||||
if (not isMUC)
|
||||
then
|
||||
module:log("debug", "537-doNotify not isMUC: %s -> %s fl=%s, type=%s, content=%s, carbon=%s, isMUC=%s => doNotify=%s",
|
||||
stanza.attr.from, stanza.attr.to, tostring(fromLocal), type, content, isSentCarbonMessage, tostring(isMUC), tostring(doNotify));
|
||||
--if (fromLocal)
|
||||
--then
|
||||
-- module:log("debug", " ignoring message from local client");
|
||||
--module:log("debug", "not sending fromLocal from=%s, to=%s, type=%s, content=%s, isSentCarbonMessage=%s", from, to, type, content, isSentCarbonMessage);
|
||||
if fromLocal and (type ~= "groupchat") then
|
||||
fcm_notify(jid_split(to), from, content, type, getDisplayName(jid_split(from)), nil, vnc_attachment_type, message_id, vncTalkConferenceEtype, vncTalkConferenceId, nil, jitsiURL, jitsiRoom);
|
||||
else
|
||||
local fromuser2, fromdomain2 = jid_split(stanza.attr.from);
|
||||
if (type ~= "groupchat") and (fromdomain2 ~= ThisDomain) then
|
||||
fcm_notify(jid_split(to), from, content, type, getDisplayName(jid_split(from)), nil, vnc_attachment_type, message_id, vncTalkConferenceEtype, vncTalkConferenceId, nil, jitsiURL, jitsiRoom);
|
||||
else
|
||||
-- notify when not from a local domain
|
||||
if not (prosody.hosts[fromdomain2]) and type == "groupchat" then
|
||||
local rjnode, rjhost, rjres = jid_split(stanza.attr.from);
|
||||
local rdn, rdh = jid_split(rjres);
|
||||
local tdn, tdh, tdr = jid_split(stanza.attr.to);
|
||||
if ((rdn == tdn) and (rdh == tdh)) then
|
||||
module:log("info", "766 ... rdn=%s, tdn=%s, rdh=%s, tdh=%s", rdn, tdn, rdh, tdh);
|
||||
else
|
||||
module:log("info", "541-doNotify IOM: %s -> %s fl=%s, type=%s, content=%s, carbon=%s, isMUC=%s => doNotify=%s, rdn=%s",
|
||||
stanza.attr.from, stanza.attr.to, tostring(fromLocal), type, content, isSentCarbonMessage, tostring(isMUC), tostring(doNotify), rdn);
|
||||
|
||||
fcm_notify(jid_split(to), from, content, type, getDisplayName(rdn), nil, vnc_attachment_type, message_id, vncTalkConferenceEtype, vncTalkConferenceId, nil, jitsiURL, jitsiRoom);
|
||||
end
|
||||
else
|
||||
module:log("debug", " ignoring message");
|
||||
end
|
||||
end
|
||||
end
|
||||
--end
|
||||
|
||||
else -- MUC
|
||||
module:log("debug", "538-doNotify isMUC: %s -> %s fl=%s, type=%s, content=%s, carbon=%s, isMUC=%s => doNotify=%s",
|
||||
stanza.attr.from, stanza.attr.to, tostring(fromLocal), type, content, isSentCarbonMessage, tostring(isMUC), tostring(doNotify));
|
||||
|
||||
local muc, host = jid_split(to);
|
||||
if prosody.hosts[host] then
|
||||
module:log("info","muc conf: %s", dumpTable(prosody.hosts[host].modules.muc));
|
||||
-- module:log("debug","muc conf: %s", dumpTable(prosody.hosts[host].modules.muc.rooms[to]));
|
||||
-- module:log("debug","muc affiliations: %s", dumpTable(prosody.hosts[host].modules.muc.rooms[to]._affiliations));
|
||||
module.log("info", "processing to and found local muc component: %s", to);
|
||||
local affs = prosody.hosts[host].modules.muc.rooms[to]._affiliations;
|
||||
if affs then
|
||||
for _aff, role in pairs(affs) do
|
||||
local now = time_now();
|
||||
local roomTopic = prosody.hosts[host].modules.muc.rooms[to]._data.subject or nil;
|
||||
module:log("info", "got muc _aff %s from muc %s", _aff, to);
|
||||
if from ~= _aff then
|
||||
module:log("info", " notify MUC affilaite Jid=%s", _aff);
|
||||
module:log("debug", "muc notifiy from: %s => to: %s", from, to);
|
||||
local roomJid = to;
|
||||
fcm_notify(jid_split(_aff), roomJid, content, type, getDisplayName(jid_split(from)), roomTopic, vnc_attachment_type, message_id, vncTalkConferenceEtype, vncTalkConferenceId, from, jitsiURL, jitsiRoom);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
module:log("debug", "ignoring from=%s, to=%s, type=%s, content=%s", from, to, type, content);
|
||||
end
|
||||
end
|
||||
|
||||
return;
|
||||
end
|
||||
|
||||
local function iom_muc_handler(event)
|
||||
-- module:log("debug", "iom muc handler - event: %s", dumpTable(event));
|
||||
local origin, stanza = event.origin, event.stanza;
|
||||
local message_id = event.stanza.attr.id;
|
||||
-- module:log("debug","message id: %s", event.stanza.attr.id);
|
||||
local type = stanza.attr.type or "normal";
|
||||
local from = jid_bare(stanza.attr.from);
|
||||
local to = jid_bare(stanza.attr.to) or from;
|
||||
local fromloc,fromhost = jid_split(from);
|
||||
local toloc,tohost = jid_split(to);
|
||||
if (prosody.hosts[tohost] and (prosody.hosts[fromhost] == nil)) then
|
||||
module:log("debug", "iom message type %s from host %s - to host %s", type, fromhost, tohost);
|
||||
return message_handler(event, false);
|
||||
else
|
||||
return nil;
|
||||
end
|
||||
end
|
||||
|
||||
local function message_handler_to_local(event)
|
||||
return message_handler(event, false);
|
||||
end
|
||||
|
||||
local function message_handler_from_local(event)
|
||||
return message_handler(event, true);
|
||||
end
|
||||
|
||||
local function logCsiEvent(event, active)
|
||||
local csires = event.origin.resource or nil;
|
||||
if active
|
||||
then
|
||||
inactive_devices[csires] = nil;
|
||||
module:log("debug", "ACTIVE: %s", tostring(event.origin));
|
||||
module:log("debug", "ACTIVE resource %s", csires);
|
||||
-- module:log("debug", "ACTIVE: %s", dumpTable(event.origin));
|
||||
else
|
||||
module:log("debug", "INACTIVE: %s", tostring(event.origin));
|
||||
-- module:log("debug", "INACTIVE: %s", dumpTable(event.origin));
|
||||
module:log("debug", "INACTIVE resource %s", csires);
|
||||
local t = os.time();
|
||||
inactive_devices[csires] = t;
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_iq(event)
|
||||
local origin, stanza = event.origin, event.stanza;
|
||||
local from_node, from_host, from_res = jid_split(stanza.attr.from);
|
||||
local reply = st.reply(stanza);
|
||||
local res = false;
|
||||
if stanza.attr.type == "set" then
|
||||
local fcm_child = stanza:get_child("add", "xmpp:vnctalk:fcm") or nil;
|
||||
if (fcm_child) then
|
||||
local fcm_token = fcm_child:get_child("fcm", "xmpp:vnctalk:fcm") or nil;
|
||||
if (fcm_token) then
|
||||
local _device = fcm_token.attr.device or nil;
|
||||
local _token = fcm_token.attr.token or nil;
|
||||
local _os = fcm_token.attr.os or nil;
|
||||
module:log("debug", "going to add token for %s - device %s, token: %s ", from_node, _device, _token);
|
||||
local do_add_token = (_device) and (_token) and (_os);
|
||||
if (do_add_token) then
|
||||
local tk_os = { token = _token , os = _os };
|
||||
local _store_fcm = fcm_token_map_store:set(from_node, _device, tk_os);
|
||||
res = true;
|
||||
origin.send(st.reply(stanza):tag('add', {xmlns='xmpp:vnctalk:fcm'}):text("ok"));
|
||||
return true;
|
||||
-- module:log("debug", "going to add token for ")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if res then
|
||||
return true;
|
||||
end
|
||||
end
|
||||
|
||||
if (moduleIsActive)
|
||||
then
|
||||
-- Stanszas to local clients
|
||||
module:hook("message/bare", message_handler_to_local, 2);
|
||||
module:hook("message/full", iom_muc_handler, 2);
|
||||
--module:hook("message/full", message_handler_to_local, 2);
|
||||
-- Stanzas sent by local clients
|
||||
module:hook("pre-message/bare", message_handler_from_local, 2);
|
||||
module:hook("pre-message/full", message_handler_from_local, 2);
|
||||
|
||||
module:hook("csi-client-active", function(event) logCsiEvent(event, true); end);
|
||||
module:hook("csi-client-inactive", function(event) logCsiEvent(event, false); end);
|
||||
|
||||
-- to track new connection
|
||||
module:hook("resource-bind", function(event)
|
||||
-- module:log("debug", "resource bind event %s", dumpTable(event.session.resource));
|
||||
local resbind = event.session.resource;
|
||||
inactive_devices[resbind] = nil;
|
||||
end);
|
||||
|
||||
module:hook_stanza(xmlns_sm3, "resume", function (event)
|
||||
-- module:log("debug", "resource bind event %s", dumpTable(event.session.resource));
|
||||
end);
|
||||
|
||||
-- module:hook("pre-iq/full", handle_iq, 1);
|
||||
module:hook("pre-iq/bare", handle_iq, 100);
|
||||
-- module:hook("pre-iq/host", handle_iq, 1);
|
||||
|
||||
-- module:hook("iq/self/urn:xmpp:vnctalk:fcm", handle_iq, -1);
|
||||
-- module:hook("iq/bare/urn:xmpp:vnctalk:fcm", handle_iq, -1);
|
||||
-- module:hook("iq/host/urn:xmpp:vnctalk:fcm", handle_iq, -1);
|
||||
|
||||
module:log("info", "FCM notifications ACTIVATED");
|
||||
end
|
||||
@@ -1,655 +0,0 @@
|
||||
-- mod_muc_notifications
|
||||
--
|
||||
--
|
||||
-- This file is MIT/X11 licensed.
|
||||
--
|
||||
-- A module to notify non-present members of messages in a group chat
|
||||
--
|
||||
|
||||
local http = require "net.http";
|
||||
local storagemanager = require "core.storagemanager";
|
||||
local json = require "util.json";
|
||||
-- local ltn12 = require "ltn12"
|
||||
local jid_bare = require "util.jid".bare;
|
||||
local jid_split = require "util.jid".split;
|
||||
local timer = require "util.timer";
|
||||
local id = require"util.id"
|
||||
local st = require"util.stanza"
|
||||
local storage_host = module:get_option_string("storage_host");
|
||||
|
||||
module:log("info","founs storage_host: %s", storage_host);
|
||||
|
||||
|
||||
local fcmAPIKey = module:get_option_string("fcm_api_key");
|
||||
local fcmAPIURL = module:get_option_string("fcm_api_url");
|
||||
|
||||
local moduleIsActive = fcmAPIURL and fcmAPIKey;
|
||||
|
||||
local inactive_devices = {};
|
||||
|
||||
local ThisDomain = module.host;
|
||||
|
||||
local xmlns_sm2 = "urn:xmpp:sm:2";
|
||||
local xmlns_sm3 = "urn:xmpp:sm:3";
|
||||
|
||||
|
||||
local fcm_token_store = module:open_store("fcmtoken");
|
||||
local fcm_token_map_store = module:open_store("fcmtoken", "map");
|
||||
local vcard_storage = module:open_store("vcard");
|
||||
local private_storage = module:open_store("private");
|
||||
|
||||
timer.add_task(3, function ()
|
||||
private_storage = storagemanager.open(storage_host, "private");
|
||||
vcard_storage = storagemanager.open(storage_host, "vcard");
|
||||
fcm_token_store = storagemanager.open(storage_host, "fcmtoken");
|
||||
fcm_token_map_store = storagemanager.open(storage_host, "fcmtoken", "map");
|
||||
if not private_storage or not vcard_storage then
|
||||
module:log("info", "private/vcard_store %s/%s not found? - will try again", private_storage, vcard_storage);
|
||||
return 3;
|
||||
else
|
||||
module:log("info", "private/vcard_store are now %s/%s", private_storage, vcard_storage);
|
||||
end
|
||||
end
|
||||
);
|
||||
|
||||
|
||||
-- some helper functions
|
||||
local function deserializeDataElement(pdElement, expectedName)
|
||||
--module:log("debug", "deserializeDataElement("..expectedName..", "..dumpTable(pdElement)..")");
|
||||
if (not pdElement) then return nil end
|
||||
if (type(pdElement) ~= "table") then return nil end
|
||||
|
||||
if (pdElement[1] and pdElement["attr"] and pdElement["attr"]["key"] and (pdElement["attr"]["key"] == expectedName))
|
||||
then
|
||||
local result = json.decode(pdElement[1]);
|
||||
--module:log("debug", "deserializeDataElement() = '"..dumpTable(result).."'");
|
||||
return result;
|
||||
end
|
||||
return nil;
|
||||
end
|
||||
|
||||
|
||||
local function contains(list, x)
|
||||
if (list) then
|
||||
for _, v in pairs(list) do
|
||||
if (v == x) then return true end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function starts_with(str, start)
|
||||
return str:sub(1, #start) == start
|
||||
end
|
||||
|
||||
local function trim(s)
|
||||
if s and (type(s) == "string") then
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
else
|
||||
return s
|
||||
end
|
||||
end
|
||||
|
||||
local function collapseSpaces(s)
|
||||
if s and (type(s) == "string") then
|
||||
return (s:gsub("%s+", " "))
|
||||
else
|
||||
return s
|
||||
end
|
||||
end
|
||||
|
||||
local function dumpTable(t, depth)
|
||||
local result = "";
|
||||
if (not depth) then depth = 0 end;
|
||||
|
||||
local prefix = string.rep(" ", depth);
|
||||
|
||||
if (type(t) ~= "table") then
|
||||
result = result.." "..tostring(t);
|
||||
else
|
||||
for key,value in pairs(t) do
|
||||
result = result..prefix..tostring(key).." => "..dumpTable(value, depth+1).."\n"
|
||||
end
|
||||
end
|
||||
|
||||
return result;
|
||||
end
|
||||
|
||||
|
||||
local function prettyUsername(userName)
|
||||
userName = string.upper(string.sub(userName, 1, 1))..string.sub(userName, 2, -1) -- upcase first char in any case
|
||||
if string.find(userName, "%.") -- contains dot
|
||||
then
|
||||
local i = 1
|
||||
while true do
|
||||
local j = string.find(userName, "%.", i)
|
||||
if j == nil or #userName == i then break end
|
||||
-- replace dot with space and upcase next char
|
||||
userName = string.sub(userName, 1, j-1).." "..string.upper(string.sub(userName, j+1, j+1))..string.sub(userName, j+2, -1)
|
||||
if #userName <= j then break end
|
||||
i = j
|
||||
end
|
||||
end
|
||||
return trim(collapseSpaces(userName));
|
||||
end
|
||||
|
||||
|
||||
local function getDisplayName(userName)
|
||||
-- module:log("info", "getDisplayName user: %s", userName);
|
||||
local vCard, err = vcard_storage:get(userName);
|
||||
if vCard then
|
||||
vCard = st.deserialize(vCard);
|
||||
end
|
||||
local name = nil;
|
||||
if not vCard or err then
|
||||
module:log("debug", "Unable to get vCard for %s : %s ", userName, tostring(err));
|
||||
else
|
||||
name = vCard:find("{vcard-temp}FN#");
|
||||
end
|
||||
if not name then name = prettyUsername(userName) or userName end
|
||||
-- module:log("info", "name for %s : %s", userName, name)
|
||||
return name;
|
||||
end
|
||||
|
||||
local function getPostCallback(_fcmId, _userName)
|
||||
return function(body, code, response)
|
||||
local shortKey = string.sub(_fcmId, 1, 6)
|
||||
if code ~= 200 then
|
||||
module:log("info", "FCM result %s@%s : HTTP %s %s", _userName, shortKey, tostring(code), tostring(body))
|
||||
-- if body then module:log("error", body); end
|
||||
else
|
||||
module:log("debug", "FCM result %s@%s : HTTP %s %s", _userName, shortKey, tostring(code), tostring(body))
|
||||
end
|
||||
return false -- close request
|
||||
--return true -- keep request open
|
||||
end
|
||||
end
|
||||
|
||||
local function postFCM(_userName, _fcmId, _source, _body, _type, _senderName, _groupTopic, _attachment_type, _lang, _msgid, _vncTalkConferenceEtype, _vncTalkConferenceId, _nFromJid, _jitsiURL, _jitsiRoom)
|
||||
|
||||
if (not moduleIsActive) then return end;
|
||||
local domainname = "";
|
||||
local v_attachment = "";
|
||||
domainname = module:get_option_string("storage_host");
|
||||
|
||||
if (_attachment_type ~= "") and (_attachment_type ~=nil) then
|
||||
v_attachment = _attachment_type;
|
||||
end
|
||||
|
||||
local lsource = _source;
|
||||
local ltype = _type;
|
||||
local signal = nil;
|
||||
local nfrom = _source;
|
||||
local nJitsiURL = "";
|
||||
local nJitsiRoom = "";
|
||||
|
||||
if (_vncTalkConferenceId ~= nil) then
|
||||
if string.match(_vncTalkConferenceId, "@") then
|
||||
lsource = _vncTalkConferenceId;
|
||||
end
|
||||
end
|
||||
|
||||
if (_vncTalkConferenceEtype ~=nil) then
|
||||
signal = "1";
|
||||
ltype = _vncTalkConferenceEtype;
|
||||
end
|
||||
|
||||
if (_nFromJid ~= nil) then
|
||||
nfrom = _nFromJid;
|
||||
end
|
||||
|
||||
if (_jitsiURL ~= nil) then
|
||||
nJitsiURL = _jitsiURL;
|
||||
end
|
||||
|
||||
if (_jitsiRoom ~= nil) then
|
||||
nJitsiRoom = _jitsiRoom;
|
||||
end
|
||||
|
||||
local stamp = os.time();
|
||||
|
||||
module:log("info", "postFCM username %s", _userName);
|
||||
local uname = "";
|
||||
if string.match(_userName, "@") then
|
||||
uname = _userName;
|
||||
else
|
||||
uname = _userName.."@"..domainname;
|
||||
end
|
||||
|
||||
local fcmRequest = {
|
||||
to = _fcmId,
|
||||
content_available = true,
|
||||
priority = "high",
|
||||
data = {
|
||||
nType = "local_notification", -- notification type
|
||||
eType = ltype, -- event type
|
||||
jid = lsource, -- source jid (room jid or 1:1 chat peer bare jid)
|
||||
nfrom = nfrom,
|
||||
nto = uname,
|
||||
name = _senderName, -- group chat nick name or single chat peer vCard name",
|
||||
gt = _groupTopic, -- topic of room iff groupchat
|
||||
aft = v_attachment,
|
||||
callSignal = signal,
|
||||
jitsiURL = nJitsiURL,
|
||||
jitsiRoom = nJitsiRoom,
|
||||
t = stamp,
|
||||
lang = _lang,
|
||||
msgid = _msgid,
|
||||
body = _body -- notification body/text content
|
||||
}
|
||||
};
|
||||
|
||||
fcmRequest["android"] = { priority = "high", ttl = 345600 };
|
||||
fcmRequest["webpush"] = { headers = { Urgency = "high", TTL = 345600 } };
|
||||
|
||||
local data = json.encode(fcmRequest);
|
||||
|
||||
local httpRequestOptions = {
|
||||
method = "POST",
|
||||
body = data,
|
||||
headers = {
|
||||
["Connection"] = 'close',
|
||||
["Authorization"] = "key="..fcmAPIKey,
|
||||
["Content-Type"] = "application/json; charset=utf-8"
|
||||
}
|
||||
}
|
||||
|
||||
-- module:log("info", "sending notification to %s for token %s - from: %s - msgid: %s - body: %s", _userName.."@"..domainname, _fcmId, _source, _msgid, _body);
|
||||
-- ssl does not seem to work with net.http, so we proxy it
|
||||
--http.request("https://fcm.googleapis.com/fcm/send", httpRequestOptions, postCallback)
|
||||
http.request(fcmAPIURL, httpRequestOptions, getPostCallback(_fcmId, _userName))
|
||||
end
|
||||
|
||||
local function postFCMIOS(_userName, _fcmId, _source, _body, _type, _senderName, _groupTopic, _attachment_type, _lang, _msgid, _vncTalkConferenceEtype, _vncTalkConferenceId, _nFromJid, _jitsiURL, _jitsiRoom)
|
||||
|
||||
if (not moduleIsActive) then return end;
|
||||
local domainname = "";
|
||||
local ntitle = "";
|
||||
local nbody = "";
|
||||
local v_attachment = "";
|
||||
local nJitsiURL = "";
|
||||
local nJitsiRoom = "";
|
||||
|
||||
domainname = module:get_option_string("storage_host");
|
||||
if (_groupTopic ~= "") and (_groupTopic ~= nil) then
|
||||
ntitle = _groupTopic;
|
||||
else
|
||||
ntitle = jid_split(_source);
|
||||
end
|
||||
|
||||
if (_attachment_type ~= "") and (_attachment_type ~=nil) then
|
||||
v_attachment = _attachment_type;
|
||||
end
|
||||
|
||||
local _click_action = _type:upper();
|
||||
|
||||
if (_click_action == "NORMAL") then
|
||||
_click_action = "CHAT";
|
||||
end
|
||||
|
||||
local lsource = _source;
|
||||
local ltype = _type;
|
||||
local signal = nil;
|
||||
local nfrom = _source;
|
||||
|
||||
if (_vncTalkConferenceId ~= nil) then
|
||||
if string.match(_vncTalkConferenceId, "@") then
|
||||
lsource = _vncTalkConferenceId;
|
||||
end
|
||||
end
|
||||
|
||||
if (_vncTalkConferenceEtype ~=nil) then
|
||||
signal = "1";
|
||||
ltype = _vncTalkConferenceEtype;
|
||||
end
|
||||
|
||||
if (_nFromJid ~= nil) then
|
||||
nfrom = _nFromJid;
|
||||
end
|
||||
if (_jitsiURL ~= nil) then
|
||||
nJitsiURL = _jitsiURL;
|
||||
end
|
||||
|
||||
if (_jitsiRoom ~= nil) then
|
||||
nJitsiRoom = _jitsiRoom;
|
||||
end
|
||||
|
||||
local fcmRequest = {
|
||||
to = _fcmId,
|
||||
priority = "high",
|
||||
notification = {
|
||||
title = ntitle,
|
||||
body = _body,
|
||||
mutable_content = true,
|
||||
sound = "incoming-call-loop.caff",
|
||||
thread_id = lsource,
|
||||
click_action = _click_action
|
||||
},
|
||||
data = {
|
||||
nType = "local_notification", -- notification type
|
||||
eType = ltype, -- event type
|
||||
jid = lsource, -- source jid (room jid or 1:1 chat peer bare jid)
|
||||
nfrom = nfrom,
|
||||
nto = _userName.."@"..domainname,
|
||||
name = _senderName, -- group chat nick name or single chat peer vCard name",
|
||||
gt = ntitle, -- topic of room iff groupchat
|
||||
aft = v_attachment,
|
||||
callSignal = signal,
|
||||
jitsiURL = nJitsiURL,
|
||||
jitsiRoom = nJitsiRoom,
|
||||
lang = _lang,
|
||||
msgid = _msgid,
|
||||
body = _body -- notification body/text content
|
||||
}
|
||||
};
|
||||
|
||||
local data = json.encode(fcmRequest);
|
||||
|
||||
local httpRequestOptions = {
|
||||
method = "POST",
|
||||
body = data,
|
||||
headers = {
|
||||
["Connection"] = 'close',
|
||||
["Authorization"] = "key="..fcmAPIKey,
|
||||
["Content-Type"] = "application/json; charset=utf-8"
|
||||
}
|
||||
}
|
||||
|
||||
-- module:log("debug", "sending notification to %s for token %s - from: %s - msgid: %s - body: %s", _userName.."@"..domainname, _fcmId, _source, _msgid, string.sub(_body, 20).."...");
|
||||
module:log("debug", "sending notification to %s for token %s - from: %s - msgid: %s - body: %s", _userName.."@"..domainname, _fcmId, _source, _msgid, _body.."...");
|
||||
-- ssl does not seem to work with net.http, so we proxy it
|
||||
--http.request("https://fcm.googleapis.com/fcm/send", httpRequestOptions, postCallback)
|
||||
module:log("debug", "calling http.request -- fcmAPIURL: %s", fcmAPIURL);
|
||||
http.request(fcmAPIURL, httpRequestOptions, getPostCallback(_fcmId, _userName))
|
||||
end
|
||||
|
||||
|
||||
-- Given a stanza, compute if it qualifies as important (notifiable)
|
||||
-- return true for message stanzas with non-empty body
|
||||
-- Should probably use something similar to muc-message-is-historic event
|
||||
local function is_important(stanza)
|
||||
local body = stanza:find("body#")
|
||||
return body and #body
|
||||
end
|
||||
|
||||
|
||||
-- get notify options for local users
|
||||
local function getNotifyOptionsForUser(userName)
|
||||
--module:log("debug", "getFCMtokenForUser("..userName..")");
|
||||
local pd, pfFetchError = private_storage:get(userName);
|
||||
if (pfFetchError) then
|
||||
module:log(
|
||||
"error",
|
||||
"Fetching private data for '%s' failed : %s", tostring(userName), tostring(pfFetchError)
|
||||
);
|
||||
return 0,{};
|
||||
elseif (pd) then
|
||||
local tokens;
|
||||
local nType;
|
||||
local nLang;
|
||||
for key,value in pairs(pd)
|
||||
do
|
||||
-- module:log("info", "PD("..userName..") : "..tostring(key).." => "..tostring(value));
|
||||
module:log("debug", "PD( %s) : %s => %s ", userName,tostring(key),tostring(value));
|
||||
if ((key == "documents:stanza:io:json") and (type(value) == "table")) then
|
||||
--module:log("debug", "PD("..userName..") : "..json.encode(value));
|
||||
-- module:log("debug", "PD( %s ) : %s ", userName ,json.encode(value));
|
||||
for k2,v2 in pairs(value) do
|
||||
if (not tokens) then
|
||||
local fcm = deserializeDataElement(v2, "fcm");
|
||||
if (type(fcm) == "table") then
|
||||
tokens = {};
|
||||
for token,x in pairs(fcm) do
|
||||
-- module:log("debug", "token: %s - x[os]: %s", token, x["os"]);
|
||||
if (x["os"] ~= nil) then
|
||||
table.insert(tokens, token.."@"..x["os"])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if (not nType) then
|
||||
local options = deserializeDataElement(v2, "notifyOptions");
|
||||
if (options and (type(options) == "table") and options["type"]) then
|
||||
nType = tonumber(options["type"]);
|
||||
end
|
||||
end
|
||||
if (not nLang) then
|
||||
local options = deserializeDataElement(v2, "lang");
|
||||
-- module:log("debug", "PDLang: %s => %s", userName, json.encode(options));
|
||||
if (options) and (type(options) == "string") then
|
||||
nLang = options;
|
||||
end;
|
||||
-- module:log("debug", "type of options: %s", type(options));
|
||||
end
|
||||
end
|
||||
break; -- we can stop after the documents:stanza:io:json element
|
||||
end
|
||||
end
|
||||
--module:log("debug", "getNotifyOptionsForUser("..userName..") = "..tostring(tokens).." => "..tostring(nType));
|
||||
|
||||
local map_res = fcm_token_store:get(userName);
|
||||
|
||||
-- module:log("debug", "result from map store for %s is: %s", userName, dumpTable(map_res));
|
||||
|
||||
if (map_res) then
|
||||
for _device, _tkr in pairs(map_res) do
|
||||
-- module:log("debug", "got for %s device %s => %s", userName, _device, dumpTable(_tkr));
|
||||
-- module:log("debug", "got for %s device %s => token: %s - os: %s", userName, _device, _tkr.token, _tkr.os);
|
||||
local sessions = prosody.bare_sessions;
|
||||
local ubjid = userName.."@"..storage_host;
|
||||
local u_sessions = sessions[ubjid] or nil;
|
||||
local deviceonline = false;
|
||||
if (u_sessions) then
|
||||
local u_sessions_device = u_sessions["sessions"] or nil;
|
||||
if (u_sessions_device) then
|
||||
-- module:log("info", "devise is %s", _device);
|
||||
-- module:log("debug", "u_sessions_device %s", dumpTable(u_sessions_device));
|
||||
local dsession = u_sessions_device[_device] or nil;
|
||||
-- module:log("debug", "dsession %s", dumpTable(dsession));
|
||||
if (dsession) then
|
||||
local hibernated = dsession["hibernated"] or nil;
|
||||
local hibernating = dsession["hibernating"] or nil;
|
||||
local awaiting_ack = dsession["awaiting_ack"] or nil;
|
||||
module:log("info", "found session for _device %s - hibernating: %s, hibernated %s", _device, hibernating, hibernated);
|
||||
if not ((hibernated) or (hibernating)) then
|
||||
local dev_in_background = inactive_devices[_device] or nil;
|
||||
if dev_in_background then
|
||||
if awaiting_ack then
|
||||
module:log("debug", "device %s is still connected, but inactive and awaiting_ack", _device);
|
||||
-- module:log("info", "handling1: %s", _tkr.token.."@".._tkr.os);
|
||||
else
|
||||
module:log("debug", "device %s is still connected, but inactive", _device);
|
||||
-- module:log("info", "handling2: %s", _tkr.token.."@".._tkr.os);
|
||||
if (_tkr.os ~= "ios") then
|
||||
deviceonline = true;
|
||||
end
|
||||
end
|
||||
else
|
||||
if awaiting_ack then
|
||||
module:log("debug", "device %s is connected and active, but awaiting_ack", _device);
|
||||
-- module:log("info", "handling3: %s", _tkr.token.."@".._tkr.os);
|
||||
else
|
||||
module:log("debug", "device %s is connected and active", _device);
|
||||
-- module:log("info", "handling4: %s", _tkr.token.."@".._tkr.os);
|
||||
if (_tkr.os ~= "ios") then
|
||||
deviceonline = true;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not(deviceonline) then
|
||||
local already_added = contains(tokens, _tkr.token.."@".._tkr.os);
|
||||
module:log("debug","already_added: %s", _tkr.token.."@".._tkr.os);
|
||||
if not(tokens) then
|
||||
tokens = {};
|
||||
end
|
||||
if not(already_added) then
|
||||
table.insert(tokens, _tkr.token.."@".._tkr.os);
|
||||
end
|
||||
end
|
||||
-- module:log("debug","tokens table is now: %s", dumpTable(tokens));
|
||||
end
|
||||
end
|
||||
|
||||
if (not tokens) then tokens = {}; end;
|
||||
if (not nType) then nType = 0; end;
|
||||
local sessions = prosody.bare_sessions;
|
||||
local ubjid = userName.."@"..ThisDomain;
|
||||
for _user, _resdetails in pairs(sessions) do
|
||||
if (_user == ubjid) then
|
||||
for _res, _detail1 in pairs(_resdetails["sessions"]) do
|
||||
local hibernated = _detail1["hibernated"] or _detail1["hibernating"] or nil;
|
||||
if (hibernated) then
|
||||
module:log("info", "for _user: %s and _res: %s got hibernated since: %s", _user, _res, hibernated);
|
||||
else
|
||||
module:log("info", "for _user: %s and _res: %s got active session?", _user, _res);
|
||||
--module:log("debug", "for _user: %s and _res: %s got detail: %s", _user, _res, dumpTable(_detail1));
|
||||
end
|
||||
end
|
||||
-- module:log("debug", "session for _res %s is: %s", _res, dumpTable(_resdetails));
|
||||
end
|
||||
end
|
||||
-- module:log("debug", "sessions: %s", dumpTable(sessions[ubjid]));
|
||||
return nType, tokens, nLang;
|
||||
end
|
||||
end
|
||||
|
||||
local function fcm_notify(userName, title, body, type, _senderName, _groupTopic, vnc_attachment_type, msgid, vncTalkConferenceEtype, vncTalkConferenceId, _nFrom)
|
||||
if (not moduleIsActive) then module:log("info", "module not active - bailung out"); return end;
|
||||
module:log("info", "getting notify opts for %s", userName);
|
||||
local uname, uhost = jid_split(userName);
|
||||
if (uhost ~= storage_host) then return end;
|
||||
local nType, tokens, lang = getNotifyOptionsForUser(uname);
|
||||
if (tokens and (#tokens) > 0) and ((nType == 1) or (nType == 2))
|
||||
then
|
||||
-- module:log(
|
||||
-- "info", "in fcm_notify(%s, %s, %s) => type=%s, %s tokens",
|
||||
-- userName, title, body, tostring(nType), tostring((#tokens))
|
||||
--);
|
||||
local sName = _senderName;
|
||||
local gTopic = _groupTopic;
|
||||
sName = "Neue Nachricht";
|
||||
gTopic = "Neue Nachricht";
|
||||
|
||||
if (lang == "en") then
|
||||
sName = "new message";
|
||||
gTopic = "new message";
|
||||
end;
|
||||
|
||||
if (lang == "fr") then
|
||||
sName = "Nouveau message";
|
||||
gTopic = "Nouveau message";
|
||||
end;
|
||||
|
||||
body = "";
|
||||
|
||||
for i,token in pairs(tokens) do
|
||||
if (token)
|
||||
then
|
||||
local rtoken, ros = jid_split(token);
|
||||
-- module:log("debug","got rtoken: %s - os: %s ", rtoken, ros);
|
||||
if (ros == "ios") then
|
||||
-- module:log("debug", "postFCMIOS with (%s, %s, %s, %s, %s, %s, %s, %s, %s)", userName, rtoken, title, body, type, _senderName, _groupTopic, vnc_attachment_type, lang);
|
||||
postFCMIOS(userName, rtoken, title, body, type, sName, gTopic, vnc_attachment_type, lang, msgid, vncTalkConferenceEtype, vncTalkConferenceId, _nFrom);
|
||||
else
|
||||
-- module:log("info", "postFCM with (%s, %s, %s, %s, %s, %s, %s, %s, %s)", userName, rtoken, title, body, type, _senderName, _groupTopic, vnc_attachment_type, lang, _nFrom);
|
||||
postFCM(userName, rtoken, title, body, type, sName, gTopic, vnc_attachment_type, lang, msgid, vncTalkConferenceEtype, vncTalkConferenceId, _nFrom);
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
module:log("debug", "fcm_notify(%s, %s, %s) => type=%s, no tokens", userName, title, body, tostring(nType));
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function handle_muc_message(event)
|
||||
-- event.room and event.stanza are available
|
||||
local room = event.room
|
||||
local stanza = event.stanza
|
||||
-- module:log("info", "handling stanza %s", stanza);
|
||||
-- module:log("info", "room: %s", dumpTable(room));
|
||||
|
||||
local message_id = event.stanza.attr.id;
|
||||
-- module:log("info","message id: %s", event.stanza.attr.id);
|
||||
local type = stanza.attr.type or "normal";
|
||||
local from = jid_bare(stanza.attr.from);
|
||||
local to = jid_bare(stanza.attr.to) or from;
|
||||
|
||||
local vncTalkConferenceEtype = stanza:find("{xmpp:vnctalk}vncTalkConference/eventType#") or nil;
|
||||
|
||||
-- module:log("info", "handling message from=%s, to=%s", stanza.attr.from, to);
|
||||
|
||||
|
||||
local content = trim(stanza:find("body#"));
|
||||
local delayedDelivery = stanza:get_child("delay", "urn:xmpp:delay");
|
||||
|
||||
-- if we have a vncTalk incoming or whiteboard element, it overrides the type
|
||||
local vncTalkIncomingType = stanza:find("{xmpp:vnctalk}vncTalkConference/conferenceType#");
|
||||
local vncTalkConferenceId = stanza:find("{xmpp:vnctalk}vncTalkConference/conferenceId#") or nil;
|
||||
local jitsiURL = stanza:find("{xmpp:vnctalk}vncTalkConference/jitsiURL#") or nil;
|
||||
local jitsiRoom = stanza:find("{xmpp:vnctalk}vncTalkConference/jitsiRoom#") or nil;
|
||||
local vncTalkWhiteboard = stanza:find("{xmpp:vnctalk}whiteboard");
|
||||
local isSentCarbonMessage = stanza:get_child("sent", "urn:xmpp:carbons:2");
|
||||
local vnc_attachment_type = stanza:find("{xmpp:vnctalk}attachment/fileType#");
|
||||
|
||||
local vnctalk_broadcast = stanza:get_child("vncTalkBroadcast", "xmpp:vnctalk");
|
||||
local vnctalk_broadcast_childid = nil;
|
||||
if vnctalk_broadcast then
|
||||
if starts_with(to, "broadcast") then
|
||||
-- module:log("message is to broadcast - bailing out");
|
||||
return nil;
|
||||
end
|
||||
vnctalk_broadcast_childid = vnctalk_broadcast.attr.id;
|
||||
local vnctalk_broadcast_title = vnctalk_broadcast.attr.title;
|
||||
local vnctalk_broadcast_target = vnctalk_broadcast.attr.origtarget;
|
||||
local body = stanza:get_child("body");
|
||||
-- module:log("debug", "broadcast body: %s", content);
|
||||
-- module:log("debug", "jid_split(to): %s", jid_split(to));
|
||||
-- fcm_notify(jid_split(to), vnctalk_broadcast_target, content, type, getDisplayName(jid_split(from)), "Broadcast: "..vnctalk_broadcast_title, vnc_attachment_type, message_id, vncTalkConferenceEtype, vncTalkConferenceId);
|
||||
return nil;
|
||||
end
|
||||
|
||||
local auxType = vncTalkIncomingType or (vncTalkWhiteboard and "whiteboard");
|
||||
|
||||
if (auxType)
|
||||
then
|
||||
content = auxType;
|
||||
type = auxType;
|
||||
end;
|
||||
|
||||
local doNotify = content and (content ~= " ") and (content ~= "") and (delayedDelivery == nil) and (isSentCarbonMessage == nil) and (
|
||||
(type == "chat") or (type == "groupchat") or (type == "audio") or (type == "video") or (type == "whiteboard") or (type == "screen")
|
||||
);
|
||||
|
||||
if (doNotify) then
|
||||
local sender = "";
|
||||
for _, occupant in pairs(room._occupants) do
|
||||
if (stanza.attr.from == occupant.nick) then sender=occupant.bare_jid; end;
|
||||
end
|
||||
-- module:log("info","sender is %s", sender);
|
||||
local roomTopic = room._data.subject or nil;
|
||||
for jid, aff in pairs(room._affiliations) do
|
||||
if aff ~= "outcast" then
|
||||
-- module:log("info", "found jid: %s as aff: %s", jid, aff);
|
||||
local roomJid = to;
|
||||
if (sender ~= jid) then
|
||||
module:log("info", "from is: %s", from);
|
||||
fcm_notify(jid, roomJid, content, type, getDisplayName(jid_split(sender)), roomTopic, vnc_attachment_type, message_id, vncTalkConferenceEtype, vncTalkConferenceId, from, jitsiURL, jitsiRoom);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module:hook("muc-broadcast-message", handle_muc_message)
|
||||
|
||||
module:hook("host-activated", function(host)
|
||||
module:log("info", "got activated event for host %s", host);
|
||||
end);
|
||||
|
||||
module:log("debug", "Module loaded")
|
||||
Reference in New Issue
Block a user