1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
-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,
groups :: set(),
resources :: dict()
}).
-record(resource_entry, {
priority :: integer(),
show :: atom(),
status :: binary()
}).
-spec init() -> ok.
init() ->
loop(#roster{entries=dict:new()}).
-spec updateResource(#roster{}, binary(), integer(), atom(), atom(), binary()) -> #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, BareJID, 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,
Groups = sets:new(),
NewEntry = #roster_entry{subscription=Subscription,name=Name,resources=Resources,groups=Groups},
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),
io:format("ephraim_roster: IQ: ~p~n", [Payload]),
loop(Roster2);
Msg ->
io:format("ephraim_roster: ~p~n", [Msg]),
loop(Roster)
end.
|