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:
parent
7a002470e6
commit
273886701b
15
ChangeLog
15
ChangeLog
@ -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
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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,
|
||||||
|
@ -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),
|
||||||
|
10
src/xml.erl
10
src/xml.erl
@ -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}.
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user