From d5adf274c137bef22d5695d4a280e10068edcb0e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 23 Jun 2010 20:37:31 +0200 Subject: Show avatars in roster --- src/core/CMakeLists.txt | 1 + src/core/ephraim.erl | 38 +++++++++++++++++++++++---------- src/core/ephraim_conn.erl | 7 +++++- src/core/ephraim_conv.erl | 4 ++-- src/core/ephraim_event.erl | 42 ++++++++++++++++++++++++++++++++++++ src/core/ephraim_roster.erl | 52 ++++++++++++++++++++++++++++++++++++--------- 6 files changed, 120 insertions(+), 24 deletions(-) create mode 100644 src/core/ephraim_event.erl (limited to 'src/core') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 792f279..c49763c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -2,6 +2,7 @@ erl_target(ephraim-core ephraim.erl ephraim_conn.erl ephraim_conv.erl + ephraim_event.erl ephraim_roster.erl ephraim_util.erl OPTIONS diff --git a/src/core/ephraim.erl b/src/core/ephraim.erl index 523749c..bd36118 100644 --- a/src/core/ephraim.erl +++ b/src/core/ephraim.erl @@ -4,6 +4,7 @@ -record(state, { conn :: pid(), roster :: pid(), + event :: pid(), convs :: dict(), uis :: set() }). @@ -25,29 +26,35 @@ init() -> Conn = spawn(ephraim_conn, init, []), Roster = spawn(ephraim_roster, init, []), - loop(#state{conn=Conn,roster=Roster,convs=dict:new(),uis=sets:new()}), + Event = spawn(ephraim_event, init, []), + loop(#state{conn=Conn,roster=Roster,event=Event,convs=dict:new(),uis=sets:new()}), init:stop(). --spec get_conv(#state{},exmpp_jid:jid()) -> {#state{},pid()}. +-spec get_conv(#state{},exmpp_jid:jid()) -> {#state{},pid()|undefined}. get_conv(State, JID) -> Key = exmpp_jid:to_lower(JID), - case dict:find(Key, State#state.convs) of - {ok, Conv} -> - {State, Conv}; - error -> - Conv = spawn(ephraim_conv, init, [Key]), - Dict = dict:store(Key, Conv, State#state.convs), - {State#state{convs=Dict}, Conv} + case Key of + {_,_,undefined} -> + {State, undefined}; + _ -> + case dict:find(Key, State#state.convs) of + {ok, Conv} -> + {State, Conv}; + error -> + Conv = spawn(ephraim_conv, init, [Key]), + Dict = dict:store(Key, Conv, State#state.convs), + {State#state{convs=Dict}, Conv} + end end. -spec loop(#state{}) -> ok. loop(State) -> receive stop -> - %dict:fold(fun(_,Conv,Msg) -> Conv ! Msg end, stop, State#state.convs), ephraim_util:send_all_values(State#state.convs, stop), State#state.conn ! stop, State#state.roster ! stop, + State#state.event ! stop, ok; {register_ui, Pid} -> @@ -78,9 +85,18 @@ loop(State) -> {receive_message, From, Packet} -> {State2, Conv} = get_conv(State, From), - Conv ! {receive_message, Packet}, + case Conv of + undefined -> + io:format("~p~n", [Packet]); + _ -> + Conv ! {receive_message, Packet} + end, loop(State2); + {receive_event, From, Packet} -> + State#state.event ! {receive_event, From, Packet}, + loop(State); + {receive_iq, IQ} -> case IQ of {iq, response, result, _, 'jabber:iq:roster', Payload, _, _, 'jabber:client'} -> diff --git a/src/core/ephraim_conn.erl b/src/core/ephraim_conn.erl index c4b163e..28e72b3 100644 --- a/src/core/ephraim_conn.erl +++ b/src/core/ephraim_conn.erl @@ -40,7 +40,12 @@ loop(State) -> #received_packet{packet_type=message, raw_packet=Packet} -> From = exmpp_xml:get_attribute(Packet, from, <<"unknown">>), - ephraim ! {receive_message, From, Packet}, + HasElement = exmpp_xml:has_element(Packet,'http://jabber.org/protocol/pubsub#event',event), + if HasElement -> + ephraim ! {receive_event, From, Packet}; + true -> + ephraim ! {receive_message, From, Packet} + end, loop(State); #received_packet{packet_type=iq, raw_packet=Packet} -> diff --git a/src/core/ephraim_conv.erl b/src/core/ephraim_conv.erl index 8f53098..b502166 100644 --- a/src/core/ephraim_conv.erl +++ b/src/core/ephraim_conv.erl @@ -17,8 +17,8 @@ loop(State) -> stop -> ok; - {receive_message, _Packet} -> - %io:format("Received packet from ~p: ~p~n", [State#conv_state.jid, Packet]), + {receive_message, Packet} -> + io:format("Received packet from ~p:~n~p~n", [State#conv_state.jid, Packet]), loop(State); Msg -> diff --git a/src/core/ephraim_event.erl b/src/core/ephraim_event.erl new file mode 100644 index 0000000..dd86a7b --- /dev/null +++ b/src/core/ephraim_event.erl @@ -0,0 +1,42 @@ +-module(ephraim_event). +-compile([debug_info, export_all]). +-include_lib("exmpp/include/exmpp.hrl"). + +-spec init() -> ok. +init() -> + loop(). + +-spec handleEvent(binary(), #xmlel{}) -> ok. +handleEvent(From, Item) -> + HasAvatarData = exmpp_xml:has_element(Item, 'urn:xmpp:avatar:data', data), + if HasAvatarData -> + Element = exmpp_xml:get_element(Item, 'urn:xmpp:avatar:data', data), + Data = base64:decode(exmpp_xml:get_cdata_from_list(Element#xmlel.children)), + ephraim ! {roster, {avatar, From, Data}}; + true -> + io:format("Received unhandled event from ~p:~n~p~n", [From, Item]) + end. + +-spec handleEvents(binary(), [#xmlel{}]) -> ok. +handleEvents(_, []) -> + ok; +handleEvents(From, [Item|Rest]) -> + handleEvent(From, Item), + handleEvents(From, Rest). + +-spec loop() -> ok. +loop() -> + receive + stop -> + ok; + + {receive_event, From, Packet} -> + Event = exmpp_xml:get_element(Packet, 'http://jabber.org/protocol/pubsub#event', event), + Items = exmpp_xml:get_element(Event, 'http://jabber.org/protocol/pubsub#event', items), + handleEvents(From, Items#xmlel.children), + loop(); + + Msg -> + io:format("ephraim_event: ~p~n", [Msg]), + loop() + end. diff --git a/src/core/ephraim_roster.erl b/src/core/ephraim_roster.erl index bfc40b1..2426761 100644 --- a/src/core/ephraim_roster.erl +++ b/src/core/ephraim_roster.erl @@ -6,11 +6,16 @@ entries :: dict() }). +-record(avatar, { + data :: binary() + }). + -record(roster_entry, { name :: binary() | undefined, subscription :: atom() | undefined, groups :: set(), - resources :: dict() + resources :: dict(), + avatar :: #avatar{} | undefined }). -record(resource_entry, { @@ -19,7 +24,6 @@ status :: binary() }). - -spec init() -> ok. init() -> loop(#roster{entries=dict:new()}). @@ -45,13 +49,11 @@ updateResource(Roster, JID, Priority, Type, Show, Status) -> _ -> 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, RosterEntry#roster_entry.name, RosterEntry#roster_entry.subscription, - sets:to_list(RosterEntry#roster_entry.groups), dict:to_list(Resources)}} - end, + NewEntry = RosterEntry#roster_entry{resources=Resources}, + + Entries = dict:store(BareJID, NewEntry, Roster#roster.entries), + uiUpdate(BareJID, NewEntry), + Roster#roster{entries=Entries}. -spec updateRosterEntry(#roster{}, binary(), binary(), atom(), set()) -> #roster{}. @@ -63,10 +65,36 @@ updateRosterEntry(Roster, JID, Name, Subscription, Groups) -> dict:new() end, 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, Name, Subscription, sets:to_list(Groups), dict:to_list(Resources)}}, + uiUpdate(JID, NewEntry), + Roster#roster{entries=Entries}. +-spec updateAvatar(#roster{}, binary(), binary()) -> #roster{}. +updateAvatar(Roster, JID, Avatar) -> + RosterEntry = case dict:find(JID, Roster#roster.entries) of + {ok, Entry} -> + Entry; + error -> + #roster_entry{resources=dict:new()} + end, + NewEntry = RosterEntry#roster_entry{avatar=#avatar{data=Avatar}}, + Entries = dict:store(JID, NewEntry, Roster#roster.entries), + uiUpdate(JID, NewEntry), + Roster#roster{entries=Entries}. + +-spec uiUpdate(binary(), #roster_entry{}) -> ok. +uiUpdate(JID, RosterEntry) -> + if RosterEntry#roster_entry.subscription =:= undefined -> + ok; + true -> + ephraim ! {ui_update, {roster_update, JID, RosterEntry#roster_entry.name, RosterEntry#roster_entry.subscription, + sets:to_list(RosterEntry#roster_entry.groups), dict:to_list(RosterEntry#roster_entry.resources), + RosterEntry#roster_entry.avatar}}, + ok + end. + -spec getGroups([#xmlel{}]) -> set(). getGroups(Els) -> getGroups(sets:new(), Els). @@ -116,6 +144,10 @@ loop(Roster) -> Roster2 = updateResource(Roster, From, Priority, Type, Show, Status), loop(Roster2); + {avatar, From, Avatar} -> + Roster2 = updateAvatar(Roster, From, Avatar), + loop(Roster2); + {roster_iq, Payload} -> Roster2 = handleRosterIQs(Roster, Payload#xmlel.children), %io:format("ephraim_roster: IQ: ~p~n", [Payload]), -- cgit v1.2.3