25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-26 16:26:24 +01:00

* src/ejabberd_ctl.erl: Added commands for backup processing

* src/ejabberd_c2s.erl: Added processing of xml:lang according to
latest XMPP-IM draft

* src/xml.erl: Added replace_tag_attr/3 function

* src/mod_roster.erl: Added auto-reply on incoming subscription
request according to latest XMPP-IM draft

* src/mod_offline.erl: Added pop_offline_messages/1 function
* src/ejabberd_c2s.erl: Updated sending of offline messages

SVN Revision: 200
This commit is contained in:
Alexey Shchepin 2004-01-18 20:42:09 +00:00
parent 7a002470e6
commit 273886701b
6 changed files with 181 additions and 29 deletions

View File

@ -1,3 +1,18 @@
2004-01-18 Alexey Shchepin <alexey@sevcom.net>
* src/ejabberd_ctl.erl: Added commands for backup processing
* src/ejabberd_c2s.erl: Added processing of xml:lang according to
latest XMPP-IM draft
* src/xml.erl: Added replace_tag_attr/3 function
* src/mod_roster.erl: Added auto-reply on incoming subscription
request according to latest XMPP-IM draft
* src/mod_offline.erl: Added pop_offline_messages/1 function
* src/ejabberd_c2s.erl: Updated sending of offline messages
2004-01-17 Alexey Shchepin <alexey@sevcom.net> 2004-01-17 Alexey Shchepin <alexey@sevcom.net>
* src/mod_muc/mod_muc_room.erl: Bugfix, updated error codes * src/mod_muc/mod_muc_room.erl: Bugfix, updated error codes

View File

@ -54,7 +54,8 @@
pres_last, pres_pri, pres_last, pres_pri,
pres_timestamp, pres_timestamp,
pres_invis = false, pres_invis = false,
privacy_list = none}). privacy_list = none,
lang}).
%-define(DBGFSM, true). %-define(DBGFSM, true).
@ -127,6 +128,7 @@ init([{SockMod, Socket}, Opts]) ->
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
case xml:get_attr_s("xmlns:stream", Attrs) of case xml:get_attr_s("xmlns:stream", Attrs) of
?NS_STREAM -> ?NS_STREAM ->
Lang = xml:get_attr_s("xml:lang", Attrs),
case xml:get_attr_s("version", Attrs) of case xml:get_attr_s("version", Attrs) of
"1.0" -> "1.0" ->
Header = io_lib:format(?STREAM_HEADER, Header = io_lib:format(?STREAM_HEADER,
@ -149,7 +151,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
[{"xmlns", ?NS_SASL}], [{"xmlns", ?NS_SASL}],
Mechs}]}), Mechs}]}),
{next_state, wait_for_sasl_auth, {next_state, wait_for_sasl_auth,
StateData#state{sasl_state = SASLState}}; StateData#state{sasl_state = SASLState,
lang = Lang}};
_ -> _ ->
case StateData#state.resource of case StateData#state.resource of
"" -> "" ->
@ -158,12 +161,14 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
{xmlelement, "stream:features", [], {xmlelement, "stream:features", [],
[{xmlelement, "bind", [{xmlelement, "bind",
[{"xmlns", ?NS_BIND}], []}]}), [{"xmlns", ?NS_BIND}], []}]}),
{next_state, wait_for_bind, StateData}; {next_state, wait_for_bind,
StateData#state{lang = Lang}};
_ -> _ ->
send_element( send_element(
StateData, StateData,
{xmlelement, "stream:features", [], []}), {xmlelement, "stream:features", [], []}),
{next_state, wait_for_session, StateData} {next_state, wait_for_session,
StateData#state{lang = Lang}}
end end
end; end;
_ -> _ ->
@ -171,7 +176,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
?STREAM_HEADER, ?STREAM_HEADER,
[StateData#state.streamid, ?MYNAME, ""]), [StateData#state.streamid, ?MYNAME, ""]),
send_text(StateData, Header), send_text(StateData, Header),
{next_state, wait_for_auth, StateData} {next_state, wait_for_auth, StateData#state{lang = Lang}}
end; end;
_ -> _ ->
Header = io_lib:format( Header = io_lib:format(
@ -541,9 +546,7 @@ session_established({xmlstreamelement, El}, StateData) ->
{xmlelement, Name, Attrs, _Els} = El, {xmlelement, Name, Attrs, _Els} = El,
User = StateData#state.user, User = StateData#state.user,
Server = StateData#state.server, Server = StateData#state.server,
%FromJID = {User, % TODO: check 'from' attribute in stanza
% Server,
% StateData#state.resource},
FromJID = StateData#state.jid, FromJID = StateData#state.jid,
To = xml:get_attr_s("to", Attrs), To = xml:get_attr_s("to", Attrs),
ToJID = case To of ToJID = case To of
@ -552,6 +555,16 @@ session_established({xmlstreamelement, El}, StateData) ->
_ -> _ ->
jlib:string_to_jid(To) jlib:string_to_jid(To)
end, end,
NewEl = case xml:get_attr_s("xml:lang", Attrs) of
"" ->
case StateData#state.lang of
"" -> El;
Lang ->
xml:replace_tag_attr("xml:lang", Lang, El)
end;
_ ->
El
end,
NewState = NewState =
case ToJID of case ToJID of
error -> error ->
@ -559,7 +572,7 @@ session_established({xmlstreamelement, El}, StateData) ->
"error" -> StateData; "error" -> StateData;
"result" -> StateData; "result" -> StateData;
_ -> _ ->
Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED), Err = jlib:make_error_reply(NewEl, ?ERR_JID_MALFORMED),
send_element(StateData, Err), send_element(StateData, Err),
StateData StateData
end; end;
@ -571,29 +584,29 @@ session_established({xmlstreamelement, El}, StateData) ->
server = Server, server = Server,
resource = ""} -> resource = ""} ->
?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)",
[FromJID, El, StateData]), [FromJID, NewEl, StateData]),
presence_update(FromJID, El, StateData); presence_update(FromJID, NewEl, StateData);
_ -> _ ->
presence_track(FromJID, ToJID, El, StateData) presence_track(FromJID, ToJID, NewEl, StateData)
end; end;
"iq" -> "iq" ->
case StateData#state.privacy_list of case StateData#state.privacy_list of
none -> none ->
ejabberd_router:route(FromJID, ToJID, El), ejabberd_router:route(FromJID, ToJID, NewEl),
StateData; StateData;
_PrivList -> _PrivList ->
case jlib:iq_query_info(El) of case jlib:iq_query_info(NewEl) of
#iq{xmlns = ?NS_PRIVACY} = IQ -> #iq{xmlns = ?NS_PRIVACY} = IQ ->
process_privacy_iq( process_privacy_iq(
FromJID, ToJID, IQ, StateData); FromJID, ToJID, IQ, StateData);
_ -> _ ->
ejabberd_router:route( ejabberd_router:route(
FromJID, ToJID, El), FromJID, ToJID, NewEl),
StateData StateData
end end
end; end;
"message" -> "message" ->
ejabberd_router:route(FromJID, ToJID, El), ejabberd_router:route(FromJID, ToJID, NewEl),
StateData; StateData;
_ -> _ ->
StateData StateData
@ -987,8 +1000,7 @@ presence_update(From, Packet, StateData) ->
FromUnavail -> FromUnavail ->
% TODO: watching ourself % TODO: watching ourself
catch mod_offline:resend_offline_messages( resend_offline_messages(StateData),
StateData#state.user),
presence_broadcast_first( presence_broadcast_first(
From, StateData#state{pres_last = Packet, From, StateData#state{pres_last = Packet,
pres_invis = false pres_invis = false
@ -1271,3 +1283,19 @@ process_privacy_iq(From, To,
NewStateData. NewStateData.
resend_offline_messages(StateData) ->
case catch mod_offline:pop_offline_messages(StateData#state.user) of
{'EXIT', _Reason} ->
ok;
Rs when list(Rs) ->
lists:foreach(
fun({route, From, To, {xmlelement, Name, Attrs, Els}}) ->
Attrs2 = jlib:replace_from_to_attrs(
jlib:jid_to_string(From),
jlib:jid_to_string(To),
Attrs),
send_element(StateData, {xmlelement, Name, Attrs2, Els})
end, Rs)
end.

View File

@ -67,6 +67,43 @@ process(Node, ["unregister", User]) ->
[User, Node, Reason]) [User, Node, Reason])
end; end;
process(Node, ["backup", Path]) ->
case rpc:call(Node, mnesia, backup, [Path]) of
{atomic, ok} ->
ok;
{error, Reason} ->
io:format("Can't store backup in ~p on node ~p: ~p~n",
[Path, Node, Reason]);
{badrpc, Reason} ->
io:format("Can't store backup in ~p on node ~p: ~p~n",
[Path, Node, Reason])
end;
process(Node, ["restore", Path]) ->
case rpc:call(Node,
mnesia, restore, [Path, [{default_op, keep_tables}]]) of
{atomic, ok} ->
ok;
{error, Reason} ->
io:format("Can't restore backup from ~p on node ~p: ~p~n",
[Path, Node, Reason]);
{badrpc, Reason} ->
io:format("Can't restore backup from ~p on node ~p: ~p~n",
[Path, Node, Reason])
end;
process(Node, ["install-fallback", Path]) ->
case rpc:call(Node, mnesia, install_fallback, [Path]) of
{atomic, ok} ->
ok;
{error, Reason} ->
io:format("Can't install fallback from ~p on node ~p: ~p~n",
[Path, Node, Reason]);
{badrpc, Reason} ->
io:format("Can't install fallback from ~p on node ~p: ~p~n",
[Path, Node, Reason])
end;
process(_Node, _Args) -> process(_Node, _Args) ->
print_usage(). print_usage().
@ -78,8 +115,11 @@ print_usage() ->
"Available commands:~n" "Available commands:~n"
" stop\t\t\t\tstop ejabberd~n" " stop\t\t\t\tstop ejabberd~n"
" restart\t\t\trestart ejabberd~n" " restart\t\t\trestart ejabberd~n"
" register user password\tregister user~n" " register user password\tregister a user~n"
" unregister user\t\tunregister user~n" " unregister user\t\tunregister a user~n"
" backup file\t\t\tstore a backup in file~n"
" restore file\t\t\trestore a backup from file~n"
" install-fallback file\t\tinstall a fallback from file~n"
"~n" "~n"
"Example:~n" "Example:~n"
" ejabberdctl ejabberd@host restart~n" " ejabberdctl ejabberd@host restart~n"

View File

@ -16,6 +16,7 @@
stop/0, stop/0,
store_packet/3, store_packet/3,
resend_offline_messages/1, resend_offline_messages/1,
pop_offline_messages/1,
remove_old_messages/1, remove_old_messages/1,
remove_user/1]). remove_user/1]).
@ -129,7 +130,7 @@ find_x_event([El | Els]) ->
resend_offline_messages(User) -> resend_offline_messages(User) ->
LUser = jlib:nodeprep(User), LUser = jlib:nodeprep(User),
F = fun() -> F = fun() ->
Rs = mnesia:read({offline_msg, LUser}), Rs = mnesia:wread({offline_msg, LUser}),
mnesia:delete({offline_msg, LUser}), mnesia:delete({offline_msg, LUser}),
Rs Rs
end, end,
@ -153,6 +154,32 @@ resend_offline_messages(User) ->
ok ok
end. end.
pop_offline_messages(User) ->
LUser = jlib:nodeprep(User),
F = fun() ->
Rs = mnesia:wread({offline_msg, LUser}),
mnesia:delete({offline_msg, LUser}),
Rs
end,
case mnesia:transaction(F) of
{atomic, Rs} ->
lists:map(
fun(R) ->
{xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
{route,
R#offline_msg.from,
R#offline_msg.to,
{xmlelement, Name, Attrs,
Els ++
[jlib:timestamp_to_xml(
calendar:now_to_universal_time(
R#offline_msg.timestamp))]}}
end,
lists:keysort(#offline_msg.timestamp, Rs));
_ ->
[]
end.
remove_old_messages(Days) -> remove_old_messages(Days) ->
{MegaSecs, Secs, _MicroSecs} = now(), {MegaSecs, Secs, _MicroSecs} = now(),
S = MegaSecs * 1000000 + Secs - 60 * 60 * 24 * Days, S = MegaSecs * 1000000 + Secs - 60 * 60 * 24 * Days,

View File

@ -375,22 +375,45 @@ process_subscription(Direction, User, JID1, Type) ->
Item#roster.ask, Item#roster.ask,
Type) Type)
end, end,
AutoReply = case Direction of
out ->
none;
in ->
in_auto_reply(Item#roster.subscription,
Item#roster.ask,
Type)
end,
case NewState of case NewState of
none -> none ->
none; {none, AutoReply};
{Subscription, Pending} -> {Subscription, Pending} ->
NewItem = Item#roster{subscription = Subscription, NewItem = Item#roster{subscription = Subscription,
ask = Pending}, ask = Pending},
mnesia:write(NewItem), mnesia:write(NewItem),
{push, NewItem} {{push, NewItem}, AutoReply}
end end
end, end,
case mnesia:transaction(F) of case mnesia:transaction(F) of
{atomic, ok} -> {atomic, {Push, AutoReply}} ->
false; case AutoReply of
{atomic, {push, Item}} -> none ->
ok;
_ ->
T = case AutoReply of
subscribed -> "subscribed";
unsubscribed -> "unsubscribed"
end,
ejabberd_router:route(
{User, ?MYNAME, ""}, JID1,
{xmlelement, "presence", [{"type", T}], []})
end,
case Push of
{push, Item} ->
push_item(User, {"", ?MYNAME, ""}, Item), push_item(User, {"", ?MYNAME, ""}, Item),
true; true;
none ->
false
end;
_ -> _ ->
false false
end. end.
@ -474,6 +497,17 @@ out_state_change(both, none, subscribed) -> none;
out_state_change(both, none, unsubscribe) -> {from, none}; out_state_change(both, none, unsubscribe) -> {from, none};
out_state_change(both, none, unsubscribed) -> {to, none}. out_state_change(both, none, unsubscribed) -> {to, none}.
in_auto_reply(from, none, subscribe) -> subscribed;
in_auto_reply(from, out, subscribe) -> subscribed;
in_auto_reply(both, none, subscribe) -> subscribed;
in_auto_reply(none, in, unsubscribe) -> unsubscribed;
in_auto_reply(none, both, unsubscribe) -> unsubscribed;
in_auto_reply(to, in, unsubscribe) -> unsubscribed;
in_auto_reply(from, none, unsubscribe) -> unsubscribed;
in_auto_reply(from, out, unsubscribe) -> unsubscribed;
in_auto_reply(both, none, unsubscribe) -> unsubscribed;
in_auto_reply(_, _, _) -> none.
remove_user(User) -> remove_user(User) ->
LUser = jlib:nodeprep(User), LUser = jlib:nodeprep(User),

View File

@ -17,7 +17,8 @@
get_attr/2, get_attr_s/2, get_attr/2, get_attr_s/2,
get_tag_attr/2, get_tag_attr_s/2, get_tag_attr/2, get_tag_attr_s/2,
get_subtag/2, get_subtag/2,
get_path_s/2]). get_path_s/2,
replace_tag_attr/3]).
element_to_string(El) -> element_to_string(El) ->
case El of case El of
@ -190,3 +191,10 @@ get_path_s(El, [{attr, Name}]) ->
get_path_s(El, [cdata]) -> get_path_s(El, [cdata]) ->
get_tag_cdata(El). get_tag_cdata(El).
replace_tag_attr(Attr, Value, {xmlelement, Name, Attrs, Els}) ->
Attrs1 = lists:keydelete(Attr, 1, Attrs),
Attrs2 = [{Attr, Value} | Attrs1],
{xmlelement, Name, Attrs2, Els}.