using Gee; using Xmpp; using Dino.Entities; namespace Dino { public class PresenceManager : StreamInteractionModule, Object { public static ModuleIdentity IDENTITY = new ModuleIdentity("presence_manager"); public string id { get { return IDENTITY.id; } } public signal void show_received(Show show, Jid jid, Account account); public signal void received_subscription_request(Jid jid, Account account); private StreamInteractor stream_interactor; private HashMap>> shows = new HashMap>>(Jid.hash_bare_func, Jid.equals_bare_func); private HashMap> resources = new HashMap>(Jid.hash_bare_func, Jid.equals_bare_func); private Gee.List subscription_requests = new ArrayList(Jid.equals_func); public static void start(StreamInteractor stream_interactor) { PresenceManager m = new PresenceManager(stream_interactor); stream_interactor.add_module(m); } private PresenceManager(StreamInteractor stream_interactor) { this.stream_interactor = stream_interactor; stream_interactor.account_added.connect(on_account_added); } public Show get_last_show(Jid jid, Account account) { Core.XmppStream? stream = stream_interactor.get_stream(account); if (stream != null) { Xmpp.Presence.Stanza? presence = stream.get_flag(Presence.Flag.IDENTITY).get_presence(jid.to_string()); if (presence != null) { return new Show(jid, presence.show, new DateTime.now_utc()); } } return new Show(jid, Show.OFFLINE, new DateTime.now_utc()); } public HashMap>? get_shows(Jid jid, Account account) { return shows[jid]; } public ArrayList? get_full_jids(Jid jid, Account account) { Core.XmppStream? stream = stream_interactor.get_stream(account); if (stream != null) { Xmpp.Presence.Flag flag = stream.get_flag(Presence.Flag.IDENTITY); if (flag == null) return null; Gee.List resources = flag.get_resources(jid.bare_jid.to_string()); if (resources == null) { return null; } ArrayList ret = new ArrayList(Jid.equals_func); resources.foreach((resource) => { ret.add(new Jid(resource)); return true; }); return ret; } return null; } public bool exists_subscription_request(Account account, Jid jid) { return subscription_requests.contains(jid); } public void request_subscription(Account account, Jid jid) { Core.XmppStream stream = stream_interactor.get_stream(account); if (stream != null) stream.get_module(Xmpp.Presence.Module.IDENTITY).request_subscription(stream, jid.bare_jid.to_string()); } public void approve_subscription(Account account, Jid jid) { Core.XmppStream stream = stream_interactor.get_stream(account); if (stream != null) { stream.get_module(Xmpp.Presence.Module.IDENTITY).approve_subscription(stream, jid.bare_jid.to_string()); subscription_requests.remove(jid); } } public void deny_subscription(Account account, Jid jid) { Core.XmppStream stream = stream_interactor.get_stream(account); if (stream != null) { stream.get_module(Xmpp.Presence.Module.IDENTITY).deny_subscription(stream, jid.bare_jid.to_string()); subscription_requests.remove(jid); } } public void cancel_subscription(Account account, Jid jid) { Core.XmppStream stream = stream_interactor.get_stream(account); if (stream != null) stream.get_module(Xmpp.Presence.Module.IDENTITY).cancel_subscription(stream, jid.bare_jid.to_string()); } private void on_account_added(Account account) { stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_available_show.connect((stream, jid, show) => on_received_available_show(account, new Jid(jid), show) ); stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_unavailable.connect((stream, presence) => on_received_unavailable(account, new Jid(presence.from)) ); stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_subscription_request.connect((stream, jid_str) => { Jid jid = new Jid(jid_str); if (!subscription_requests.contains(jid)) { subscription_requests.add(jid); } received_subscription_request(jid, account); }); } private void on_received_available_show(Account account, Jid jid, string show) { lock (resources) { if (!resources.has_key(jid)){ resources[jid] = new ArrayList(Jid.equals_func); } if (!resources[jid].contains(jid)) { resources[jid].add(jid); } } add_show(account, jid, show); } private void on_received_unavailable(Account account, Jid jid) { lock (resources) { if (resources.has_key(jid)) { resources[jid].remove(jid); if (resources[jid].size == 0 || jid.is_bare()) { resources.unset(jid); } } } add_show(account, jid, Show.OFFLINE); } private void add_show(Account account, Jid jid, string s) { Show show = new Show(jid, s, new DateTime.now_utc()); lock (shows) { if (!shows.has_key(jid)) { shows[jid] = new HashMap>(); } if (!shows[jid].has_key(jid)) { shows[jid][jid] = new ArrayList(); } shows[jid][jid].add(show); } show_received(show, jid, account); } } public class Show : Object { public const string ONLINE = Xmpp.Presence.Stanza.SHOW_ONLINE; public const string AWAY = Xmpp.Presence.Stanza.SHOW_AWAY; public const string CHAT = Xmpp.Presence.Stanza.SHOW_CHAT; public const string DND = Xmpp.Presence.Stanza.SHOW_DND; public const string XA = Xmpp.Presence.Stanza.SHOW_XA; public const string OFFLINE = "offline"; public Jid jid; public string as; public DateTime datetime; public Show(Jid jid, string show, DateTime datetime) { this.jid = jid; this.as = show; this.datetime = datetime; } } }