aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ejabberd_auth.erl12
-rw-r--r--src/ejabberd_auth_internal.erl15
-rw-r--r--src/ejabberd_odbc.erl3
-rw-r--r--src/ejd2odbc.erl161
-rw-r--r--src/mod_announce.erl22
-rw-r--r--src/mod_irc.erl18
-rw-r--r--src/mod_last.erl16
-rw-r--r--src/mod_muc.erl64
-rw-r--r--src/mod_offline.erl60
-rw-r--r--src/mod_privacy.erl43
-rw-r--r--src/mod_private.erl17
-rw-r--r--src/mod_roster.erl30
-rw-r--r--src/mod_shared_roster.erl23
-rw-r--r--src/mod_vcard.erl38
-rw-r--r--src/mod_vcard_xupdate.erl13
-rw-r--r--src/odbc_queries.erl11
16 files changed, 510 insertions, 36 deletions
diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl
index a82c343e4..7cc40ae1e 100644
--- a/src/ejabberd_auth.erl
+++ b/src/ejabberd_auth.erl
@@ -35,8 +35,8 @@
check_password/5, check_password_with_authmodule/3,
check_password_with_authmodule/5, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2, export/1,
- get_vh_registered_users_number/1,
+ get_vh_registered_users/2, export/1, import/1,
+ get_vh_registered_users_number/1, import/3,
get_vh_registered_users_number/2, get_password/2,
get_password_s/2, get_password_with_authmodule/2,
is_user_exists/2, is_user_exists_in_other_modules/3,
@@ -437,3 +437,11 @@ auth_modules(Server) ->
export(Server) ->
ejabberd_auth_internal:export(Server).
+
+import(Server) ->
+ ejabberd_auth_internal:import(Server).
+
+import(Server, mnesia, Passwd) ->
+ ejabberd_auth_internal:import(Server, mnesia, Passwd);
+import(_, _, _) ->
+ pass.
diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl
index f66b09c88..5a6c1b10a 100644
--- a/src/ejabberd_auth_internal.erl
+++ b/src/ejabberd_auth_internal.erl
@@ -38,8 +38,8 @@
get_vh_registered_users_number/1,
get_vh_registered_users_number/2, get_password/2,
get_password_s/2, is_user_exists/2, remove_user/2,
- remove_user/3, store_type/0, export/1,
- plain_password_required/0]).
+ remove_user/3, store_type/0, export/1, import/1,
+ import/3, plain_password_required/0]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -474,3 +474,14 @@ export(_Server) ->
(_Host, _R) ->
[]
end}].
+
+import(LServer) ->
+ [{<<"select username, password from users;">>,
+ fun([LUser, Password]) ->
+ #passwd{us = {LUser, LServer}, password = Password}
+ end}].
+
+import(_LServer, mnesia, #passwd{} = P) ->
+ mnesia:dirty_write(P);
+import(_, _, _) ->
+ pass.
diff --git a/src/ejabberd_odbc.erl b/src/ejabberd_odbc.erl
index b530f8f29..937805579 100644
--- a/src/ejabberd_odbc.erl
+++ b/src/ejabberd_odbc.erl
@@ -515,6 +515,9 @@ pgsql_to_odbc({ok, PGSQLResult}) ->
pgsql_item_to_odbc({<<"SELECT", _/binary>>, Rows,
Recs}) ->
{selected, [element(1, Row) || Row <- Rows], Recs};
+pgsql_item_to_odbc({<<"FETCH", _/binary>>, Rows,
+ Recs}) ->
+ {selected, [element(1, Row) || Row <- Rows], Recs};
pgsql_item_to_odbc(<<"INSERT ", OIDN/binary>>) ->
[_OID, N] = str:tokens(OIDN, <<" ">>),
{updated, jlib:binary_to_integer(N)};
diff --git a/src/ejd2odbc.erl b/src/ejd2odbc.erl
index b96503dbe..8777a7597 100644
--- a/src/ejd2odbc.erl
+++ b/src/ejd2odbc.erl
@@ -28,10 +28,14 @@
-author('alexey@process-one.net').
--export([export/2, export/3]).
+-include("logger.hrl").
+
+-export([export/2, export/3, import_file/2, import/2, import/3]).
-define(MAX_RECORDS_PER_TRANSACTION, 100).
+-record(dump, {fd, cont = start}).
+
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
@@ -42,21 +46,24 @@
%%% - Output can be either odbc to export to the configured relational
%%% database or "Filename" to export to text file.
+modules() ->
+ [ejabberd_auth,
+ mod_announce,
+ mod_caps,
+ mod_irc,
+ mod_last,
+ mod_muc,
+ mod_offline,
+ mod_privacy,
+ mod_private,
+ mod_roster,
+ mod_shared_roster,
+ mod_vcard,
+ mod_vcard_xupdate].
+
export(Server, Output) ->
LServer = jlib:nameprep(iolist_to_binary(Server)),
- Modules = [ejabberd_auth,
- mod_announce,
- mod_caps,
- mod_irc,
- mod_last,
- mod_muc,
- mod_offline,
- mod_privacy,
- mod_private,
- mod_roster,
- mod_shared_roster,
- mod_vcard,
- mod_vcard_xupdate],
+ Modules = modules(),
IO = prepare_output(Output),
lists:foreach(
fun(Module) ->
@@ -73,6 +80,47 @@ export(Server, Output, Module) ->
end, Module:export(Server)),
close_output(Output, IO).
+import_file(Server, FileName) when is_binary(FileName) ->
+ import(Server, binary_to_list(FileName));
+import_file(Server, FileName) ->
+ case disk_log:open([{name, make_ref()},
+ {file, FileName},
+ {mode, read_only}]) of
+ {ok, Fd} ->
+ LServer = jlib:nameprep(Server),
+ Mods = [{Mod, gen_mod:db_type(LServer, Mod)}
+ || Mod <- modules(), gen_mod:is_loaded(LServer, Mod)],
+ AuthMods = case lists:member(ejabberd_auth_internal,
+ ejabberd_auth:auth_modules(LServer)) of
+ true ->
+ [{ejabberd_auth, mnesia}];
+ false ->
+ []
+ end,
+ import_dump(LServer, AuthMods ++ Mods, #dump{fd = Fd});
+ Err ->
+ exit(Err)
+ end.
+
+import(Server, Output) ->
+ LServer = jlib:nameprep(iolist_to_binary(Server)),
+ Modules = modules(),
+ IO = prepare_output(Output, disk_log),
+ lists:foreach(
+ fun(Module) ->
+ import(LServer, IO, Module)
+ end, Modules),
+ close_output(Output, IO).
+
+import(Server, Output, Module) ->
+ LServer = jlib:nameprep(iolist_to_binary(Server)),
+ IO = prepare_output(Output, disk_log),
+ lists:foreach(
+ fun({SelectQuery, ConvertFun}) ->
+ import(LServer, SelectQuery, IO, ConvertFun)
+ end, Module:import(Server)),
+ close_output(Output, IO).
+
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
@@ -109,18 +157,97 @@ output(_LServer, Table, Fd, SQLs) ->
file:write(Fd, ["-- \n-- Mnesia table: ", atom_to_list(Table),
"\n--\n", SQLs]).
-prepare_output(FileName) when is_list(FileName); is_binary(FileName) ->
+import(LServer, SelectQuery, IO, ConvertFun) ->
+ F = fun() ->
+ ejabberd_odbc:sql_query_t(
+ iolist_to_binary(
+ [<<"declare c cursor for ">>, SelectQuery])),
+ fetch(IO, ConvertFun)
+ end,
+ ejabberd_odbc:sql_transaction(LServer, F).
+
+fetch(IO, ConvertFun) ->
+ fetch(IO, ConvertFun, undefined).
+
+fetch(IO, ConvertFun, PrevRow) ->
+ case ejabberd_odbc:sql_query_t([<<"fetch c;">>]) of
+ {selected, _, [Row]} when Row == PrevRow ->
+ %% Avoid calling ConvertFun with the same input
+ fetch(IO, ConvertFun, Row);
+ {selected, _, [Row]} ->
+ case catch ConvertFun(Row) of
+ {'EXIT', _} = Err ->
+ ?ERROR_MSG("failed to convert ~p: ~p",
+ [Row, Err]);
+ Term ->
+ ok = disk_log:log(IO#dump.fd, Term)
+ end,
+ fetch(IO, ConvertFun, Row);
+ {selected, _, []} ->
+ ok;
+ Err ->
+ erlang:error(Err)
+ end.
+
+import_dump(LServer, Mods, #dump{fd = Fd, cont = Cont}) ->
+ case disk_log:chunk(Fd, Cont) of
+ {NewCont, Terms} ->
+ import_terms(LServer, Mods, Terms),
+ import_dump(LServer, Mods, #dump{fd = Fd, cont = NewCont});
+ eof ->
+ ok;
+ Err ->
+ exit(Err)
+ end.
+
+import_terms(LServer, Mods, [Term|Terms]) ->
+ import_term(LServer, Mods, Term),
+ import_terms(LServer, Mods, Terms);
+import_terms(_LServer, _Mods, []) ->
+ ok.
+
+import_term(LServer, [{Mod, DBType}|Mods], Term) ->
+ case catch Mod:import(LServer, DBType, Term) of
+ pass -> import_term(LServer, Mods, Term);
+ ok -> ok;
+ Err ->
+ ?ERROR_MSG("failed to import ~p for module ~p: ~p",
+ [Term, Mod, Err])
+ end;
+import_term(_LServer, [], _Term) ->
+ ok.
+
+prepare_output(FileName) ->
+ prepare_output(FileName, normal).
+
+prepare_output(FileName, Type) when is_binary(FileName) ->
+ prepare_output(binary_to_list(FileName), Type);
+prepare_output(FileName, normal) when is_list(FileName) ->
case file:open(FileName, [write, raw]) of
{ok, Fd} ->
Fd;
Err ->
exit(Err)
end;
-prepare_output(Output) ->
+prepare_output(FileName, disk_log) when is_list(FileName) ->
+ case disk_log:open([{name, make_ref()},
+ {repair, truncate},
+ {file, FileName}]) of
+ {ok, Fd} ->
+ #dump{fd = Fd};
+ Err ->
+ exit(Err)
+ end;
+prepare_output(Output, _Type) ->
Output.
close_output(FileName, Fd) when FileName /= Fd ->
- file:close(Fd),
+ case Fd of
+ #dump{} ->
+ disk_log:close(Fd#dump.fd);
+ _ ->
+ file:close(Fd)
+ end,
ok;
close_output(_, _) ->
ok.
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index 8d72b4bf7..b558897a0 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -35,7 +35,9 @@
-export([start/2,
init/0,
stop/1,
- export/1,
+ export/1,
+ import/1,
+ import/3,
announce/3,
send_motd/1,
disco_identity/5,
@@ -1072,3 +1074,21 @@ export(_Server) ->
(_Host, _R) ->
[]
end}].
+
+import(LServer) ->
+ [{<<"select xml from motd where username='';">>,
+ fun([XML]) ->
+ El = xml_stream:parse_element(XML),
+ #motd{server = LServer, packet = El}
+ end},
+ {<<"select username from motd where xml='';">>,
+ fun([LUser]) ->
+ #motd_users{us = {LUser, LServer}}
+ end}].
+
+import(_LServer, mnesia, #motd{} = Motd) ->
+ mnesia:dirty_write(Motd);
+import(_LServer, mnesia, #motd_users{} = Users) ->
+ mnesia:dirty_write(Users);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_irc.erl b/src/mod_irc.erl
index 9d9246fad..3aa57002f 100644
--- a/src/mod_irc.erl
+++ b/src/mod_irc.erl
@@ -33,8 +33,8 @@
-behaviour(gen_mod).
%% API
--export([start_link/2, start/2, stop/1, export/1,
- closed_connection/3, get_connection_params/3]).
+-export([start_link/2, start/2, stop/1, export/1, import/1,
+ import/3, closed_connection/3, get_connection_params/3]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2,
@@ -1288,3 +1288,17 @@ export(_Server) ->
[]
end
end}].
+
+import(_LServer) ->
+ [{<<"select jid, host, data from irc_custom;">>,
+ fun([SJID, IRCHost, SData]) ->
+ #jid{luser = U, lserver = S} = jlib:string_to_jid(SJID),
+ Data = ejabberd_odbc:decode_term(SData),
+ #irc_custom{us_host = {{U, S}, IRCHost},
+ data = Data}
+ end}].
+
+import(_LServer, mnesia, #irc_custom{} = R) ->
+ mnesia:dirty_write(R);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_last.erl b/src/mod_last.erl
index 28fcda63a..3ea86b350 100644
--- a/src/mod_last.erl
+++ b/src/mod_last.erl
@@ -31,7 +31,7 @@
-behaviour(gen_mod).
-export([start/2, stop/1, process_local_iq/3, export/1,
- process_sm_iq/3, on_presence_update/4,
+ process_sm_iq/3, on_presence_update/4, import/1, import/3,
store_last_info/4, get_last_info/2, remove_user/2]).
-include("ejabberd.hrl").
@@ -305,3 +305,17 @@ export(_Server) ->
(_Host, _R) ->
[]
end}].
+
+import(LServer) ->
+ [{<<"select username, seconds, state from last">>,
+ fun([LUser, TimeStamp, State]) ->
+ #last_activity{us = {LUser, LServer},
+ timestamp = jlib:binary_to_integer(
+ TimeStamp),
+ status = State}
+ end}].
+
+import(_LServer, mnesia, #last_activity{} = LA) ->
+ mnesia:dirty_write(LA);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_muc.erl b/src/mod_muc.erl
index 6b87f1579..cfed60a3c 100644
--- a/src/mod_muc.erl
+++ b/src/mod_muc.erl
@@ -44,6 +44,9 @@
shutdown_rooms/1,
process_iq_disco_items/4,
broadcast_service_message/2,
+ export/1,
+ import/1,
+ import/3,
can_use_nick/4]).
%% gen_server callbacks
@@ -1141,3 +1144,64 @@ update_muc_registered_table(_Host) ->
?INFO_MSG("Recreating muc_registered table", []),
mnesia:transform_table(muc_registered, ignore, Fields)
end.
+
+export(_Server) ->
+ [{muc_room,
+ fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) ->
+ case str:suffix(Host, RoomHost) of
+ true ->
+ SName = ejabberd_odbc:escape(Name),
+ SRoomHost = ejabberd_odbc:escape(RoomHost),
+ SOpts = ejabberd_odbc:encode_term(Opts),
+ [[<<"delete from muc_room where name='">>, SName,
+ <<"' and host='">>, SRoomHost, <<"';">>],
+ [<<"insert into muc_room(name, host, opts) ",
+ "values (">>,
+ <<"'">>, SName, <<"', '">>, SRoomHost,
+ <<"', '">>, SOpts, <<"');">>]];
+ false ->
+ []
+ end
+ end},
+ {muc_registered,
+ fun(Host, #muc_registered{us_host = {{U, S}, RoomHost},
+ nick = Nick}) ->
+ case str:suffix(Host, RoomHost) of
+ true ->
+ SJID = ejabberd_odbc:escape(
+ jlib:jid_to_string(
+ jlib:make_jid(U, S, <<"">>))),
+ SNick = ejabberd_odbc:escape(Nick),
+ SRoomHost = ejabberd_odbc:escape(RoomHost),
+ [[<<"delete from muc_registered where jid='">>,
+ SJID, <<"' and host='">>, SRoomHost, <<"';">>],
+ [<<"insert into muc_registered(jid, host, "
+ "nick) values ('">>,
+ SJID, <<"', '">>, SRoomHost, <<"', '">>, SNick,
+ <<"');">>]];
+ false ->
+ []
+ end
+ end}].
+
+import(_LServer) ->
+ [{<<"select name, host, opts from muc_room;">>,
+ fun([Name, RoomHost, SOpts]) ->
+ Opts = opts_to_binary(ejabberd_odbc:decode_term(SOpts)),
+ #muc_room{name_host = {Name, RoomHost},
+ opts = Opts}
+ end},
+ {<<"select jid, host, nick from muc_registered;">>,
+ fun([J, RoomHost, Nick]) ->
+ #jid{user = U, server = S} =
+ jlib:string_to_jid(J),
+ #muc_registered{us_host = {{U, S}, RoomHost},
+ nick = Nick}
+ end}].
+
+import(_LServer, mnesia, #muc_room{} = R) ->
+ mnesia:dirty_write(R);
+import(_LServer, mnesia, #muc_registered{} = R) ->
+ mnesia:dirty_write(R);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 503317485..10ee7b409 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -42,6 +42,9 @@
remove_expired_messages/1,
remove_old_messages/2,
remove_user/2,
+ import/1,
+ import/3,
+ export/1,
get_queue_length/2,
get_offline_els/2,
webadmin_page/3,
@@ -873,3 +876,60 @@ count_offline_messages(LUser, LServer) ->
_ ->
0
end.
+
+export(_Server) ->
+ [{offline_msg,
+ fun(Host, #offline_msg{us = {LUser, LServer},
+ timestamp = TimeStamp, from = From, to = To,
+ packet = Packet})
+ when LServer == Host ->
+ Username = ejabberd_odbc:escape(LUser),
+ #xmlel{name = Name, attrs = Attrs, children = Els} =
+ Packet,
+ Attrs2 =
+ jlib:replace_from_to_attrs(jlib:jid_to_string(From),
+ jlib:jid_to_string(To),
+ Attrs),
+ NewPacket = #xmlel{name = Name, attrs = Attrs2,
+ children =
+ Els ++
+ [jlib:timestamp_to_xml(
+ calendar:now_to_universal_time(TimeStamp),
+ utc,
+ jlib:make_jid(<<"">>,
+ LServer,
+ <<"">>),
+ <<"Offline Storage">>),
+ jlib:timestamp_to_xml(
+ calendar:now_to_universal_time(TimeStamp))]},
+ XML =
+ ejabberd_odbc:escape(xml:element_to_binary(NewPacket)),
+ [[<<"delete from spool where username='">>, Username, <<"';">>],
+ [<<"insert into spool(username, xml) values ('">>,
+ Username, <<"', '">>, XML, <<"');">>]];
+ (_Host, _R) ->
+ []
+ end}].
+
+import(LServer) ->
+ [{<<"select username, xml from spool;">>,
+ fun([LUser, XML]) ->
+ El = #xmlel{} = xml_stream:parse_element(XML),
+ From = #jid{} = jlib:string_to_jid(
+ xml:get_attr_s(<<"from">>, El)),
+ To = #jid{} = jlib:string_to_jid(
+ xml:get_attr_s(<<"to">>, El)),
+ Stamp = xml:get_path_s(El, [{elem, <<"delay">>},
+ {elem, <<"stamp">>},
+ cdata]),
+ {_, _, _} = TS = jlib:datetime_string_to_timestamp(Stamp),
+ Expire = find_x_expire(TS, El#xmlel.children),
+ #offline_msg{us = {LUser, LServer},
+ from = From, to = To,
+ timestamp = TS, expire = Expire}
+ end}].
+
+import(_LServer, mnesia, #offline_msg{} = Msg) ->
+ mnesia:dirty_write(Msg);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl
index ab77a30d3..5edfccd28 100644
--- a/src/mod_privacy.erl
+++ b/src/mod_privacy.erl
@@ -30,11 +30,11 @@
-behaviour(gen_mod).
--export([start/2, stop/1, process_iq/3, export/1,
+-export([start/2, stop/1, process_iq/3, export/1, import/1,
process_iq_set/4, process_iq_get/5, get_user_list/3,
check_packet/6, remove_user/2, item_to_raw/1,
raw_to_item/1, is_list_needdb/1, updated_list/3,
- item_to_xml/1, get_user_lists/2]).
+ item_to_xml/1, get_user_lists/2, import/3]).
%% For mod_blocking
-export([sql_add_privacy_list/2,
@@ -965,6 +965,11 @@ sql_get_privacy_list_data(LUser, LServer, Name) ->
odbc_queries:get_privacy_list_data(LServer, Username,
SName).
+sql_get_privacy_list_data_t(LUser, Name) ->
+ Username = ejabberd_odbc:escape(LUser),
+ SName = ejabberd_odbc:escape(Name),
+ odbc_queries:get_privacy_list_data_t(Username, SName).
+
sql_get_privacy_list_data_by_id(ID, LServer) ->
odbc_queries:get_privacy_list_data_by_id(LServer, ID).
@@ -1098,3 +1103,37 @@ get_id() ->
ID = get(id),
put(id, ID + 1),
ID + 1.
+
+import(LServer) ->
+ [{<<"select username from privacy_list;">>,
+ fun([LUser]) ->
+ Default = case sql_get_default_privacy_list_t(LUser) of
+ {selected, [<<"name">>], []} ->
+ none;
+ {selected, [<<"name">>], [[DefName]]} ->
+ DefName;
+ _ ->
+ none
+ end,
+ {selected, [<<"name">>], Names} =
+ sql_get_privacy_list_names_t(LUser),
+ Lists = lists:flatmap(
+ fun([Name]) ->
+ case sql_get_privacy_list_data_t(LUser, Name) of
+ {selected, _, RItems} ->
+ [{Name,
+ lists:map(fun raw_to_item/1,
+ RItems)}];
+ _ ->
+ []
+ end
+ end, Names),
+ #privacy{default = Default,
+ us = {LUser, LServer},
+ lists = Lists}
+ end}].
+
+import(_LServer, mnesia, #privacy{} = P) ->
+ mnesia:dirty_write(P);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_private.erl b/src/mod_private.erl
index 19e1e038e..ae7068480 100644
--- a/src/mod_private.erl
+++ b/src/mod_private.erl
@@ -30,8 +30,8 @@
-behaviour(gen_mod).
--export([start/2, stop/1, process_sm_iq/3,
- remove_user/2, get_data/2, export/1]).
+-export([start/2, stop/1, process_sm_iq/3, import/3,
+ remove_user/2, get_data/2, export/1, import/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -277,3 +277,16 @@ export(_Server) ->
(_Host, _R) ->
[]
end}].
+
+import(LServer) ->
+ [{<<"select username, namespace, data from private_storage;">>,
+ fun([LUser, XMLNS, XML]) ->
+ El = #xmlel{} = xml_stream:parse_element(XML),
+ #private_storage{usns = {LUser, LServer, XMLNS},
+ xml = El}
+ end}].
+
+import(_LServer, mnesia, #private_storage{} = PS) ->
+ mnesia:dirty_write(PS);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index 1ab618a43..e04822915 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -39,8 +39,8 @@
-behaviour(gen_mod).
--export([start/2, stop/1, process_iq/3, export/1,
- process_local_iq/3, get_user_roster/2,
+-export([start/2, stop/1, process_iq/3, export/1, import/1,
+ process_local_iq/3, get_user_roster/2, import/3,
get_subscription_lists/3, get_roster/2,
get_in_pending_subscriptions/3, in_subscription/6,
out_subscription/4, set_items/3, remove_user/2,
@@ -1569,3 +1569,29 @@ export(_Server) ->
(_Host, _R) ->
[]
end}].
+
+import(LServer) ->
+ [{<<"select username, jid, nick, subscription, "
+ "ask, askmessage, server, subscribe, type from rosterusers;">>,
+ fun([LUser, JID|_] = Row) ->
+ Item = raw_to_record(LServer, Row),
+ Username = ejabberd_odbc:escape(LUser),
+ SJID = ejabberd_odbc:escape(JID),
+ {selected, _, Rows} =
+ ejabberd_odbc:sql_query_t(
+ [<<"select grp from rostergroups where username='">>,
+ Username, <<"' and jid='">>, SJID, <<"'">>]),
+ Groups = [Grp || [Grp] <- Rows],
+ Item#roster{groups = Groups}
+ end},
+ {<<"select username, version from roster_version;">>,
+ fun([LUser, Ver]) ->
+ #roster_version{us = {LUser, LServer}, version = Ver}
+ end}].
+
+import(_LServer, mnesia, #roster{} = R) ->
+ mnesia:dirty_write(R);
+import(_LServer, mnesia, #roster_version{} = RV) ->
+ mnesia:dirty_write(RV);
+import(_, _, _) ->
+ ok.
diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl
index 2501ef2b5..743b1dd62 100644
--- a/src/mod_shared_roster.erl
+++ b/src/mod_shared_roster.erl
@@ -30,9 +30,9 @@
-behaviour(gen_mod).
--export([start/2, stop/1, item_to_xml/1, export/1,
+-export([start/2, stop/1, item_to_xml/1, export/1, import/1,
webadmin_menu/3, webadmin_page/3, get_user_roster/2,
- get_subscription_lists/3, get_jid_info/4,
+ get_subscription_lists/3, get_jid_info/4, import/3,
process_item/2, in_subscription/6, out_subscription/4,
user_available/1, unset_presence/4, register_user/2,
remove_user/2, list_groups/1, create_group/2,
@@ -1334,3 +1334,22 @@ export(_Server) ->
(_Host, _R) ->
[]
end}].
+
+import(LServer) ->
+ [{<<"select name, opts from sr_group;">>,
+ fun([Group, SOpts]) ->
+ #sr_group{group_host = {Group, LServer},
+ opts = ejabberd_odbc:decode_term(SOpts)}
+ end},
+ {<<"select jid, grp from sr_user;">>,
+ fun([SJID, Group]) ->
+ #jid{luser = U, lserver = S} = jlib:string_to_jid(SJID),
+ #sr_user{us = {U, S}, group_host = {Group, LServer}}
+ end}].
+
+import(_LServer, mnesia, #sr_group{} = G) ->
+ mnesia:dirty_write(G);
+import(_LServer, mnesia, #sr_user{} = U) ->
+ mnesia:dirty_write(U);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
index fa657df5d..08feb071a 100644
--- a/src/mod_vcard.erl
+++ b/src/mod_vcard.erl
@@ -32,7 +32,7 @@
-export([start/2, init/3, stop/1, get_sm_features/5,
process_local_iq/3, process_sm_iq/3, reindex_vcards/0,
- remove_user/2, export/1]).
+ remove_user/2, export/1, import/1, import/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -1006,3 +1006,39 @@ export(_Server) ->
(_Host, _R) ->
[]
end}].
+
+import(LServer) ->
+ [{<<"select username, vcard from vcard;">>,
+ fun([LUser, SVCard]) ->
+ #xmlel{} = VCARD = xml_stream:parse_element(SVCard),
+ #vcard{us = {LUser, LServer}, vcard = VCARD}
+ end},
+ {<<"select username, lusername, fn, lfn, family, lfamily, "
+ "given, lgiven, middle, lmiddle, nickname, lnickname, "
+ "bday, lbday, ctry, lctry, locality, llocality, email, "
+ "lemail, orgname, lorgname, orgunit, lorgunit from vcard_search;">>,
+ fun([User, LUser, FN, LFN,
+ Family, LFamily, Given, LGiven,
+ Middle, LMiddle, Nickname, LNickname,
+ BDay, LBDay, CTRY, LCTRY, Locality, LLocality,
+ EMail, LEMail, OrgName, LOrgName, OrgUnit, LOrgUnit]) ->
+ #vcard_search{us = {LUser, LServer},
+ user = {User, LServer}, luser = LUser,
+ fn = FN, lfn = LFN, family = Family,
+ lfamily = LFamily, given = Given,
+ lgiven = LGiven, middle = Middle,
+ lmiddle = LMiddle, nickname = Nickname,
+ lnickname = LNickname, bday = BDay,
+ lbday = LBDay, ctry = CTRY, lctry = LCTRY,
+ locality = Locality, llocality = LLocality,
+ email = EMail, lemail = LEMail,
+ orgname = OrgName, lorgname = LOrgName,
+ orgunit = OrgUnit, lorgunit = LOrgUnit}
+ end}].
+
+import(_LServer, mnesia, #vcard{} = VCard) ->
+ mnesia:dirty_write(VCard);
+import(_LServer, mnesia, #vcard_search{} = S) ->
+ mnesia:dirty_write(S);
+import(_, _, _) ->
+ pass.
diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl
index 4c70315f7..b2ea34419 100644
--- a/src/mod_vcard_xupdate.erl
+++ b/src/mod_vcard_xupdate.erl
@@ -13,7 +13,7 @@
-export([start/2, stop/1]).
%% hooks
--export([update_presence/3, vcard_set/3, export/1]).
+-export([update_presence/3, vcard_set/3, export/1, import/1, import/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -203,3 +203,14 @@ export(_Server) ->
(_Host, _R) ->
[]
end}].
+
+import(LServer) ->
+ [{<<"select username, hash from vcard_xupdate;">>,
+ fun([LUser, Hash]) ->
+ #vcard_xupdate{us = {LUser, LServer}, hash = Hash}
+ end}].
+
+import(_LServer, mnesia, #vcard_xupdate{} = R) ->
+ mnesia:dirty_write(R);
+import(_, _, _) ->
+ pass.
diff --git a/src/odbc_queries.erl b/src/odbc_queries.erl
index e8fb47379..23b8e8da6 100644
--- a/src/odbc_queries.erl
+++ b/src/odbc_queries.erl
@@ -45,7 +45,7 @@
get_default_privacy_list_t/1, get_privacy_list_names/2,
get_privacy_list_names_t/1, get_privacy_list_id/3,
get_privacy_list_id_t/2, get_privacy_list_data/3,
- get_privacy_list_data_by_id/2,
+ get_privacy_list_data_by_id/2, get_privacy_list_data_t/2,
get_privacy_list_data_by_id_t/1,
set_default_privacy_list/2,
unset_default_privacy_list/2,
@@ -519,6 +519,15 @@ get_privacy_list_data(LServer, Username, SName) ->
Username, <<"' and name='">>, SName,
<<"') order by ord;">>]).
+get_privacy_list_data_t(Username, SName) ->
+ ejabberd_odbc:sql_query_t([<<"select t, value, action, ord, match_all, "
+ "match_iq, match_message, match_presence_in, "
+ "match_presence_out from privacy_list_data "
+ "where id = (select id from privacy_list "
+ "where username='">>,
+ Username, <<"' and name='">>, SName,
+ <<"') order by ord;">>]).
+
get_privacy_list_data_by_id(LServer, ID) ->
ejabberd_odbc:sql_query(LServer,
[<<"select t, value, action, ord, match_all, "