Improve MUC test cases

This commit is contained in:
Evgeniy Khramtsov 2014-07-19 17:23:13 +04:00
parent 1f4e0c8aea
commit 744018425b
5 changed files with 655 additions and 37 deletions

View File

@ -177,7 +177,6 @@ db_tests() ->
privacy,
blocking,
vcard,
muc_single,
pubsub,
test_unregister]},
{test_roster_subscribe, [parallel],
@ -185,6 +184,8 @@ db_tests() ->
roster_subscribe_slave]},
{test_offline, [sequence],
[offline_master, offline_slave]},
{test_muc, [parallel],
[muc_master, muc_slave]},
{test_roster_remove, [parallel],
[roster_remove_master,
roster_remove_slave]}].
@ -202,13 +203,14 @@ db_tests(riak) ->
privacy,
blocking,
vcard,
muc_single,
test_unregister]},
{test_roster_subscribe, [parallel],
[roster_subscribe_master,
roster_subscribe_slave]},
{test_offline, [sequence],
[offline_master, offline_slave]},
{test_muc, [parallel],
[muc_master, muc_slave]},
{test_roster_remove, [parallel],
[roster_remove_master,
roster_remove_slave]}];
@ -225,7 +227,6 @@ db_tests(_) ->
privacy,
blocking,
vcard,
muc_single,
pubsub,
test_unregister]},
{test_roster_subscribe, [parallel],
@ -233,6 +234,8 @@ db_tests(_) ->
roster_subscribe_slave]},
{test_offline, [sequence],
[offline_master, offline_slave]},
{test_muc, [parallel],
[muc_master, muc_slave]},
{test_roster_remove, [parallel],
[roster_remove_master,
roster_remove_slave]}].
@ -916,15 +919,22 @@ proxy65_slave(Config) ->
socks5_recv(Socks5, Data),
disconnect(Config).
muc_single(Config) ->
muc_master(Config) ->
MyJID = my_jid(Config),
PeerJID = ?config(slave, Config),
PeerBareJID = jlib:jid_remove_resource(PeerJID),
PeerJIDStr = jlib:jid_to_string(PeerJID),
MUC = muc_jid(Config),
Room = muc_room_jid(Config),
Nick = ?config(user, Config),
NickJID = jlib:jid_replace_resource(Room, Nick),
MyNick = ?config(master_nick, Config),
MyNickJID = jlib:jid_replace_resource(Room, MyNick),
PeerNick = ?config(slave_nick, Config),
PeerNickJID = jlib:jid_replace_resource(Room, PeerNick),
Subject = ?config(room_subject, Config),
Localhost = jlib:make_jid(<<"">>, <<"localhost">>, <<"">>),
true = is_feature_advertised(Config, ?NS_MUC, MUC),
%% Joining
send(Config, #presence{to = NickJID, sub_els = [#muc{}]}),
send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}),
%% As per XEP-0045 we MUST receive stanzas in the following order:
%% 1. In-room presence from other occupants
%% 2. In-room presence from the joining entity itself (so-called "self-presence")
@ -933,7 +943,7 @@ muc_single(Config) ->
%% 5. Live messages, presence updates, new user joins, etc.
%% As this is the newly created room, we receive only the 2nd stanza.
#presence{
from = NickJID,
from = MyNickJID,
sub_els = [#muc_user{
status_codes = Codes,
items = [#muc_item{role = moderator,
@ -941,8 +951,7 @@ muc_single(Config) ->
affiliation = owner}]}]} = recv(),
%% 110 -> Inform user that presence refers to itself
%% 201 -> Inform user that a new room has been created
true = lists:member(110, Codes),
true = lists:member(201, Codes),
[110, 201] = lists:sort(Codes),
%% Request the configuration
#iq{type = result, sub_els = [#muc_owner{config = #xdata{} = RoomCfg}]} =
send_recv(Config, #iq{type = get, sub_els = [#muc_owner{}],
@ -959,10 +968,14 @@ muc_single(Config) ->
[<<"Trying to break the server">>];
<<"muc#roomconfig_persistentroom">> ->
[<<"1">>];
<<"muc#roomconfig_changesubject">> ->
[<<"0">>];
<<"muc#roomconfig_allowinvites">> ->
[<<"1">>];
<<"members_by_default">> ->
[<<"0">>];
<<"muc#roomconfig_allowvoicerequests">> ->
[<<"1">>];
<<"public_list">> ->
[<<"1">>];
<<"muc#roomconfig_publicroom">> ->
[<<"1">>];
_ ->
[]
end,
@ -974,20 +987,230 @@ muc_single(Config) ->
end, RoomCfg#xdata.fields),
NewRoomCfg = #xdata{type = submit, fields = NewFields},
%% BUG: We should not receive any sub_els!
%% TODO: fix this crap in ejabberd.
#iq{type = result, sub_els = [_|_]} =
send_recv(Config, #iq{type = set, to = Room,
sub_els = [#muc_owner{config = NewRoomCfg}]}),
%% Set subject
send(Config, #message{to = Room, type = groupchat,
body = [#text{data = <<"Subject">>}]}),
#message{from = NickJID, type = groupchat,
body = [#text{data = <<"Subject">>}]} = recv(),
%% Leaving
send(Config, #presence{type = unavailable, to = NickJID}),
#presence{from = NickJID, type = unavailable,
sub_els = [#muc_user{status_codes = NewCodes}]} = recv(),
true = lists:member(110, NewCodes),
body = [#text{data = Subject}]}),
#message{from = MyNickJID, type = groupchat,
body = [#text{data = Subject}]} = recv(),
%% Sending messages (and thus, populating history for our peer)
lists:foreach(
fun(N) ->
Text = #text{data = jlib:integer_to_binary(N)},
I = send(Config, #message{to = Room, body = [Text],
type = groupchat}),
#message{from = MyNickJID, id = I,
type = groupchat,
body = [Text]} = recv()
end, lists:seq(1, 5)),
%% Inviting the peer
send(Config, #message{to = Room, type = normal,
sub_els =
[#muc_user{
invites =
[#muc_invite{to = PeerJID}]}]}),
%% Peer is joining
#presence{from = PeerNickJID,
sub_els = [#muc_user{
items = [#muc_item{role = visitor,
jid = PeerJID,
affiliation = none}]}]} = recv(),
%% Receiving a voice request
#message{from = Room,
sub_els = [#xdata{type = form,
instructions = [_],
fields = VoiceReqFs}]} = recv(),
%% Approving the voice request
ReplyVoiceReqFs =
lists:map(
fun(#xdata_field{var = Var, values = OrigVals}) ->
Vals = case {Var, OrigVals} of
{<<"FORM_TYPE">>,
[<<"http://jabber.org/protocol/muc#request">>]} ->
OrigVals;
{<<"muc#role">>, [<<"participant">>]} ->
[<<"participant">>];
{<<"muc#jid">>, [PeerJIDStr]} ->
[PeerJIDStr];
{<<"muc#roomnick">>, [PeerNick]} ->
[PeerNick];
{<<"muc#request_allow">>, [<<"0">>]} ->
[<<"1">>]
end,
#xdata_field{values = Vals, var = Var}
end, VoiceReqFs),
send(Config, #message{to = Room,
sub_els = [#xdata{type = submit,
fields = ReplyVoiceReqFs}]}),
%% Peer is becoming a participant
#presence{from = PeerNickJID,
sub_els = [#muc_user{
items = [#muc_item{role = participant,
jid = PeerJID,
affiliation = none}]}]} = recv(),
%% Receive private message from the peer
#message{from = PeerNickJID, body = [#text{data = Subject}]} = recv(),
%% Granting membership to the peer and localhost server
I1 = send(Config,
#iq{type = set, to = Room,
sub_els =
[#muc_admin{
items = [#muc_item{jid = Localhost,
affiliation = member},
#muc_item{nick = PeerNick,
jid = PeerBareJID,
affiliation = member}]}]}),
%% Peer became a member
#presence{from = PeerNickJID,
sub_els = [#muc_user{
items = [#muc_item{affiliation = member,
jid = PeerJID,
role = participant}]}]} = recv(),
%% BUG: We should not receive any sub_els!
#iq{type = result, id = I1, sub_els = [_|_]} = recv(),
%% Receive groupchat message from the peer
#message{type = groupchat, from = PeerNickJID,
body = [#text{data = Subject}]} = recv(),
%% Kick the peer
I2 = send(Config,
#iq{type = set, to = Room,
sub_els = [#muc_admin{
items = [#muc_item{nick = PeerNick,
role = none}]}]}),
%% Got notification the peer is kicked
%% 307 -> Inform user that he or she has been kicked from the room
#presence{from = PeerNickJID,
sub_els = [#muc_user{
status_codes = [307],
items = [#muc_item{affiliation = member,
jid = PeerJID,
role = none}]}]} = recv(),
%% BUG: We should not receive any sub_els!
#iq{type = result, id = I2, sub_els = [_|_]} = recv(),
%% Destroying the room
I3 = send(Config,
#iq{type = set, to = Room,
sub_els = [#muc_owner{
destroy = #muc_owner_destroy{
reason = Subject}}]}),
%% Kicked off
#presence{from = MyNickJID, type = unavailable,
sub_els = [#muc_user{items = [#muc_item{role = none,
affiliation = none}],
destroy = #muc_user_destroy{
reason = Subject}}]} = recv(),
%% BUG: We should not receive any sub_els!
#iq{type = result, id = I3, sub_els = [_|_]} = recv(),
disconnect(Config).
muc_slave(Config) ->
MyJID = my_jid(Config),
MyBareJID = jlib:jid_remove_resource(MyJID),
PeerJID = ?config(master, Config),
MUC = muc_jid(Config),
Room = muc_room_jid(Config),
MyNick = ?config(slave_nick, Config),
MyNickJID = jlib:jid_replace_resource(Room, MyNick),
PeerNick = ?config(master_nick, Config),
PeerNickJID = jlib:jid_replace_resource(Room, PeerNick),
Subject = ?config(room_subject, Config),
Localhost = jlib:make_jid(<<"">>, <<"localhost">>, <<"">>),
%% Receive an invite from the peer
#message{from = Room, type = normal,
sub_els =
[#muc_user{invites =
[#muc_invite{from = PeerJID}]}]} = recv(),
%% But before joining we discover the MUC service first
%% to check if the room is in the disco list
#iq{type = result,
sub_els = [#disco_items{items = [#disco_item{jid = Room}]}]} =
send_recv(Config, #iq{type = get, to = MUC,
sub_els = [#disco_items{}]}),
%% Now check if the peer is in the room. We check this via disco#items
#iq{type = result,
sub_els = [#disco_items{items = [#disco_item{jid = PeerNickJID,
name = PeerNick}]}]} =
send_recv(Config, #iq{type = get, to = Room,
sub_els = [#disco_items{}]}),
%% Now joining
send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}),
%% First presence is from the participant, i.e. from the peer
#presence{
from = PeerNickJID,
sub_els = [#muc_user{
status_codes = [],
items = [#muc_item{role = moderator,
affiliation = owner}]}]} = recv(),
%% The next is the self-presence (code 110 means it)
#presence{
from = MyNickJID,
sub_els = [#muc_user{
status_codes = [110],
items = [#muc_item{role = visitor,
affiliation = none}]}]} = recv(),
%% Receive the room subject
#message{from = PeerNickJID, type = groupchat,
body = [#text{data = Subject}],
sub_els = [#delay{}, #legacy_delay{}]} = recv(),
%% Receive MUC history
lists:foreach(
fun(N) ->
Text = #text{data = jlib:integer_to_binary(N)},
#message{from = PeerNickJID,
type = groupchat,
body = [Text],
sub_els = [#delay{}, #legacy_delay{}]} = recv()
end, lists:seq(1, 5)),
%% Sending a voice request
VoiceReq = #xdata{
type = submit,
fields =
[#xdata_field{
var = <<"FORM_TYPE">>,
values = [<<"http://jabber.org/protocol/muc#request">>]},
#xdata_field{
var = <<"muc#role">>,
type = 'text-single',
values = [<<"participant">>]}]},
send(Config, #message{to = Room, sub_els = [VoiceReq]}),
%% Becoming a participant
#presence{from = MyNickJID,
sub_els = [#muc_user{
items = [#muc_item{role = participant,
affiliation = none}]}]} = recv(),
%% Sending private message to the peer
send(Config, #message{to = PeerNickJID,
body = [#text{data = Subject}]}),
%% Becoming a member
#presence{from = MyNickJID,
sub_els = [#muc_user{
items = [#muc_item{role = participant,
affiliation = member}]}]} = recv(),
%% Retrieving a member list
#iq{type = result, sub_els = [#muc_admin{items = MemberList}]} =
send_recv(Config,
#iq{type = get, to = Room,
sub_els =
[#muc_admin{items = [#muc_item{affiliation = member}]}]}),
[#muc_item{affiliation = member,
jid = Localhost},
#muc_item{affiliation = member,
jid = MyBareJID}] = lists:keysort(#muc_item.jid, MemberList),
%% Sending groupchat message
send(Config, #message{to = Room, type = groupchat,
body = [#text{data = Subject}]}),
%% Receive this message back
#message{type = groupchat, from = MyNickJID,
body = [#text{data = Subject}]} = recv(),
%% We're kicked off
%% 307 -> Inform user that he or she has been kicked from the room
#presence{from = MyNickJID, type = unavailable,
sub_els = [#muc_user{
status_codes = [307],
items = [#muc_item{affiliation = member,
role = none}]}]} = recv(),
disconnect(Config).
offline_master(Config) ->

View File

@ -39,6 +39,9 @@ init_config(Config) ->
{server_host, "localhost"},
{server, ?COMMON_VHOST},
{user, <<"test_single">>},
{master_nick, <<"master_nick">>},
{slave_nick, <<"slave_nick">>},
{room_subject, <<"hello, world!">>},
{certfile, CertFile},
{base_dir, BaseDir},
{resource, <<"resource">>},

View File

@ -14,6 +14,21 @@ decode({xmlel, _name, _attrs, _} = _el) ->
case {_name, get_attr(<<"xmlns">>, _attrs)} of
{<<"x">>, <<"http://jabber.org/protocol/muc">>} ->
decode_muc(_el);
{<<"query">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
decode_muc_admin(_el);
{<<"reason">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
decode_muc_admin_reason(_el);
{<<"continue">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
decode_muc_admin_continue(_el);
{<<"actor">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
decode_muc_admin_actor(_el);
{<<"item">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
decode_muc_admin_item(_el);
{<<"query">>,
<<"http://jabber.org/protocol/muc#owner">>} ->
decode_muc_owner(_el);
@ -691,6 +706,21 @@ decode({xmlel, _name, _attrs, _} = _el) ->
is_known_tag({xmlel, _name, _attrs, _} = _el) ->
case {_name, get_attr(<<"xmlns">>, _attrs)} of
{<<"x">>, <<"http://jabber.org/protocol/muc">>} -> true;
{<<"query">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
true;
{<<"reason">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
true;
{<<"continue">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
true;
{<<"actor">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
true;
{<<"item">>,
<<"http://jabber.org/protocol/muc#admin">>} ->
true;
{<<"query">>,
<<"http://jabber.org/protocol/muc#owner">>} ->
true;
@ -1240,6 +1270,10 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) ->
encode({muc, _, _} = X) ->
encode_muc(X,
[{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]);
encode({muc_admin, _} = Query) ->
encode_muc_admin(Query,
[{<<"xmlns">>,
<<"http://jabber.org/protocol/muc#admin">>}]);
encode({muc_owner, _, _} = Query) ->
encode_muc_owner(Query,
[{<<"xmlns">>,
@ -1252,14 +1286,6 @@ encode({muc_user, _, _, _, _, _, _} = X) ->
encode_muc_user(X,
[{<<"xmlns">>,
<<"http://jabber.org/protocol/muc#user">>}]);
encode({muc_item, _, _, _, _, _, _, _} = Item) ->
encode_muc_user_item(Item,
[{<<"xmlns">>,
<<"http://jabber.org/protocol/muc#user">>}]);
encode({muc_actor, _, _} = Actor) ->
encode_muc_user_actor(Actor,
[{<<"xmlns">>,
<<"http://jabber.org/protocol/muc#user">>}]);
encode({muc_invite, _, _, _} = Invite) ->
encode_muc_user_invite(Invite,
[{<<"xmlns">>,
@ -1742,14 +1768,15 @@ pp(muc_history, 4) ->
pp(muc_decline, 3) -> [reason, from, to];
pp(muc_user_destroy, 2) -> [reason, jid];
pp(muc_invite, 3) -> [reason, from, to];
pp(muc_actor, 2) -> [jid, nick];
pp(muc_item, 7) ->
[actor, continue, reason, affiliation, role, jid, nick];
pp(muc_user, 6) ->
[decline, destroy, invites, items, status_codes,
password];
pp(muc_owner_destroy, 3) -> [jid, reason, password];
pp(muc_owner, 2) -> [destroy, config];
pp(muc_item, 7) ->
[actor, continue, reason, affiliation, role, jid, nick];
pp(muc_actor, 2) -> [jid, nick];
pp(muc_admin, 1) -> [items];
pp(muc, 2) -> [history, password];
pp(_, _) -> no.
@ -1834,6 +1861,319 @@ encode_muc_attr_password(undefined, _acc) -> _acc;
encode_muc_attr_password(_val, _acc) ->
[{<<"password">>, _val} | _acc].
decode_muc_admin({xmlel, <<"query">>, _attrs, _els}) ->
Items = decode_muc_admin_els(_els, []),
{muc_admin, Items}.
decode_muc_admin_els([], Items) -> lists:reverse(Items);
decode_muc_admin_els([{xmlel, <<"item">>, _attrs, _} =
_el
| _els],
Items) ->
_xmlns = get_attr(<<"xmlns">>, _attrs),
if _xmlns == <<>>;
_xmlns == <<"http://jabber.org/protocol/muc#admin">> ->
decode_muc_admin_els(_els,
[decode_muc_admin_item(_el) | Items]);
true -> decode_muc_admin_els(_els, Items)
end;
decode_muc_admin_els([_ | _els], Items) ->
decode_muc_admin_els(_els, Items).
encode_muc_admin({muc_admin, Items}, _xmlns_attrs) ->
_els = 'encode_muc_admin_$items'(Items, []),
_attrs = _xmlns_attrs,
{xmlel, <<"query">>, _attrs, _els}.
'encode_muc_admin_$items'([], _acc) -> _acc;
'encode_muc_admin_$items'([Items | _els], _acc) ->
'encode_muc_admin_$items'(_els,
[encode_muc_admin_item(Items, []) | _acc]).
decode_muc_admin_reason({xmlel, <<"reason">>, _attrs,
_els}) ->
Cdata = decode_muc_admin_reason_els(_els, <<>>), Cdata.
decode_muc_admin_reason_els([], Cdata) ->
decode_muc_admin_reason_cdata(Cdata);
decode_muc_admin_reason_els([{xmlcdata, _data} | _els],
Cdata) ->
decode_muc_admin_reason_els(_els,
<<Cdata/binary, _data/binary>>);
decode_muc_admin_reason_els([_ | _els], Cdata) ->
decode_muc_admin_reason_els(_els, Cdata).
encode_muc_admin_reason(Cdata, _xmlns_attrs) ->
_els = encode_muc_admin_reason_cdata(Cdata, []),
_attrs = _xmlns_attrs,
{xmlel, <<"reason">>, _attrs, _els}.
decode_muc_admin_reason_cdata(<<>>) -> undefined;
decode_muc_admin_reason_cdata(_val) -> _val.
encode_muc_admin_reason_cdata(undefined, _acc) -> _acc;
encode_muc_admin_reason_cdata(_val, _acc) ->
[{xmlcdata, _val} | _acc].
decode_muc_admin_continue({xmlel, <<"continue">>,
_attrs, _els}) ->
Thread = decode_muc_admin_continue_attrs(_attrs,
undefined),
Thread.
decode_muc_admin_continue_attrs([{<<"thread">>, _val}
| _attrs],
_Thread) ->
decode_muc_admin_continue_attrs(_attrs, _val);
decode_muc_admin_continue_attrs([_ | _attrs], Thread) ->
decode_muc_admin_continue_attrs(_attrs, Thread);
decode_muc_admin_continue_attrs([], Thread) ->
decode_muc_admin_continue_attr_thread(Thread).
encode_muc_admin_continue(Thread, _xmlns_attrs) ->
_els = [],
_attrs = encode_muc_admin_continue_attr_thread(Thread,
_xmlns_attrs),
{xmlel, <<"continue">>, _attrs, _els}.
decode_muc_admin_continue_attr_thread(undefined) ->
undefined;
decode_muc_admin_continue_attr_thread(_val) -> _val.
encode_muc_admin_continue_attr_thread(undefined,
_acc) ->
_acc;
encode_muc_admin_continue_attr_thread(_val, _acc) ->
[{<<"thread">>, _val} | _acc].
decode_muc_admin_actor({xmlel, <<"actor">>, _attrs,
_els}) ->
{Jid, Nick} = decode_muc_admin_actor_attrs(_attrs,
undefined, undefined),
{muc_actor, Jid, Nick}.
decode_muc_admin_actor_attrs([{<<"jid">>, _val}
| _attrs],
_Jid, Nick) ->
decode_muc_admin_actor_attrs(_attrs, _val, Nick);
decode_muc_admin_actor_attrs([{<<"nick">>, _val}
| _attrs],
Jid, _Nick) ->
decode_muc_admin_actor_attrs(_attrs, Jid, _val);
decode_muc_admin_actor_attrs([_ | _attrs], Jid, Nick) ->
decode_muc_admin_actor_attrs(_attrs, Jid, Nick);
decode_muc_admin_actor_attrs([], Jid, Nick) ->
{decode_muc_admin_actor_attr_jid(Jid),
decode_muc_admin_actor_attr_nick(Nick)}.
encode_muc_admin_actor({muc_actor, Jid, Nick},
_xmlns_attrs) ->
_els = [],
_attrs = encode_muc_admin_actor_attr_nick(Nick,
encode_muc_admin_actor_attr_jid(Jid,
_xmlns_attrs)),
{xmlel, <<"actor">>, _attrs, _els}.
decode_muc_admin_actor_attr_jid(undefined) -> undefined;
decode_muc_admin_actor_attr_jid(_val) ->
case catch dec_jid(_val) of
{'EXIT', _} ->
erlang:error({xmpp_codec,
{bad_attr_value, <<"jid">>, <<"actor">>,
<<"http://jabber.org/protocol/muc#admin">>}});
_res -> _res
end.
encode_muc_admin_actor_attr_jid(undefined, _acc) ->
_acc;
encode_muc_admin_actor_attr_jid(_val, _acc) ->
[{<<"jid">>, enc_jid(_val)} | _acc].
decode_muc_admin_actor_attr_nick(undefined) ->
undefined;
decode_muc_admin_actor_attr_nick(_val) -> _val.
encode_muc_admin_actor_attr_nick(undefined, _acc) ->
_acc;
encode_muc_admin_actor_attr_nick(_val, _acc) ->
[{<<"nick">>, _val} | _acc].
decode_muc_admin_item({xmlel, <<"item">>, _attrs,
_els}) ->
{Actor, Continue, Reason} =
decode_muc_admin_item_els(_els, undefined, undefined,
undefined),
{Affiliation, Role, Jid, Nick} =
decode_muc_admin_item_attrs(_attrs, undefined,
undefined, undefined, undefined),
{muc_item, Actor, Continue, Reason, Affiliation, Role,
Jid, Nick}.
decode_muc_admin_item_els([], Actor, Continue,
Reason) ->
{Actor, Continue, Reason};
decode_muc_admin_item_els([{xmlel, <<"actor">>, _attrs,
_} =
_el
| _els],
Actor, Continue, Reason) ->
_xmlns = get_attr(<<"xmlns">>, _attrs),
if _xmlns == <<>>;
_xmlns == <<"http://jabber.org/protocol/muc#admin">> ->
decode_muc_admin_item_els(_els,
decode_muc_admin_actor(_el), Continue,
Reason);
true ->
decode_muc_admin_item_els(_els, Actor, Continue, Reason)
end;
decode_muc_admin_item_els([{xmlel, <<"continue">>,
_attrs, _} =
_el
| _els],
Actor, Continue, Reason) ->
_xmlns = get_attr(<<"xmlns">>, _attrs),
if _xmlns == <<>>;
_xmlns == <<"http://jabber.org/protocol/muc#admin">> ->
decode_muc_admin_item_els(_els, Actor,
decode_muc_admin_continue(_el), Reason);
true ->
decode_muc_admin_item_els(_els, Actor, Continue, Reason)
end;
decode_muc_admin_item_els([{xmlel, <<"reason">>, _attrs,
_} =
_el
| _els],
Actor, Continue, Reason) ->
_xmlns = get_attr(<<"xmlns">>, _attrs),
if _xmlns == <<>>;
_xmlns == <<"http://jabber.org/protocol/muc#admin">> ->
decode_muc_admin_item_els(_els, Actor, Continue,
decode_muc_admin_reason(_el));
true ->
decode_muc_admin_item_els(_els, Actor, Continue, Reason)
end;
decode_muc_admin_item_els([_ | _els], Actor, Continue,
Reason) ->
decode_muc_admin_item_els(_els, Actor, Continue,
Reason).
decode_muc_admin_item_attrs([{<<"affiliation">>, _val}
| _attrs],
_Affiliation, Role, Jid, Nick) ->
decode_muc_admin_item_attrs(_attrs, _val, Role, Jid,
Nick);
decode_muc_admin_item_attrs([{<<"role">>, _val}
| _attrs],
Affiliation, _Role, Jid, Nick) ->
decode_muc_admin_item_attrs(_attrs, Affiliation, _val,
Jid, Nick);
decode_muc_admin_item_attrs([{<<"jid">>, _val}
| _attrs],
Affiliation, Role, _Jid, Nick) ->
decode_muc_admin_item_attrs(_attrs, Affiliation, Role,
_val, Nick);
decode_muc_admin_item_attrs([{<<"nick">>, _val}
| _attrs],
Affiliation, Role, Jid, _Nick) ->
decode_muc_admin_item_attrs(_attrs, Affiliation, Role,
Jid, _val);
decode_muc_admin_item_attrs([_ | _attrs], Affiliation,
Role, Jid, Nick) ->
decode_muc_admin_item_attrs(_attrs, Affiliation, Role,
Jid, Nick);
decode_muc_admin_item_attrs([], Affiliation, Role, Jid,
Nick) ->
{decode_muc_admin_item_attr_affiliation(Affiliation),
decode_muc_admin_item_attr_role(Role),
decode_muc_admin_item_attr_jid(Jid),
decode_muc_admin_item_attr_nick(Nick)}.
encode_muc_admin_item({muc_item, Actor, Continue,
Reason, Affiliation, Role, Jid, Nick},
_xmlns_attrs) ->
_els = 'encode_muc_admin_item_$reason'(Reason,
'encode_muc_admin_item_$continue'(Continue,
'encode_muc_admin_item_$actor'(Actor,
[]))),
_attrs = encode_muc_admin_item_attr_nick(Nick,
encode_muc_admin_item_attr_jid(Jid,
encode_muc_admin_item_attr_role(Role,
encode_muc_admin_item_attr_affiliation(Affiliation,
_xmlns_attrs)))),
{xmlel, <<"item">>, _attrs, _els}.
'encode_muc_admin_item_$actor'(undefined, _acc) -> _acc;
'encode_muc_admin_item_$actor'(Actor, _acc) ->
[encode_muc_admin_actor(Actor, []) | _acc].
'encode_muc_admin_item_$continue'(undefined, _acc) ->
_acc;
'encode_muc_admin_item_$continue'(Continue, _acc) ->
[encode_muc_admin_continue(Continue, []) | _acc].
'encode_muc_admin_item_$reason'(undefined, _acc) ->
_acc;
'encode_muc_admin_item_$reason'(Reason, _acc) ->
[encode_muc_admin_reason(Reason, []) | _acc].
decode_muc_admin_item_attr_affiliation(undefined) ->
undefined;
decode_muc_admin_item_attr_affiliation(_val) ->
case catch dec_enum(_val,
[admin, member, none, outcast, owner])
of
{'EXIT', _} ->
erlang:error({xmpp_codec,
{bad_attr_value, <<"affiliation">>, <<"item">>,
<<"http://jabber.org/protocol/muc#admin">>}});
_res -> _res
end.
encode_muc_admin_item_attr_affiliation(undefined,
_acc) ->
_acc;
encode_muc_admin_item_attr_affiliation(_val, _acc) ->
[{<<"affiliation">>, enc_enum(_val)} | _acc].
decode_muc_admin_item_attr_role(undefined) -> undefined;
decode_muc_admin_item_attr_role(_val) ->
case catch dec_enum(_val,
[moderator, none, participant, visitor])
of
{'EXIT', _} ->
erlang:error({xmpp_codec,
{bad_attr_value, <<"role">>, <<"item">>,
<<"http://jabber.org/protocol/muc#admin">>}});
_res -> _res
end.
encode_muc_admin_item_attr_role(undefined, _acc) ->
_acc;
encode_muc_admin_item_attr_role(_val, _acc) ->
[{<<"role">>, enc_enum(_val)} | _acc].
decode_muc_admin_item_attr_jid(undefined) -> undefined;
decode_muc_admin_item_attr_jid(_val) ->
case catch dec_jid(_val) of
{'EXIT', _} ->
erlang:error({xmpp_codec,
{bad_attr_value, <<"jid">>, <<"item">>,
<<"http://jabber.org/protocol/muc#admin">>}});
_res -> _res
end.
encode_muc_admin_item_attr_jid(undefined, _acc) -> _acc;
encode_muc_admin_item_attr_jid(_val, _acc) ->
[{<<"jid">>, enc_jid(_val)} | _acc].
decode_muc_admin_item_attr_nick(undefined) -> undefined;
decode_muc_admin_item_attr_nick(_val) -> _val.
encode_muc_admin_item_attr_nick(undefined, _acc) ->
_acc;
encode_muc_admin_item_attr_nick(_val, _acc) ->
[{<<"nick">>, _val} | _acc].
decode_muc_owner({xmlel, <<"query">>, _attrs, _els}) ->
{Config, Destroy} = decode_muc_owner_els(_els,
undefined, undefined),

View File

@ -61,9 +61,6 @@
node :: binary(),
publisher :: binary()}).
-record(muc_actor, {jid :: any(),
nick :: binary()}).
-record(stat, {name :: binary(),
units :: binary(),
value :: binary(),
@ -126,6 +123,9 @@
subid :: binary(),
type :: 'none' | 'pending' | 'subscribed' | 'unconfigured'}).
-record(muc_actor, {jid :: any(),
nick :: binary()}).
-record(shim, {headers = [] :: [{binary(),'undefined' | binary()}]}).
-record(caps, {hash :: binary(),
@ -208,6 +208,8 @@
status_codes = [] :: [pos_integer()],
password :: binary()}).
-record(muc_admin, {items = [] :: [#muc_item{}]}).
-record(bytestreams, {hosts = [] :: [#streamhost{}],
used :: any(),
activate :: any(),

View File

@ -1974,6 +1974,56 @@
label = '$destroy'},
#ref{name = xdata, min = 0, max = 1, label = '$config'}]}).
-xml(muc_admin_item,
#elem{name = <<"item">>,
xmlns = <<"http://jabber.org/protocol/muc#admin">>,
result = {muc_item, '$actor', '$continue', '$reason',
'$affiliation', '$role', '$jid', '$nick'},
refs = [#ref{name = muc_admin_actor,
min = 0, max = 1, label = '$actor'},
#ref{name = muc_admin_continue,
min = 0, max = 1, label = '$continue'},
#ref{name = muc_admin_reason,
min = 0, max = 1, label = '$reason'}],
attrs = [#attr{name = <<"affiliation">>,
dec = {dec_enum, [[admin, member, none,
outcast, owner]]},
enc = {enc_enum, []}},
#attr{name = <<"role">>,
dec = {dec_enum, [[moderator, none,
participant, visitor]]},
enc = {enc_enum, []}},
#attr{name = <<"jid">>,
dec = {dec_jid, []},
enc = {enc_jid, []}},
#attr{name = <<"nick">>}]}).
-xml(muc_admin_actor,
#elem{name = <<"actor">>,
xmlns = <<"http://jabber.org/protocol/muc#admin">>,
result = {muc_actor, '$jid', '$nick'},
attrs = [#attr{name = <<"jid">>,
dec = {dec_jid, []},
enc = {enc_jid, []}},
#attr{name = <<"nick">>}]}).
-xml(muc_admin_continue,
#elem{name = <<"continue">>,
xmlns = <<"http://jabber.org/protocol/muc#admin">>,
result = '$thread',
attrs = [#attr{name = <<"thread">>}]}).
-xml(muc_admin_reason,
#elem{name = <<"reason">>,
xmlns = <<"http://jabber.org/protocol/muc#admin">>,
result = '$cdata'}).
-xml(muc_admin,
#elem{name = <<"query">>,
xmlns = <<"http://jabber.org/protocol/muc#admin">>,
result = {muc_admin, '$items'},
refs = [#ref{name = muc_admin_item, label = '$items'}]}).
-xml(muc,
#elem{name = <<"x">>,
xmlns = <<"http://jabber.org/protocol/muc">>,