3 -- |
3 -- |
4 -- This file is MIT/X11 licensed. |
4 -- This file is MIT/X11 licensed. |
5 |
5 |
6 local st = require "util.stanza"; |
6 local st = require "util.stanza"; |
7 local jid_bare = require "util.jid".bare; |
7 local jid_bare = require "util.jid".bare; |
8 local jid_split = require "util.jid".split; |
|
9 local xmlns_carbons = "urn:xmpp:carbons:1"; |
8 local xmlns_carbons = "urn:xmpp:carbons:1"; |
10 local xmlns_forward = "urn:xmpp:forward:0"; |
9 local xmlns_forward = "urn:xmpp:forward:0"; |
11 local host_sessions = hosts[module.host].sessions; |
10 local host_sessions = hosts[module.host].sessions; |
|
11 local full_sessions, bare_sessions = full_sessions, bare_sessions; |
12 |
12 |
13 local function toggle_carbons(event) |
13 local function toggle_carbons(event) |
14 local origin, stanza = event.origin, event.stanza; |
14 local origin, stanza = event.origin, event.stanza; |
15 if stanza.attr.type == "set" then |
15 if stanza.attr.type == "set" then |
16 local state = stanza.tags[1].name; |
16 local state = stanza.tags[1].name; |
25 |
25 |
26 local function message_handler(event, c2s) |
26 local function message_handler(event, c2s) |
27 local origin, stanza = event.origin, event.stanza; |
27 local origin, stanza = event.origin, event.stanza; |
28 local orig_type = stanza.attr.type; |
28 local orig_type = stanza.attr.type; |
29 local orig_to = stanza.attr.to; |
29 local orig_to = stanza.attr.to; |
30 local orig_from = stanza.attr.from; |
|
31 |
30 |
32 if not (orig_type == nil |
31 if not (orig_type == nil |
33 or orig_type == "normal" |
32 or orig_type == "normal" |
34 or orig_type == "chat") then |
33 or orig_type == "chat") then |
35 return -- No carbons for messages of type error or headline |
34 return -- No carbons for messages of type error or headline |
36 end |
35 end |
37 |
36 |
38 local bare_jid, user_sessions; |
37 -- Stanza sent by a local client |
39 local no_carbon_to = {}; |
38 local bare_jid = origin.username .. "@" .. origin.host; |
40 module:log("debug", "Message from %s to %s", tostring(orig_from), tostring(orig_to)); |
39 local target_session = origin; |
41 if c2s then -- Stanza sent by a local client |
40 local top_priority = false; |
42 bare_jid = (origin.username.."@"..origin.host) |
41 local user_sessions = host_sessions[origin.username]; |
43 user_sessions = host_sessions[origin.username]; |
42 |
44 else -- Stanza about to be delivered to a local client |
43 -- Stanza about to be delivered to a local client |
45 local username, hostname, resource = jid_split(orig_to); |
44 if not c2s then |
46 bare_jid = jid_bare(orig_to); |
45 bare_jid = jid_bare(orig_to); |
47 user_sessions = host_sessions[username]; |
46 target_session = full_sessions[orig_to] |
48 if resource then |
47 user_sessions = bare_sessions[bare_jid]; |
49 module:log("debug", "Message was to resource %s, it will not get carbon", resource); |
48 if not target_session and user_sessions then |
50 no_carbon_to[resource] = true; |
49 -- The top resources will already receive this message per normal routing rules, |
51 elseif user_sessions then |
50 -- so we are going to skip them in order to avoid sending duplicated messages. |
52 local top_resources = user_sessions.top_resources; |
51 local top_resources = user_sessions.top_resources; |
53 if top_resources then |
52 top_priority = top_resources and top_resources[1].priority |
54 -- These will already receive this message per normal routing rules, |
|
55 -- so we skip them to avoid duplicated messages. |
|
56 for i=1,#top_resources do |
|
57 local resource = top_resources[i].resource; |
|
58 module:log("debug", "Not sending carbons to top resource %s", resource); |
|
59 no_carbon_to[resource] = true; |
|
60 end |
|
61 end |
|
62 end |
53 end |
63 end |
54 end |
64 |
55 |
65 if not user_sessions then |
56 if not user_sessions then |
66 module:log("debug", "Skip carbons for offline user"); |
57 module:log("debug", "Skip carbons for offline user"); |
82 local carbon = st.message{ from = bare_jid, type = orig_type, } |
73 local carbon = st.message{ from = bare_jid, type = orig_type, } |
83 :tag(c2s and "sent" or "received", { xmlns = xmlns_carbons }):up() |
74 :tag(c2s and "sent" or "received", { xmlns = xmlns_carbons }):up() |
84 :tag("forwarded", { xmlns = xmlns_forward }) |
75 :tag("forwarded", { xmlns = xmlns_forward }) |
85 :add_child(copy):reset(); |
76 :add_child(copy):reset(); |
86 |
77 |
87 -- And finally, send the carbon to the sessions that should have it. |
|
88 user_sessions = user_sessions and user_sessions.sessions; |
78 user_sessions = user_sessions and user_sessions.sessions; |
89 for resource, session in pairs(user_sessions) do |
79 for _, session in pairs(user_sessions) do |
90 local full_jid = bare_jid .. "/" .. resource; |
80 -- Carbons are sent to resources that have enabled it |
91 if session.want_carbons and ((c2s and session ~= origin) or (not c2s and not no_carbon_to[resource])) then |
81 if session.want_carbons |
92 carbon.attr.to = full_jid; |
82 -- but not the resource that sent the message, or the one that it's directed to |
93 module:log("debug", "Sending carbon to %s", full_jid); |
83 and session ~= target_session |
|
84 -- and isn't among the top resources that would receive the message per standard routing rules |
|
85 and (not c2s or session.priority ~= top_priority) then |
|
86 carbon.attr.to = session.full_jid; |
|
87 module:log("debug", "Sending carbon to %s", session.full_jid); |
94 session.send(carbon); |
88 session.send(carbon); |
95 end |
89 end |
96 end |
90 end |
97 end |
91 end |
98 |
92 |