clix/roster.lua

Sun, 15 Nov 2020 20:45:50 +0100

author
Kim Alvefur <zash@zash.se>
date
Sun, 15 Nov 2020 20:45:50 +0100
changeset 140
8815232cbbeb
parent 123
c61fadb9d4fa
child 164
fafdcde2e2eb
permissions
-rw-r--r--

clix.watch_pep: Take PEP node as positional argument

Thanks MattJ

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

mercurial