Software /
code /
verse
File
plugins/roster.lua @ 445:b119dc4d8bc2
plugins.smacks: Don't warn about zero stanzas acked
It's only if the count somehow goes backwards that something is really
wrong. An ack for zero stanzas is fine and we don't need to do anything.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 10 Jun 2021 11:58:23 +0200 |
parent | 395:e86144a4eaa1 |
child | 490:6b2f31da9610 |
line wrap: on
line source
local verse = require "verse"; local bare_jid = require "util.jid".bare; local xmlns_roster = "jabber:iq:roster"; local xmlns_rosterver = "urn:xmpp:features:rosterver"; local t_insert = table.insert; function verse.plugins.roster(stream) local ver_supported = false; local roster = { items = {}; ver = ""; -- TODO: -- groups = {}; }; stream.roster = roster; stream:hook("stream-features", function(features_stanza) if features_stanza:get_child("ver", xmlns_rosterver) then ver_supported = true; end end); local function item_lua2xml(item_table) local xml_item = verse.stanza("item", { xmlns = xmlns_roster }); for k, v in pairs(item_table) do if k ~= "groups" then xml_item.attr[k] = v; else for i = 1,#v do xml_item:tag("group"):text(v[i]):up(); end end end return xml_item; end local function item_xml2lua(xml_item) local item_table = { }; local groups = {}; item_table.groups = groups; for k, v in pairs(xml_item.attr) do if k ~= "xmlns" then item_table[k] = v end end for group in xml_item:childtags("group") do t_insert(groups, group:get_text()) end return item_table; end function roster:load(r) roster.ver, roster.items = r.ver, r.items; end function roster:dump() return { ver = roster.ver, items = roster.items, }; end -- should this be add_contact(item, callback) instead? function roster:add_contact(jid, name, groups, callback) local item = { jid = jid, name = name, groups = groups }; local stanza = verse.iq({ type = "set" }) :tag("query", { xmlns = xmlns_roster }) :add_child(item_lua2xml(item)); stream:send_iq(stanza, function (reply) if not callback then return end if reply.attr.type == "result" then callback(true); else callback(nil, reply); end end); end -- What about subscriptions? function roster:delete_contact(jid, callback) jid = (type(jid) == "table" and jid.jid) or jid; local item = { jid = jid, subscription = "remove" } if not roster.items[jid] then return false, "item-not-found"; end stream:send_iq(verse.iq({ type = "set" }) :tag("query", { xmlns = xmlns_roster }) :add_child(item_lua2xml(item)), function (reply) if not callback then return end if reply.attr.type == "result" then callback(true); else callback(nil, reply); end end); end local function add_item(item) -- Takes one roster <item/> local roster_item = item_xml2lua(item); roster.items[roster_item.jid] = roster_item; end -- Private low level local function delete_item(jid) local deleted_item = roster.items[jid]; roster.items[jid] = nil; return deleted_item; end function roster:fetch(callback) stream:send_iq(verse.iq({type="get"}):tag("query", { xmlns = xmlns_roster, ver = ver_supported and roster.ver or nil }), function (result) if result.attr.type == "result" then local query = result:get_child("query", xmlns_roster); if query then roster.items = {}; for item in query:childtags("item") do add_item(item) end roster.ver = query.attr.ver or ""; end callback(roster); else callback(nil, result); end end); end stream:hook("iq/"..xmlns_roster, function(stanza) local type, from = stanza.attr.type, stanza.attr.from; if type == "set" and (not from or from == bare_jid(stream.jid)) then local query = stanza:get_child("query", xmlns_roster); local item = query and query:get_child("item"); if item then local event, target; local jid = item.attr.jid; if item.attr.subscription == "remove" then event = "removed" target = delete_item(jid); else event = roster.items[jid] and "changed" or "added"; add_item(item) target = roster.items[jid]; end roster.ver = query.attr.ver; if target then stream:event("roster/item-"..event, target); end -- TODO else return error? Events? end stream:send(verse.reply(stanza)) return true; end end); end