diff options
Diffstat (limited to 'src/core/ephraim_roster.erl')
-rw-r--r-- | src/core/ephraim_roster.erl | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/core/ephraim_roster.erl b/src/core/ephraim_roster.erl new file mode 100644 index 0000000..4f8dfef --- /dev/null +++ b/src/core/ephraim_roster.erl @@ -0,0 +1,109 @@ +-module(ephraim_roster). +-compile([debug_info, export_all]). +-include_lib("exmpp/include/exmpp.hrl"). + +-record(roster, { + entries :: dict() + }). + +-record(roster_entry, { + name :: binary() | undefined, + subscription :: atom() | undefined, + resources :: dict() + }). + +-record(resource_entry, { + priority :: integer(), + show :: atom(), + status :: string() + }). + + +-spec init() -> ok. +init() -> + loop(#roster{entries=dict:new()}). + +-spec updateResource(#roster{}, binary(), integer(), atom(), atom(), string()) -> #roster{}. +updateResource(Roster, JID, Priority, Type, Show, Status) -> + {Node, Domain, Resource} = exmpp_jid:to_lower(exmpp_jid:parse(JID)), + BareJID = list_to_binary([Node, <<"@">>, Domain]), + + RosterEntry = case dict:find(BareJID, Roster#roster.entries) of + {ok, Entry} -> + Entry; + error -> + #roster_entry{resources=dict:new()} + end, + + Resources = case Type of + available -> + ResourceEntry = #resource_entry{priority=Priority,show=Show,status=Status}, + dict:store(Resource, ResourceEntry, RosterEntry#roster_entry.resources); + _ -> + RosterEntry#roster_entry.resources + end, + Entries = dict:store(BareJID, RosterEntry#roster_entry{resources=Resources}, Roster#roster.entries), + if RosterEntry#roster_entry.subscription =:= undefined -> + ok; + true -> + ephraim ! {ui_update, {roster_update, JID, dict:to_list(Resources)}} + end, + Roster#roster{entries=Entries}. + +-spec updateRosterEntry(#roster{}, binary(), binary(), atom()) -> #roster{}. +updateRosterEntry(Roster, JID, Name, Subscription) -> + Resources = case dict:find(JID, Roster#roster.entries) of + {ok, Entry} -> + Entry#roster_entry.resources; + error -> + dict:new() + end, + NewEntry = #roster_entry{subscription=Subscription,name=Name,resources=Resources}, + Entries = dict:store(JID, NewEntry, Roster#roster.entries), + ephraim ! {ui_update, {roster_update, JID, dict:to_list(Resources)}}, + Roster#roster{entries=Entries}. + +-spec handleRosterIQ(#roster{}, #xmlel{}) -> #roster{}. +handleRosterIQ(Roster, Item) -> + JID = exmpp_xml:get_attribute(Item, jid, undefined), + Name = exmpp_xml:get_attribute(Item, name, undefined), + Subscription = binary_to_atom(exmpp_xml:get_attribute(Item, subscription, undefined), utf8), + + updateRosterEntry(Roster, JID, Name, Subscription). + +-spec handleRosterIQs(#roster{}, [#xmlel{}]) -> #roster{}. +handleRosterIQs(Roster, []) -> + Roster; + +handleRosterIQs(Roster, [Item = #xmlel{name=item}|Rest]) -> + Roster2 = handleRosterIQ(Roster, Item), + handleRosterIQs(Roster2, Rest); + +handleRosterIQs(Roster, [_|Rest]) -> + handleRosterIQs(Roster, Rest). + +-spec loop(#roster{}) -> ok. +loop(Roster) -> + receive + stop -> + ok; + + {presence, Packet} -> + From = exmpp_xml:get_attribute(Packet, from, <<"unknown">>), + + Priority = exmpp_presence:get_priority(Packet), + Type = exmpp_presence:get_type(Packet), + Show = exmpp_presence:get_show(Packet), + Status = exmpp_presence:get_status(Packet), + + Roster2 = updateResource(Roster, From, Priority, Type, Show, Status), + loop(Roster2); + + {roster_iq, Payload} -> + Roster2 = handleRosterIQs(Roster, Payload#xmlel.children), + loop(Roster2); + + Msg -> + io:format("ephraim_roster: ~p~n", [Msg]), + loop(Roster) + end. |