mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-02 15:27:09 +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>
|
||||
|
||||
* src/mod_muc/mod_muc_room.erl: Bugfix, updated error codes
|
||||
|
@ -54,7 +54,8 @@
|
||||
pres_last, pres_pri,
|
||||
pres_timestamp,
|
||||
pres_invis = false,
|
||||
privacy_list = none}).
|
||||
privacy_list = none,
|
||||
lang}).
|
||||
|
||||
%-define(DBGFSM, true).
|
||||
|
||||
@ -127,6 +128,7 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
case xml:get_attr_s("xmlns:stream", Attrs) of
|
||||
?NS_STREAM ->
|
||||
Lang = xml:get_attr_s("xml:lang", Attrs),
|
||||
case xml:get_attr_s("version", Attrs) of
|
||||
"1.0" ->
|
||||
Header = io_lib:format(?STREAM_HEADER,
|
||||
@ -149,7 +151,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
[{"xmlns", ?NS_SASL}],
|
||||
Mechs}]}),
|
||||
{next_state, wait_for_sasl_auth,
|
||||
StateData#state{sasl_state = SASLState}};
|
||||
StateData#state{sasl_state = SASLState,
|
||||
lang = Lang}};
|
||||
_ ->
|
||||
case StateData#state.resource of
|
||||
"" ->
|
||||
@ -158,12 +161,14 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
{xmlelement, "stream:features", [],
|
||||
[{xmlelement, "bind",
|
||||
[{"xmlns", ?NS_BIND}], []}]}),
|
||||
{next_state, wait_for_bind, StateData};
|
||||
{next_state, wait_for_bind,
|
||||
StateData#state{lang = Lang}};
|
||||
_ ->
|
||||
send_element(
|
||||
StateData,
|
||||
{xmlelement, "stream:features", [], []}),
|
||||
{next_state, wait_for_session, StateData}
|
||||
{next_state, wait_for_session,
|
||||
StateData#state{lang = Lang}}
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
@ -171,7 +176,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
?STREAM_HEADER,
|
||||
[StateData#state.streamid, ?MYNAME, ""]),
|
||||
send_text(StateData, Header),
|
||||
{next_state, wait_for_auth, StateData}
|
||||
{next_state, wait_for_auth, StateData#state{lang = Lang}}
|
||||
end;
|
||||
_ ->
|
||||
Header = io_lib:format(
|
||||
@ -541,9 +546,7 @@ session_established({xmlstreamelement, El}, StateData) ->
|
||||
{xmlelement, Name, Attrs, _Els} = El,
|
||||
User = StateData#state.user,
|
||||
Server = StateData#state.server,
|
||||
%FromJID = {User,
|
||||
% Server,
|
||||
% StateData#state.resource},
|
||||
% TODO: check 'from' attribute in stanza
|
||||
FromJID = StateData#state.jid,
|
||||
To = xml:get_attr_s("to", Attrs),
|
||||
ToJID = case To of
|
||||
@ -552,6 +555,16 @@ session_established({xmlstreamelement, El}, StateData) ->
|
||||
_ ->
|
||||
jlib:string_to_jid(To)
|
||||
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 =
|
||||
case ToJID of
|
||||
error ->
|
||||
@ -559,7 +572,7 @@ session_established({xmlstreamelement, El}, StateData) ->
|
||||
"error" -> 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),
|
||||
StateData
|
||||
end;
|
||||
@ -571,29 +584,29 @@ session_established({xmlstreamelement, El}, StateData) ->
|
||||
server = Server,
|
||||
resource = ""} ->
|
||||
?DEBUG("presence_update(~p,~n\t~p,~n\t~p)",
|
||||
[FromJID, El, StateData]),
|
||||
presence_update(FromJID, El, StateData);
|
||||
[FromJID, NewEl, StateData]),
|
||||
presence_update(FromJID, NewEl, StateData);
|
||||
_ ->
|
||||
presence_track(FromJID, ToJID, El, StateData)
|
||||
presence_track(FromJID, ToJID, NewEl, StateData)
|
||||
end;
|
||||
"iq" ->
|
||||
case StateData#state.privacy_list of
|
||||
none ->
|
||||
ejabberd_router:route(FromJID, ToJID, El),
|
||||
ejabberd_router:route(FromJID, ToJID, NewEl),
|
||||
StateData;
|
||||
_PrivList ->
|
||||
case jlib:iq_query_info(El) of
|
||||
case jlib:iq_query_info(NewEl) of
|
||||
#iq{xmlns = ?NS_PRIVACY} = IQ ->
|
||||
process_privacy_iq(
|
||||
FromJID, ToJID, IQ, StateData);
|
||||
_ ->
|
||||
ejabberd_router:route(
|
||||
FromJID, ToJID, El),
|
||||
FromJID, ToJID, NewEl),
|
||||
StateData
|
||||
end
|
||||
end;
|
||||
"message" ->
|
||||
ejabberd_router:route(FromJID, ToJID, El),
|
||||
ejabberd_router:route(FromJID, ToJID, NewEl),
|
||||
StateData;
|
||||
_ ->
|
||||
StateData
|
||||
@ -987,8 +1000,7 @@ presence_update(From, Packet, StateData) ->
|
||||
FromUnavail ->
|
||||
% TODO: watching ourself
|
||||
|
||||
catch mod_offline:resend_offline_messages(
|
||||
StateData#state.user),
|
||||
resend_offline_messages(StateData),
|
||||
presence_broadcast_first(
|
||||
From, StateData#state{pres_last = Packet,
|
||||
pres_invis = false
|
||||
@ -1271,3 +1283,19 @@ process_privacy_iq(From, To,
|
||||
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])
|
||||
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) ->
|
||||
print_usage().
|
||||
|
||||
@ -78,8 +115,11 @@ print_usage() ->
|
||||
"Available commands:~n"
|
||||
" stop\t\t\t\tstop ejabberd~n"
|
||||
" restart\t\t\trestart ejabberd~n"
|
||||
" register user password\tregister user~n"
|
||||
" unregister user\t\tunregister user~n"
|
||||
" register user password\tregister a 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"
|
||||
"Example:~n"
|
||||
" ejabberdctl ejabberd@host restart~n"
|
||||
|
@ -16,6 +16,7 @@
|
||||
stop/0,
|
||||
store_packet/3,
|
||||
resend_offline_messages/1,
|
||||
pop_offline_messages/1,
|
||||
remove_old_messages/1,
|
||||
remove_user/1]).
|
||||
|
||||
@ -129,7 +130,7 @@ find_x_event([El | Els]) ->
|
||||
resend_offline_messages(User) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
F = fun() ->
|
||||
Rs = mnesia:read({offline_msg, LUser}),
|
||||
Rs = mnesia:wread({offline_msg, LUser}),
|
||||
mnesia:delete({offline_msg, LUser}),
|
||||
Rs
|
||||
end,
|
||||
@ -153,6 +154,32 @@ resend_offline_messages(User) ->
|
||||
ok
|
||||
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) ->
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
S = MegaSecs * 1000000 + Secs - 60 * 60 * 24 * Days,
|
||||
|
@ -375,22 +375,45 @@ process_subscription(Direction, User, JID1, Type) ->
|
||||
Item#roster.ask,
|
||||
Type)
|
||||
end,
|
||||
AutoReply = case Direction of
|
||||
out ->
|
||||
none;
|
||||
in ->
|
||||
in_auto_reply(Item#roster.subscription,
|
||||
Item#roster.ask,
|
||||
Type)
|
||||
end,
|
||||
case NewState of
|
||||
none ->
|
||||
none;
|
||||
{none, AutoReply};
|
||||
{Subscription, Pending} ->
|
||||
NewItem = Item#roster{subscription = Subscription,
|
||||
ask = Pending},
|
||||
mnesia:write(NewItem),
|
||||
{push, NewItem}
|
||||
{{push, NewItem}, AutoReply}
|
||||
end
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, ok} ->
|
||||
false;
|
||||
{atomic, {push, Item}} ->
|
||||
push_item(User, {"", ?MYNAME, ""}, Item),
|
||||
true;
|
||||
{atomic, {Push, AutoReply}} ->
|
||||
case AutoReply of
|
||||
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),
|
||||
true;
|
||||
none ->
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
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, 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) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
|
10
src/xml.erl
10
src/xml.erl
@ -17,7 +17,8 @@
|
||||
get_attr/2, get_attr_s/2,
|
||||
get_tag_attr/2, get_tag_attr_s/2,
|
||||
get_subtag/2,
|
||||
get_path_s/2]).
|
||||
get_path_s/2,
|
||||
replace_tag_attr/3]).
|
||||
|
||||
element_to_string(El) ->
|
||||
case El of
|
||||
@ -190,3 +191,10 @@ get_path_s(El, [{attr, Name}]) ->
|
||||
get_path_s(El, [cdata]) ->
|
||||
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