mirror of
https://github.com/processone/ejabberd
synced 2025-10-05 19:42:11 +02:00
* src/mod_irc/: Added support for private chats, nicks changes and
error handling SVN Revision: 78
This commit is contained in:
parent
17000076ad
commit
b704efd553
3 changed files with 253 additions and 60 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
2003-02-18 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
|
* src/mod_irc/: Added support for private chats, nicks changes and
|
||||||
|
error handling
|
||||||
|
|
||||||
2003-02-17 Alexey Shchepin <alexey@sevcom.net>
|
2003-02-17 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
* src/mod_irc/: Still not completed...
|
* src/mod_irc/: Still not completed...
|
||||||
|
|
|
@ -91,21 +91,39 @@ do_route(Host, From, To, Packet) ->
|
||||||
irc_connection,
|
irc_connection,
|
||||||
#irc_connection{userserver = {From, Server},
|
#irc_connection{userserver = {From, Server},
|
||||||
pid = Pid}),
|
pid = Pid}),
|
||||||
mod_irc_connection:route(
|
mod_irc_connection:route_chan(
|
||||||
Pid, Channel, Resource, Packet),
|
Pid, Channel, Resource, Packet),
|
||||||
ok;
|
ok;
|
||||||
[R] ->
|
[R] ->
|
||||||
Pid = R#irc_connection.pid,
|
Pid = R#irc_connection.pid,
|
||||||
io:format("send to process ~p~n",
|
io:format("send to process ~p~n",
|
||||||
[Pid]),
|
[Pid]),
|
||||||
mod_irc_connection:route(
|
mod_irc_connection:route_chan(
|
||||||
Pid, Channel, Resource, Packet),
|
Pid, Channel, Resource, Packet),
|
||||||
ok
|
ok
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Err = jlib:make_error_reply(
|
case string:tokens(ChanServ, "!") of
|
||||||
Packet, "406", "Not Acceptable"),
|
[[_ | _] = Nick, [_ | _] = Server] ->
|
||||||
ejabberd_router:route(To, From, Err)
|
case ets:lookup(irc_connection, {From, Server}) of
|
||||||
|
[] ->
|
||||||
|
Err = jlib:make_error_reply(
|
||||||
|
Packet,
|
||||||
|
"503", "Service Unavailable"),
|
||||||
|
ejabberd_router:route(To, From, Err);
|
||||||
|
[R] ->
|
||||||
|
Pid = R#irc_connection.pid,
|
||||||
|
io:format("send to process ~p~n",
|
||||||
|
[Pid]),
|
||||||
|
mod_irc_connection:route_nick(
|
||||||
|
Pid, Nick, Packet),
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
Err = jlib:make_error_reply(
|
||||||
|
Packet, "406", "Not Acceptable"),
|
||||||
|
ejabberd_router:route(To, From, Err)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
-behaviour(gen_fsm).
|
-behaviour(gen_fsm).
|
||||||
|
|
||||||
%% External exports
|
%% External exports
|
||||||
-export([start/3, receiver/2, route/4]).
|
-export([start/3, receiver/2, route_chan/4, route_nick/3]).
|
||||||
|
|
||||||
%% gen_fsm callbacks
|
%% gen_fsm callbacks
|
||||||
-export([init/1,
|
-export([init/1,
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
-record(state, {socket, receiver, queue,
|
-record(state, {socket, receiver, queue,
|
||||||
user, myname, server, nick,
|
user, myname, server, nick,
|
||||||
channels = ?SETS:new(),
|
channels = dict:new(),
|
||||||
inbuf = "", outbuf = ""}).
|
inbuf = "", outbuf = ""}).
|
||||||
|
|
||||||
-define(IRC_ENCODING, "koi8-r").
|
-define(IRC_ENCODING, "koi8-r").
|
||||||
|
@ -110,17 +110,6 @@ open_socket(init, StateData) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
wait_for_registration(closed, StateData) ->
|
wait_for_registration(closed, StateData) ->
|
||||||
bounce_messages("Server Connect Failed"),
|
|
||||||
lists:foreach(
|
|
||||||
fun(Chan) ->
|
|
||||||
ejabberd_router:route(
|
|
||||||
{lists:concat([Chan, "%", StateData#state.server]),
|
|
||||||
StateData#state.myname, StateData#state.nick},
|
|
||||||
StateData#state.user,
|
|
||||||
{xmlelement, "presence", [{"type", "error"}],
|
|
||||||
[{xmlelement, "error", [{"code", "502"}],
|
|
||||||
[{xmlcdata, "Server Connect Failed"}]}]})
|
|
||||||
end, ?SETS:to_list(StateData#state.channels)),
|
|
||||||
{stop, normal, StateData}.
|
{stop, normal, StateData}.
|
||||||
|
|
||||||
stream_established({xmlstreamend, Name}, StateData) ->
|
stream_established({xmlstreamend, Name}, StateData) ->
|
||||||
|
@ -187,31 +176,41 @@ code_change(OldVsn, StateName, StateData, Extra) ->
|
||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||||
%% {stop, Reason, NewStateData}
|
%% {stop, Reason, NewStateData}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
handle_info({route, Channel, Resource, {xmlelement, "presence", Attrs, Els}},
|
handle_info({route_chan, Channel, Resource,
|
||||||
|
{xmlelement, "presence", Attrs, Els}},
|
||||||
StateName, StateData) ->
|
StateName, StateData) ->
|
||||||
NewStateData =
|
NewStateData =
|
||||||
case xml:get_attr_s("type", Attrs) of
|
case xml:get_attr_s("type", Attrs) of
|
||||||
"unavailable" ->
|
"unavailable" ->
|
||||||
S1 = ?SEND(io_lib:format("PART #~s\r\n", [Channel])),
|
S1 = ?SEND(io_lib:format("PART #~s\r\n", [Channel])),
|
||||||
S1#state{channels =
|
S1#state{channels =
|
||||||
remove_element(Channel, S1#state.channels)};
|
dict:erase(Channel, S1#state.channels)};
|
||||||
"subscribe" -> StateData;
|
"subscribe" -> StateData;
|
||||||
"subscribed" -> StateData;
|
"subscribed" -> StateData;
|
||||||
"unsubscribe" -> StateData;
|
"unsubscribe" -> StateData;
|
||||||
"unsubscribed" -> StateData;
|
"unsubscribed" -> StateData;
|
||||||
_ ->
|
_ ->
|
||||||
S1 = ?SEND(io_lib:format("JOIN #~s\r\n", [Channel])),
|
S1 = ?SEND(io_lib:format("NICK ~s\r\n"
|
||||||
S1#state{channels =
|
"JOIN #~s\r\n",
|
||||||
?SETS:add_element(Channel, S1#state.channels)}
|
[Resource, Channel])),
|
||||||
|
case dict:is_key(Channel, S1#state.channels) of
|
||||||
|
true ->
|
||||||
|
S1#state{nick = Resource};
|
||||||
|
_ ->
|
||||||
|
S1#state{nick = Resource,
|
||||||
|
channels =
|
||||||
|
dict:store(Channel, ?SETS:new(),
|
||||||
|
S1#state.channels)}
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
case ?SETS:is_empty(NewStateData#state.channels) of
|
case length(dict:fetch_keys(NewStateData#state.channels)) of
|
||||||
true ->
|
0 ->
|
||||||
{stop, normal, NewStateData};
|
{stop, normal, NewStateData};
|
||||||
_ ->
|
_ ->
|
||||||
{next_state, StateName, NewStateData}
|
{next_state, StateName, NewStateData}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_info({route, Channel, Resource,
|
handle_info({route_chan, Channel, Resource,
|
||||||
{xmlelement, "message", Attrs, Els} = El},
|
{xmlelement, "message", Attrs, Els} = El},
|
||||||
StateName, StateData) ->
|
StateName, StateData) ->
|
||||||
NewStateData =
|
NewStateData =
|
||||||
|
@ -236,11 +235,58 @@ handle_info({route, Channel, Resource,
|
||||||
[Channel, S])
|
[Channel, S])
|
||||||
end, Strings)),
|
end, Strings)),
|
||||||
?SEND(Res);
|
?SEND(Res);
|
||||||
_ -> StateData
|
"chat" ->
|
||||||
|
Body = xml:get_path_s(El, [{elem, "body"}, cdata]),
|
||||||
|
Body1 = case Body of
|
||||||
|
[$/, $m, $e, $ | Rest] ->
|
||||||
|
"\001ACTION " ++ Rest ++ "\001";
|
||||||
|
_ ->
|
||||||
|
Body
|
||||||
|
end,
|
||||||
|
Strings = string:tokens(Body1, "\n"),
|
||||||
|
Res = lists:concat(
|
||||||
|
lists:map(
|
||||||
|
fun(S) ->
|
||||||
|
io_lib:format("PRIVMSG ~s :~s\r\n",
|
||||||
|
[Resource, S])
|
||||||
|
end, Strings)),
|
||||||
|
?SEND(Res);
|
||||||
|
_ ->
|
||||||
|
StateData
|
||||||
end,
|
end,
|
||||||
{next_state, StateName, NewStateData};
|
{next_state, StateName, NewStateData};
|
||||||
|
|
||||||
handle_info({route, Channel, Resource, Packet}, StateName, StateData) ->
|
handle_info({route_chan, Channel, Resource, Packet}, StateName, StateData) ->
|
||||||
|
{next_state, StateName, StateData};
|
||||||
|
|
||||||
|
|
||||||
|
handle_info({route_nick, Nick,
|
||||||
|
{xmlelement, "message", Attrs, Els} = El},
|
||||||
|
StateName, StateData) ->
|
||||||
|
NewStateData =
|
||||||
|
case xml:get_attr_s("type", Attrs) of
|
||||||
|
"chat" ->
|
||||||
|
Body = xml:get_path_s(El, [{elem, "body"}, cdata]),
|
||||||
|
Body1 = case Body of
|
||||||
|
[$/, $m, $e, $ | Rest] ->
|
||||||
|
"\001ACTION " ++ Rest ++ "\001";
|
||||||
|
_ ->
|
||||||
|
Body
|
||||||
|
end,
|
||||||
|
Strings = string:tokens(Body1, "\n"),
|
||||||
|
Res = lists:concat(
|
||||||
|
lists:map(
|
||||||
|
fun(S) ->
|
||||||
|
io_lib:format("PRIVMSG ~s :~s\r\n",
|
||||||
|
[Nick, S])
|
||||||
|
end, Strings)),
|
||||||
|
?SEND(Res);
|
||||||
|
_ ->
|
||||||
|
StateData
|
||||||
|
end,
|
||||||
|
{next_state, StateName, NewStateData};
|
||||||
|
|
||||||
|
handle_info({route_nick, Nick, Packet}, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData};
|
{next_state, StateName, StateData};
|
||||||
|
|
||||||
|
|
||||||
|
@ -253,20 +299,20 @@ handle_info({ircstring, [$: | String]}, StateName, StateData) ->
|
||||||
NewStateData =
|
NewStateData =
|
||||||
case Words of
|
case Words of
|
||||||
[_, "353" | Items] ->
|
[_, "353" | Items] ->
|
||||||
process_channel_list(StateData, Items),
|
process_channel_list(StateData, Items);
|
||||||
StateData;
|
|
||||||
[From, "PRIVMSG", [$# | Chan] | _] ->
|
[From, "PRIVMSG", [$# | Chan] | _] ->
|
||||||
process_chanprivmsg(StateData, Chan, From, String),
|
process_chanprivmsg(StateData, Chan, From, String),
|
||||||
StateData;
|
StateData;
|
||||||
[From, "PRIVMSG", Nick, ":\001VERSION\001" | _] ->
|
[From, "PRIVMSG", Nick, ":\001VERSION\001" | _] ->
|
||||||
process_version(StateData, Nick, From),
|
process_version(StateData, Nick, From),
|
||||||
StateData;
|
StateData;
|
||||||
|
[From, "PRIVMSG", Nick | _] ->
|
||||||
|
process_privmsg(StateData, Nick, From, String),
|
||||||
|
StateData;
|
||||||
[From, "PART", [$# | Chan] | _] ->
|
[From, "PART", [$# | Chan] | _] ->
|
||||||
process_part(StateData, Chan, From, String),
|
process_part(StateData, Chan, From, String);
|
||||||
StateData;
|
|
||||||
[From, "JOIN", Chan | _] ->
|
[From, "JOIN", Chan | _] ->
|
||||||
process_join(StateData, Chan, From, String),
|
process_join(StateData, Chan, From, String);
|
||||||
StateData;
|
|
||||||
[From, "MODE", [$# | Chan], "+o", Nick | _] ->
|
[From, "MODE", [$# | Chan], "+o", Nick | _] ->
|
||||||
process_mode_o(StateData, Chan, From, Nick,
|
process_mode_o(StateData, Chan, From, Nick,
|
||||||
"admin", "moderator"),
|
"admin", "moderator"),
|
||||||
|
@ -278,6 +324,8 @@ handle_info({ircstring, [$: | String]}, StateName, StateData) ->
|
||||||
[From, "KICK", [$# | Chan], Nick | _] ->
|
[From, "KICK", [$# | Chan], Nick | _] ->
|
||||||
process_kick(StateData, Chan, From, Nick),
|
process_kick(StateData, Chan, From, Nick),
|
||||||
StateData;
|
StateData;
|
||||||
|
[From, "NICK", Nick | _] ->
|
||||||
|
process_nick(StateData, From, Nick);
|
||||||
_ ->
|
_ ->
|
||||||
io:format("unknown irc command '~s'~n", [String]),
|
io:format("unknown irc command '~s'~n", [String]),
|
||||||
StateData
|
StateData
|
||||||
|
@ -292,6 +340,11 @@ handle_info({ircstring, [$: | String]}, StateName, StateData) ->
|
||||||
end,
|
end,
|
||||||
{next_state, stream_established, NewStateData1};
|
{next_state, stream_established, NewStateData1};
|
||||||
|
|
||||||
|
handle_info({ircstring, [$E, $R, $R, $O, $R | _] = String},
|
||||||
|
StateName, StateData) ->
|
||||||
|
process_error(StateData, String),
|
||||||
|
{next_state, StateName, StateData};
|
||||||
|
|
||||||
|
|
||||||
handle_info({ircstring, String}, StateName, StateData) ->
|
handle_info({ircstring, String}, StateName, StateData) ->
|
||||||
io:format("unknown irc command '~s'~n", [String]),
|
io:format("unknown irc command '~s'~n", [String]),
|
||||||
|
@ -331,6 +384,17 @@ handle_info({tcp_error, Socket, Reason}, StateName, StateData) ->
|
||||||
terminate(Reason, StateName, StateData) ->
|
terminate(Reason, StateName, StateData) ->
|
||||||
mod_irc:closed_conection(StateData#state.user,
|
mod_irc:closed_conection(StateData#state.user,
|
||||||
StateData#state.server),
|
StateData#state.server),
|
||||||
|
bounce_messages("Server Connect Failed"),
|
||||||
|
lists:foreach(
|
||||||
|
fun(Chan) ->
|
||||||
|
ejabberd_router:route(
|
||||||
|
{lists:concat([Chan, "%", StateData#state.server]),
|
||||||
|
StateData#state.myname, StateData#state.nick},
|
||||||
|
StateData#state.user,
|
||||||
|
{xmlelement, "presence", [{"type", "error"}],
|
||||||
|
[{xmlelement, "error", [{"code", "502"}],
|
||||||
|
[{xmlcdata, "Server Connect Failed"}]}]})
|
||||||
|
end, dict:fetch_keys(StateData#state.channels)),
|
||||||
case StateData#state.socket of
|
case StateData#state.socket of
|
||||||
undefined ->
|
undefined ->
|
||||||
ok;
|
ok;
|
||||||
|
@ -395,8 +459,11 @@ bounce_messages(Reason) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
route(Pid, Channel, Resource, Packet) ->
|
route_chan(Pid, Channel, Resource, Packet) ->
|
||||||
Pid ! {route, Channel, Resource, Packet}.
|
Pid ! {route_chan, Channel, Resource, Packet}.
|
||||||
|
|
||||||
|
route_nick(Pid, Nick, Packet) ->
|
||||||
|
Pid ! {route_nick, Nick, Packet}.
|
||||||
|
|
||||||
|
|
||||||
process_lines([S]) ->
|
process_lines([S]) ->
|
||||||
|
@ -409,17 +476,17 @@ process_channel_list(StateData, Items) ->
|
||||||
process_channel_list_find_chan(StateData, Items).
|
process_channel_list_find_chan(StateData, Items).
|
||||||
|
|
||||||
process_channel_list_find_chan(StateData, []) ->
|
process_channel_list_find_chan(StateData, []) ->
|
||||||
ok;
|
StateData;
|
||||||
process_channel_list_find_chan(StateData, [[$# | Chan] | Items]) ->
|
process_channel_list_find_chan(StateData, [[$# | Chan] | Items]) ->
|
||||||
process_channel_list_users(StateData, Chan, Items);
|
process_channel_list_users(StateData, Chan, Items);
|
||||||
process_channel_list_find_chan(StateData, [_ | Items]) ->
|
process_channel_list_find_chan(StateData, [_ | Items]) ->
|
||||||
process_channel_list_find_chan(StateData, Items).
|
process_channel_list_find_chan(StateData, Items).
|
||||||
|
|
||||||
process_channel_list_users(StateData, Chan, []) ->
|
process_channel_list_users(StateData, Chan, []) ->
|
||||||
ok;
|
StateData;
|
||||||
process_channel_list_users(StateData, Chan, [User | Items]) ->
|
process_channel_list_users(StateData, Chan, [User | Items]) ->
|
||||||
process_channel_list_user(StateData, Chan, User),
|
NewStateData = process_channel_list_user(StateData, Chan, User),
|
||||||
process_channel_list_users(StateData, Chan, Items).
|
process_channel_list_users(NewStateData, Chan, Items).
|
||||||
|
|
||||||
process_channel_list_user(StateData, Chan, User) ->
|
process_channel_list_user(StateData, Chan, User) ->
|
||||||
User1 = case User of
|
User1 = case User of
|
||||||
|
@ -439,13 +506,21 @@ process_channel_list_user(StateData, Chan, User) ->
|
||||||
[{xmlelement, "item",
|
[{xmlelement, "item",
|
||||||
[{"affiliation", Affiliation},
|
[{"affiliation", Affiliation},
|
||||||
{"role", Role}],
|
{"role", Role}],
|
||||||
[]}]}]}).
|
[]}]}]}),
|
||||||
|
case catch dict:update(Chan,
|
||||||
|
fun(Ps) ->
|
||||||
|
?SETS:add_element(User2, Ps)
|
||||||
|
end, StateData#state.channels) of
|
||||||
|
{'EXIT', _} ->
|
||||||
|
StateData;
|
||||||
|
NS ->
|
||||||
|
StateData#state{channels = NS}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
process_chanprivmsg(StateData, Chan, From, String) ->
|
process_chanprivmsg(StateData, Chan, From, String) ->
|
||||||
[FromUser | _] = string:tokens(From, "!"),
|
[FromUser | _] = string:tokens(From, "!"),
|
||||||
{ok, Msg, _} = regexp:sub(String, ".*PRIVMSG[^:]*:", ""),
|
{ok, Msg, _} = regexp:sub(String, ".*PRIVMSG[^:]*:", ""),
|
||||||
%Msg = lists:last(string:tokens(String, ":")),
|
|
||||||
Msg1 = case Msg of
|
Msg1 = case Msg of
|
||||||
[1, $A, $C, $T, $I, $O, $N, $ | Rest] ->
|
[1, $A, $C, $T, $I, $O, $N, $ | Rest] ->
|
||||||
"/me " ++ Rest;
|
"/me " ++ Rest;
|
||||||
|
@ -468,23 +543,44 @@ process_chanprivmsg(StateData, Chan, From, String) ->
|
||||||
{xmlelement, "message", [{"type", "groupchat"}],
|
{xmlelement, "message", [{"type", "groupchat"}],
|
||||||
[{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}).
|
[{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}).
|
||||||
|
|
||||||
|
process_privmsg(StateData, Nick, From, String) ->
|
||||||
|
[FromUser | _] = string:tokens(From, "!"),
|
||||||
|
{ok, Msg, _} = regexp:sub(String, ".*PRIVMSG[^:]*:", ""),
|
||||||
|
Msg1 = case Msg of
|
||||||
|
[1, $A, $C, $T, $I, $O, $N, $ | Rest] ->
|
||||||
|
"/me " ++ Rest;
|
||||||
|
_ ->
|
||||||
|
Msg
|
||||||
|
end,
|
||||||
|
Msg2 = lists:filter(
|
||||||
|
fun(C) ->
|
||||||
|
if (C < 32) and
|
||||||
|
(C /= 9) and
|
||||||
|
(C /= 10) and
|
||||||
|
(C /= 13) ->
|
||||||
|
false;
|
||||||
|
true -> true
|
||||||
|
end
|
||||||
|
end, Msg1),
|
||||||
|
ejabberd_router:route(
|
||||||
|
{lists:concat([FromUser, "!", StateData#state.server]),
|
||||||
|
StateData#state.myname, ""},
|
||||||
|
StateData#state.user,
|
||||||
|
{xmlelement, "message", [{"type", "chat"}],
|
||||||
|
[{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}).
|
||||||
|
|
||||||
process_version(StateData, Nick, From) ->
|
process_version(StateData, Nick, From) ->
|
||||||
case StateData#state.nick of
|
[FromUser | _] = string:tokens(From, "!"),
|
||||||
Nick ->
|
send_text(
|
||||||
[FromUser | _] = string:tokens(From, "!"),
|
StateData#state.socket,
|
||||||
send_text(
|
io_lib:format("NOTICE ~s :\001VERSION "
|
||||||
StateData#state.socket,
|
"ejabberd IRC transport ~s (c) Alexey Shchepin"
|
||||||
io_lib:format("NOTICE ~s :\001VERSION "
|
"\001\r\n",
|
||||||
"ejabberd IRC transport ~s (c) Alexey Shchepin"
|
[FromUser, ?VERSION]) ++
|
||||||
"\001\r\n",
|
io_lib:format("NOTICE ~s :\001VERSION "
|
||||||
[FromUser, ?VERSION]) ++
|
"http://www.jabber.ru/projects/ejabberd/"
|
||||||
io_lib:format("NOTICE ~s :\001VERSION "
|
"\001\r\n",
|
||||||
"http://www.jabber.ru/projects/ejabberd/"
|
[FromUser])).
|
||||||
"\001\r\n",
|
|
||||||
[FromUser]));
|
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
process_part(StateData, Chan, From, String) ->
|
process_part(StateData, Chan, From, String) ->
|
||||||
|
@ -498,7 +594,16 @@ process_part(StateData, Chan, From, String) ->
|
||||||
[{xmlelement, "item",
|
[{xmlelement, "item",
|
||||||
[{"affiliation", "member"},
|
[{"affiliation", "member"},
|
||||||
{"role", "none"}],
|
{"role", "none"}],
|
||||||
[]}]}]}).
|
[]}]}]}),
|
||||||
|
case catch dict:update(Chan,
|
||||||
|
fun(Ps) ->
|
||||||
|
remove_element(FromUser, Ps)
|
||||||
|
end, StateData#state.channels) of
|
||||||
|
{'EXIT', _} ->
|
||||||
|
StateData;
|
||||||
|
NS ->
|
||||||
|
StateData#state{channels = NS}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
process_join(StateData, Channel, From, String) ->
|
process_join(StateData, Channel, From, String) ->
|
||||||
|
@ -512,7 +617,17 @@ process_join(StateData, Channel, From, String) ->
|
||||||
[{xmlelement, "item",
|
[{xmlelement, "item",
|
||||||
[{"affiliation", "member"},
|
[{"affiliation", "member"},
|
||||||
{"role", "participant"}],
|
{"role", "participant"}],
|
||||||
[]}]}]}).
|
[]}]}]}),
|
||||||
|
case catch dict:update(Chan,
|
||||||
|
fun(Ps) ->
|
||||||
|
?SETS:add_element(FromUser, Ps)
|
||||||
|
end, StateData#state.channels) of
|
||||||
|
{'EXIT', _} ->
|
||||||
|
StateData;
|
||||||
|
NS ->
|
||||||
|
StateData#state{channels = NS}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
process_mode_o(StateData, Chan, From, Nick, Affiliation, Role) ->
|
process_mode_o(StateData, Chan, From, Nick, Affiliation, Role) ->
|
||||||
|
@ -541,6 +656,61 @@ process_kick(StateData, Chan, From, Nick) ->
|
||||||
{xmlelement, "status", [{"code", "307"}], []}
|
{xmlelement, "status", [{"code", "307"}], []}
|
||||||
]}]}).
|
]}]}).
|
||||||
|
|
||||||
|
process_nick(StateData, From, NewNick) ->
|
||||||
|
[FromUser | _] = string:tokens(From, "!"),
|
||||||
|
Nick = lists:subtract(NewNick, ":"),
|
||||||
|
NewChans =
|
||||||
|
dict:map(
|
||||||
|
fun(Chan, Ps) ->
|
||||||
|
case ?SETS:is_member(FromUser, Ps) of
|
||||||
|
true ->
|
||||||
|
ejabberd_router:route(
|
||||||
|
{lists:concat([Chan, "%", StateData#state.server]),
|
||||||
|
StateData#state.myname, FromUser},
|
||||||
|
StateData#state.user,
|
||||||
|
{xmlelement, "presence", [{"type", "unavailable"}],
|
||||||
|
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
|
||||||
|
[{xmlelement, "item",
|
||||||
|
[{"affiliation", "member"},
|
||||||
|
{"role", "participant"},
|
||||||
|
{"nick", Nick}],
|
||||||
|
[]},
|
||||||
|
{xmlelement, "status", [{"code", "303"}], []}
|
||||||
|
]}]}),
|
||||||
|
ejabberd_router:route(
|
||||||
|
{lists:concat([Chan, "%", StateData#state.server]),
|
||||||
|
StateData#state.myname, Nick},
|
||||||
|
StateData#state.user,
|
||||||
|
{xmlelement, "presence", [],
|
||||||
|
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
|
||||||
|
[{xmlelement, "item",
|
||||||
|
[{"affiliation", "member"},
|
||||||
|
{"role", "participant"}],
|
||||||
|
[]}
|
||||||
|
]}]}),
|
||||||
|
?SETS:add_element(Nick,
|
||||||
|
remove_element(FromUser, Ps));
|
||||||
|
_ ->
|
||||||
|
Ps
|
||||||
|
end
|
||||||
|
end, StateData#state.channels),
|
||||||
|
StateData#state{channels = NewChans}.
|
||||||
|
|
||||||
|
|
||||||
|
process_error(StateData, String) ->
|
||||||
|
lists:foreach(
|
||||||
|
fun(Chan) ->
|
||||||
|
ejabberd_router:route(
|
||||||
|
{lists:concat([Chan, "%", StateData#state.server]),
|
||||||
|
StateData#state.myname, StateData#state.nick},
|
||||||
|
StateData#state.user,
|
||||||
|
{xmlelement, "presence", [{"type", "error"}],
|
||||||
|
[{xmlelement, "error", [{"code", "502"}],
|
||||||
|
[{xmlcdata, String}]}]})
|
||||||
|
end, dict:fetch_keys(StateData#state.channels)).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
remove_element(E, Set) ->
|
remove_element(E, Set) ->
|
||||||
case ?SETS:is_element(E, Set) of
|
case ?SETS:is_element(E, Set) of
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue