Sat, 14 Nov 2020 15:30:35 +0100
clix.raw: Add a shorthand for top level stanza attributes
The m, p and iq functions are amended so that indexing them sets the
'type' attribute and a subsequent function call with a string sets the
'to' attribute.
Examples:
m.chat"recipient":body"Hello"
iq.get"example.com":query"jabber:iq:version"
short_opts.i = "interactive"; local split_jid = require "util.jid".split; local function printor(str) return function(ok, err) if ok then print(str) else print(err:get_error()); end end end return function (opts, arg) if opts.short_help then print("Show or edit your roster"); return; end if opts.help and not opts.interactive then return 0; end local function on_connect(conn) -- Fake socket object around stdin local stdin = { getfd = function () return 0; end; dirty = function (self) return false; end; settimeout = function () end; send = function (_, d) return #d, 0; end; close = function () end; receive = function (_, patt) local data = io.stdin:read(patt); if data == nil then conn:close(); end if opts.echo then io.write(data, patt == "*l" and "\n" or ""); end return data; end }; local commands = { quit = function(param) conn:close(); end; add = function(param) conn.roster:add_contact(param) end; sub = function(param) conn:send(verse.presence{to=param, type="subscribe"}); end; unsub = function(param) conn:send(verse.presence{to=param, type="unsubscribe"}); end; auth = function(param) conn:send(verse.presence{to=param, type="subscribed"}); end; unauth = function(param) conn:send(verse.presence{to=param, type="unsubscribed"}); end; del = function(param) conn.roster:delete_contact(param) end; setnick = function(param) local jid, nick = param:match("^(%S+)%s+(.+)"); local item = conn.roster.items[jid]; if not item then print("no jid "..jid); return; end conn.roster:add_contact(jid, nick, item.groups or {}, printor("saved")); end; addgroup = function(param) local jid, group = param:match("^(%S+)%s+(.+)"); local item = conn.roster.items[jid]; local groups = item.groups or {}; table.insert(groups, group); conn.roster:add_contact(jid, item.name, groups, printor("saved")); end; delgroup = function(param) local jid, group = param:match("^(%S+)%s+(.+)"); local item = conn.roster.items[jid]; local groups = item.groups; if not groups then return end; for i = 1,#groups do if groups[i] == group then table.remove(groups, i); break end end conn.roster:add_contact(jid, item.name, groups, printor("saved")); end; list = function(param) if param == "" then param = nil end for jid, item in pairs(conn.roster.items) do local name, host = item.name or split_jid(jid); local groups = table.concat(item.groups or {}, ", "); if not param or ( (name and name:find(param, 1, true)) or jid:find(param, 1, true) ) then print(jid, name or host, groups); end end end; listgroups = function(param) local groups = {}; for jid, item in pairs(conn.roster.items) do for i = 1,#item.groups do groups[item.groups[i]] = ( groups[item.groups[i]] or 0 ) + 1; end end for group, size in pairs(groups) do print(group, size) end end; show = function(param) local item = conn.roster.items[param]; if not item then print("No such contact"); return; end for k,v in pairs(item) do print(k,type(v) == "table" and table.concat(v, ", ") or v) end end; export = function() local stored_roster = { [false] = { version = conn.roster.ver } } for jid, item in pairs(conn.roster.items) do stored_roster[jid] = { name = item.name; subscription = item.subscription; groups = { unpack(item.groups) }; } end print("return "..require"util.serialization".serialize(stored_roster)); end } function commands.help () print("Roster commands"); for cmd in pairs(commands) do print(" * " .. cmd); end print("Most commands takes a JID as argument."); end local function on_incoming(stdin, text) local cmd = text:match("^(%a*)"); local param = text:match("%s+(.*)", #cmd); if commands[cmd] then commands[cmd](param); end end stdin = require "net.server".wrapclient(stdin, "stdin", 0, { onincoming = on_incoming, ondisconnect = function () end }, "*l"); conn:add_plugin("roster"); conn.roster:fetch(function(roster) if not roster then print("There was an error fetching your roster"); conn:close() end if not opts.interactive then local firstcmd = commands[arg[1] or "list"]; if firstcmd then firstcmd(table.concat(arg, " ", 2, #arg)) end conn:close(); end end); local function notif(e) return function(item) return print(("%s %s"):format((item.name and item.name .. " (" .. item.jid .. ")") or item.jid, e)); end end if opts.interactive then conn:hook("roster/item-added", notif("added")); conn:hook("roster/item-changed", notif("changed")); conn:hook("roster/item-removed", notif("removed")); end if opts.presence then conn:hook("presence", function(presence) if presence.attr.type == "subscribe" then print(("%s wants to subscribe to you"):format(presence.attr.from)); --elseif presence.attr.type == "subscribed" then --print(("%s subscribed to you?"):format(presence.attr.from)); end end) end end clix_connect(opts, on_connect); end