summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexey Shchepin <alexey@process-one.net>2004-01-18 20:42:09 +0000
committerAlexey Shchepin <alexey@process-one.net>2004-01-18 20:42:09 +0000
commit273886701bd8d033330037ff7997b7bfe6e3f501 (patch)
treef727c495c2151325034594ebcb7ae8606478f064 /src
parent* src/mod_muc/mod_muc_room.erl: Bugfix, updated error codes (diff)
* 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
Diffstat (limited to '')
-rw-r--r--src/ejabberd_c2s.erl64
-rw-r--r--src/ejabberd_ctl.erl44
-rw-r--r--src/mod_offline.erl29
-rw-r--r--src/mod_roster.erl48
-rw-r--r--src/xml.erl10
5 files changed, 166 insertions, 29 deletions
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 09ab2a7b..44da28c0 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -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.
+
+
diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl
index 39141f3a..ea71f757 100644
--- a/src/ejabberd_ctl.erl
+++ b/src/ejabberd_ctl.erl
@@ -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"
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index fbd8dfbf..7af72442 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -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,
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index cbb6085a..836dbdba 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -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),
diff --git a/src/xml.erl b/src/xml.erl
index 9f047c82..e14f54c1 100644
--- a/src/xml.erl
+++ b/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}.
+
+