From 42cdf80cd4fd6d398639b4d722282ab29473b311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= Date: Tue, 23 May 2006 20:19:37 +0000 Subject: [PATCH] * src/mod_roster.erl: The subscribe request are now resend at login as long as they have not been answered. mod_roster do no more depends on mod_offline. * src/ejabberd_sm.erl: Likewise. * src/ejabberd_c2s.erl: Likewise. * src/mod_roster_odbc.erl: Likewise (The ODBC/relational support has not yet been tested). * src/mod_roster.hrl: Likewise. * src/mod_offline.erl: Likewise. * src/mod_offline_odbc.erl: Likewise. * odbc/pg.sql: Likewise. * odbc/mysql.sql: Likewise. SVN Revision: 569 --- ChangeLog | 15 ++++ src/ejabberd_c2s.erl | 14 ++++ src/ejabberd_sm.erl | 55 +++++---------- src/mod_offline.erl | 4 -- src/mod_offline_odbc.erl | 4 -- src/mod_roster.erl | 146 +++++++++++++++++++++++++-------------- src/mod_roster.hrl | 2 +- src/mod_roster_odbc.erl | 67 +++++++++++++++--- src/odbc/mysql.sql | 3 + src/odbc/pg.sql | 17 +++-- 10 files changed, 215 insertions(+), 112 deletions(-) diff --git a/ChangeLog b/ChangeLog index 29faebc93..16cb561a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-05-23 Mickael Remond + + * src/mod_roster.erl: The subscribe request are now resend at login as + long as they have not been answered. mod_roster do no more depends on + mod_offline. + * src/ejabberd_sm.erl: Likewise. + * src/ejabberd_c2s.erl: Likewise. + * src/mod_roster_odbc.erl: Likewise (The ODBC/relational support has + not yet been tested). + * src/mod_roster.hrl: Likewise. + * src/mod_offline.erl: Likewise. + * src/mod_offline_odbc.erl: Likewise. + * odbc/pg.sql: Likewise. + * odbc/mysql.sql: Likewise. + 2006-05-22 Mickael Remond * src/ejabberd_sm.erl: The max_user_sessions has been moved to diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 826c52b53..8683f62cb 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1364,6 +1364,7 @@ presence_update(From, Packet, StateData) -> StateData#state.server, [StateData#state.jid]), resend_offline_messages(StateData), + resend_subscription_requests(StateData), presence_broadcast_first( From, StateData#state{pres_last = Packet, pres_invis = false @@ -1727,6 +1728,19 @@ resend_offline_messages(#state{user = User, end, Rs) end. +resend_subscription_requests(#state{user = User, + server = Server} = StateData) -> + PendingSubscriptions = ejabberd_hooks:run_fold( + resend_subscription_requests_hook, + Server, + [], + [User, Server]), + lists:foreach(fun(XMLPacket) -> + send_element(StateData, + XMLPacket) + end, + PendingSubscriptions). + get_showtag(undefined) -> "unavailable"; get_showtag(Presence) -> diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index ec985f5b0..2ad148ac5 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -306,32 +306,34 @@ do_route(From, To, Packet) -> {Pass, Subsc} = case xml:get_attr_s("type", Attrs) of "subscribe" -> + Reason = xml:get_tag_cdata( + xml:get_subtag(Packet, "status")), {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, subscribe]), + [User, Server, From, subscribe, Reason]), true}; "subscribed" -> {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, subscribed]), + [User, Server, From, subscribed, ""]), true}; "unsubscribe" -> {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, unsubscribe]), + [User, Server, From, unsubscribe, ""]), true}; "unsubscribed" -> {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, unsubscribed]), + [User, Server, From, unsubscribed, ""]), true}; _ -> {true, false} @@ -340,39 +342,18 @@ do_route(From, To, Packet) -> LFrom = jlib:jid_tolower(From), PResources = get_user_present_resources( LUser, LServer), - if - PResources /= [] -> - lists:foreach( - fun({_, R}) -> - if LFrom /= - {LUser, LServer, R} -> - do_route( - From, - jlib:jid_replace_resource(To, R), - Packet); - true -> - ok - end - end, PResources); - true -> - if - Subsc -> - case ejabberd_auth:is_user_exists( - LUser, LServer) of - true -> - ejabberd_hooks:run( - offline_subscription_hook, - LServer, - [From, To, Packet]); - _ -> - Err = jlib:make_error_reply( - Packet, ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err) - end; - true -> - ok - end - end; + lists:foreach( + fun({_, R}) -> + if LFrom /= + {LUser, LServer, R} -> + do_route( + From, + jlib:jid_replace_resource(To, R), + Packet); + true -> + ok + end + end, PResources); true -> ok end; diff --git a/src/mod_offline.erl b/src/mod_offline.erl index a261dbfc5..425406c9d 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -37,8 +37,6 @@ start(Host, _Opts) -> update_table(), ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:add(offline_subscription_hook, Host, - ?MODULE, store_packet, 50), ejabberd_hooks:add(resend_offline_messages_hook, Host, ?MODULE, pop_offline_messages, 50), ejabberd_hooks:add(remove_user, Host, @@ -83,8 +81,6 @@ receive_all(Msgs) -> stop(Host) -> ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:delete(offline_subscription_hook, Host, - ?MODULE, store_packet, 50), ejabberd_hooks:delete(resend_offline_messages_hook, Host, ?MODULE, pop_offline_messages, 50), ejabberd_hooks:delete(remove_user, Host, diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 2241ce27d..50a0e53c9 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -28,8 +28,6 @@ start(Host, _Opts) -> ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:add(offline_subscription_hook, Host, - ?MODULE, store_packet, 50), ejabberd_hooks:add(resend_offline_messages_hook, Host, ?MODULE, pop_offline_messages, 50), ejabberd_hooks:add(remove_user, Host, @@ -97,8 +95,6 @@ receive_all(Msgs) -> stop(Host) -> ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:delete(offline_subscription_hook, Host, - ?MODULE, store_packet, 50), ejabberd_hooks:delete(resend_offline_messages_hook, Host, ?MODULE, pop_offline_messages, 50), ejabberd_hooks:delete(remove_user, Host, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 6ca6f6c8b..4ddd30c60 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -17,7 +17,8 @@ process_local_iq/3, get_user_roster/2, get_subscription_lists/3, - in_subscription/5, + get_in_pending_subscriptions/3, + in_subscription/6, out_subscription/4, set_items/3, remove_user/2, @@ -46,6 +47,8 @@ start(Host, Opts) -> ?MODULE, get_jid_info, 50), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), + ejabberd_hooks:add(resend_subscription_requests_hook, Host, + ?MODULE, get_in_pending_subscriptions, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). @@ -62,6 +65,8 @@ stop(Host) -> ?MODULE, get_jid_info, 50), ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), + ejabberd_hooks:delete(resend_subscription_requests_hook, Host, + ?MODULE, get_in_pending_subscriptions, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). @@ -130,8 +135,6 @@ get_user_roster(Acc, US) -> end. - - item_to_xml(Item) -> Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}], Attrs2 = case Item#roster.name of @@ -160,12 +163,11 @@ item_to_xml(Item) -> _ -> Attrs3 end, - Attrs = Attrs4 ++ Item#roster.xattrs, SubEls1 = lists:map(fun(G) -> {xmlelement, "group", [], [{xmlcdata, G}]} end, Item#roster.groups), SubEls = SubEls1 ++ Item#roster.xs, - {xmlelement, "item", Attrs, SubEls}. + {xmlelement, "item", Attrs4, SubEls}. process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) -> @@ -193,7 +195,6 @@ process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> I#roster{jid = JID, name = "", groups = [], - xattrs = [], xs = []} end, Item1 = process_item_attrs(Item, Attrs), @@ -274,9 +275,7 @@ process_item_attrs(Item, [{Attr, Val} | Attrs]) -> "ask" -> process_item_attrs(Item, Attrs); _ -> - XAttrs = Item#roster.xattrs, - process_item_attrs(Item#roster{xattrs = [{Attr, Val} | XAttrs]}, - Attrs) + process_item_attrs(Item, Attrs) end; process_item_attrs(Item, []) -> Item. @@ -374,13 +373,13 @@ ask_to_pending(Ask) -> Ask. -in_subscription(_, User, Server, JID, Type) -> - process_subscription(in, User, Server, JID, Type). +in_subscription(_, User, Server, JID, Type, Reason) -> + process_subscription(in, User, Server, JID, Type, Reason). out_subscription(User, Server, JID, Type) -> - process_subscription(out, User, Server, JID, Type). + process_subscription(out, User, Server, JID, Type, []). -process_subscription(Direction, User, Server, JID1, Type) -> +process_subscription(Direction, User, Server, JID1, Type, Reason) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), US = {LUser, LServer}, @@ -415,12 +414,18 @@ process_subscription(Direction, User, Server, JID1, Type) -> Item#roster.ask, Type) end, + AskMessage = case NewState of + {_, both} -> Reason; + {_, in} -> Reason; + {_, _} -> [] + end, case NewState of none -> {none, AutoReply}; {Subscription, Pending} -> NewItem = Item#roster{subscription = Subscription, - ask = Pending}, + ask = Pending, + askmessage = list_to_binary(AskMessage)}, mnesia:write(NewItem), {{push, NewItem}, AutoReply} end @@ -630,13 +635,42 @@ process_item_attrs_ws(Item, [{Attr, Val} | Attrs]) -> "ask" -> process_item_attrs_ws(Item, Attrs); _ -> - XAttrs = Item#roster.xattrs, - process_item_attrs_ws(Item#roster{xattrs = [{Attr, Val} | XAttrs]}, - Attrs) + process_item_attrs_ws(Item, Attrs) end; process_item_attrs_ws(Item, []) -> Item. +get_in_pending_subscriptions(Ls, User, Server) -> + JID = jlib:make_jid(User, Server,""), + case mnesia:dirty_index_read(roster, {User,Server}, #roster.us) of + Result when list(Result) -> + Ls ++ lists:map( + fun(R) -> + Message = R#roster.askmessage, + Status = if is_binary(Message) -> + binary_to_list(Message); + true -> + [] + end, + {xmlelement, "presence", [{"from", jlib:jid_to_string(R#roster.jid)}, + {"to", jlib:jid_to_string(JID)}, + {"type", "subscribe"}], + [{xmlelement, "status", [], + [{xmlcdata, Status}]}]} + end, + lists:filter( + fun(R) -> + case R#roster.ask of + in -> true; + both -> true; + _ -> false + end + end, + Result)); + _ -> [] + end. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -673,42 +707,54 @@ update_table() -> Fields -> ok; [uj, user, jid, name, subscription, ask, groups, xattrs, xs] -> - ?INFO_MSG("Converting roster table from " - "{uj, user, jid, name, subscription, ask, groups, xattrs, xs} format", []), - Host = ?MYNAME, - {atomic, ok} = mnesia:create_table( - mod_roster_tmp_table, - [{disc_only_copies, [node()]}, - {type, bag}, - {local_content, true}, - {record_name, roster}, - {attributes, record_info(fields, roster)}]), - mnesia:del_table_index(roster, user), - mnesia:transform_table(roster, ignore, Fields), - F1 = fun() -> - mnesia:write_lock_table(mod_roster_tmp_table), - mnesia:foldl( - fun(#roster{usj = {U, JID}, us = U} = R, _) -> - mnesia:dirty_write( - mod_roster_tmp_table, - R#roster{usj = {U, Host, JID}, - us = {U, Host}}) - end, ok, roster) - end, - mnesia:transaction(F1), - mnesia:clear_table(roster), - F2 = fun() -> - mnesia:write_lock_table(roster), - mnesia:foldl( - fun(R, _) -> - mnesia:dirty_write(R) - end, ok, mod_roster_tmp_table) - end, - mnesia:transaction(F2), - mnesia:delete_table(mod_roster_tmp_table); + convert_table1(Fields); + [usj, us, jid, name, subscription, ask, groups, xattrs, xs] -> + convert_table2(Fields); _ -> ?INFO_MSG("Recreating roster table", []), mnesia:transform_table(roster, ignore, Fields) end. +%% Convert roster table to support virtual host +convert_table1(Fields) -> + ?INFO_MSG("Virtual host support: converting roster table from " + "{uj, user, jid, name, subscription, ask, groups, xattrs, xs} format", []), + Host = ?MYNAME, + {atomic, ok} = mnesia:create_table( + mod_roster_tmp_table, + [{disc_only_copies, [node()]}, + {type, bag}, + {local_content, true}, + {record_name, roster}, + {attributes, record_info(fields, roster)}]), + mnesia:del_table_index(roster, user), + mnesia:transform_table(roster, ignore, Fields), + F1 = fun() -> + mnesia:write_lock_table(mod_roster_tmp_table), + mnesia:foldl( + fun(#roster{usj = {U, JID}, us = U} = R, _) -> + mnesia:dirty_write( + mod_roster_tmp_table, + R#roster{usj = {U, Host, JID}, + us = {U, Host}}) + end, ok, roster) + end, + mnesia:transaction(F1), + mnesia:clear_table(roster), + F2 = fun() -> + mnesia:write_lock_table(roster), + mnesia:foldl( + fun(R, _) -> + mnesia:dirty_write(R) + end, ok, mod_roster_tmp_table) + end, + mnesia:transaction(F2), + mnesia:delete_table(mod_roster_tmp_table). + + +%% Convert roster table: xattrs fields become +convert_table2(Fields) -> + ?INFO_MSG("Converting roster table from " + "{usj, us, jid, name, subscription, ask, groups, xattrs, xs} format", []), + mnesia:transform_table(roster, ignore, Fields). diff --git a/src/mod_roster.hrl b/src/mod_roster.hrl index 5cab7e414..ca882b744 100644 --- a/src/mod_roster.hrl +++ b/src/mod_roster.hrl @@ -13,6 +13,6 @@ subscription = none, ask = none, groups = [], - xattrs = [], + askmessage = [], xs = []}). diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 82ba55ad7..440898d2d 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -17,7 +17,8 @@ process_local_iq/3, get_user_roster/2, get_subscription_lists/3, - in_subscription/5, + get_in_pending_subscriptions/3, + in_subscription/6, out_subscription/4, set_items/3, remove_user/2, @@ -41,6 +42,8 @@ start(Host, Opts) -> ?MODULE, get_jid_info, 50), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), + ejabberd_hooks:add(resend_subscription_requests_hook, Host, + ?MODULE, get_in_pending_subscriptions, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). @@ -57,6 +60,8 @@ stop(Host) -> ?MODULE, get_jid_info, 50), ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), + ejabberd_hooks:delete(resend_subscription_requests_hook, Host, + ?MODULE, get_in_pending_subscriptions, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). @@ -253,7 +258,8 @@ process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> ["insert into rosterusers(" " username, jid, nick, " " subscription, ask, " - " server, subscribe, type) " + " askmessage, server, " + " subscribe, type) " " values ", ItemVals, ";"]), ejabberd_odbc:sql_query_t( ["delete from rostergroups " @@ -436,13 +442,13 @@ ask_to_pending(Ask) -> Ask. -in_subscription(_, User, Server, JID, Type) -> - process_subscription(in, User, Server, JID, Type). +in_subscription(_, User, Server, JID, Type, Reason) -> + process_subscription(in, User, Server, JID, Type, Reason). out_subscription(User, Server, JID, Type) -> - process_subscription(out, User, Server, JID, Type). + process_subscription(out, User, Server, JID, Type, []). -process_subscription(Direction, User, Server, JID1, Type) -> +process_subscription(Direction, User, Server, JID1, Type, Reason) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), LJID = jlib:jid_tolower(JID1), @@ -497,12 +503,18 @@ process_subscription(Direction, User, Server, JID1, Type) -> Item#roster.ask, Type) end, + AskMessage = case NewState of + {_, both} -> Reason; + {_, in} -> Reason; + {_, _} -> [] + end, case NewState of none -> {none, AutoReply}; {Subscription, Pending} -> NewItem = Item#roster{subscription = Subscription, - ask = Pending}, + ask = Pending, + askmessage = AskMessage}, ItemVals = record_to_string(NewItem), ejabberd_odbc:sql_query_t( ["delete from rosterusers " @@ -512,7 +524,8 @@ process_subscription(Direction, User, Server, JID1, Type) -> ["insert into rosterusers(" " username, jid, nick, " " subscription, ask, " - " server, subscribe, type) " + " askmessage, server, subscribe, " + " type) " " values ", ItemVals, ";"]), {{push, NewItem}, AutoReply} end @@ -700,7 +713,8 @@ process_item_set_t(LUser, LServer, {xmlelement, _Name, Attrs, Els}) -> ["insert into rosterusers(" " username, jid, nick, " " subscription, ask, " - " server, subscribe, type) " + " askmessage, server, subscribe, " + " type) " " values ", ItemVals, ";"], ["delete from rostergroups " " where username='", Username, "' " @@ -755,6 +769,37 @@ process_item_attrs_ws(Item, []) -> Item. +get_in_pending_subscriptions(Ls, User, Server) -> + JID = jlib:make_jid(User, Server,""), + case mnesia:dirty_index_read(roster, {User,Server}, #roster.us) of + Result when list(Result) -> + Ls ++ lists:map( + fun(R) -> + Message = R#roster.askmessage, + Status = if is_binary(Message) -> + binary_to_list(Message); + true -> + [] + end, + {xmlelement, "presence", [{"from", jlib:jid_to_string(R#roster.jid)}, + {"to", jlib:jid_to_string(JID)}, + {"type", "subscribe"}], + [{xmlelement, "status", [], + [{xmlcdata, Status}]}]} + end, + lists:filter( + fun(R) -> + case R#roster.ask of + in -> true; + both -> true; + _ -> false + end + end, + Result)); + _ -> [] + end. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% get_jid_info(_, User, Server, JID) -> @@ -857,7 +902,8 @@ record_to_string(#roster{us = {User, _Server}, jid = JID, name = Name, subscription = Subscription, - ask = Ask}) -> + ask = Ask, + askmessage = AskMessage}) -> Username = ejabberd_odbc:escape(User), SJID = ejabberd_odbc:escape(jlib:jid_to_string(jlib:jid_tolower(JID))), Nick = ejabberd_odbc:escape(Name), @@ -881,6 +927,7 @@ record_to_string(#roster{us = {User, _Server}, "'", Nick, "'," "'", SSubscription, "'," "'", SAsk, "'," + "'", AskMessage, "'," "'N', '', 'item')"]. groups_to_string(#roster{us = {User, _Server}, diff --git a/src/odbc/mysql.sql b/src/odbc/mysql.sql index 89c7f65b8..8642d72a4 100644 --- a/src/odbc/mysql.sql +++ b/src/odbc/mysql.sql @@ -19,6 +19,7 @@ CREATE TABLE rosterusers ( nick text, subscription character(1) NOT NULL, ask character(1) NOT NULL, + askmessage text, server character(1) NOT NULL, subscribe text, type text @@ -91,3 +92,5 @@ CREATE INDEX i_vcard_search_lemail ON vcard_search(lemail); CREATE INDEX i_vcard_search_lorgname ON vcard_search(lorgname); CREATE INDEX i_vcard_search_lorgunit ON vcard_search(lorgunit); +--- To update from 1.x: +-- ALTER TABLE rosterusers ADD COLUMN askmessage text AFTER ask; diff --git a/src/odbc/pg.sql b/src/odbc/pg.sql index 0db27d2c5..d115e1e5a 100644 --- a/src/odbc/pg.sql +++ b/src/odbc/pg.sql @@ -18,6 +18,7 @@ CREATE TABLE rosterusers ( nick text, subscription character(1) NOT NULL, ask character(1) NOT NULL, + askmessage text, server character(1) NOT NULL, subscribe text, "type" text @@ -36,12 +37,6 @@ CREATE TABLE rostergroups ( CREATE INDEX pk_rosterg_user_jid ON rostergroups USING btree (username, jid); ---- To update from previous table definition: --- CREATE SEQUENCE spool_seq_seq; --- ALTER TABLE spool ADD COLUMN seq integer; --- ALTER TABLE spool ALTER COLUMN seq SET DEFAULT nextval('spool_seq_seq'); --- UPDATE spool SET seq = DEFAULT; --- ALTER TABLE spool ALTER COLUMN seq SET NOT NULL; CREATE TABLE spool ( username text NOT NULL, @@ -95,3 +90,13 @@ CREATE INDEX i_vcard_search_llocality ON vcard_search(llocality); CREATE INDEX i_vcard_search_lemail ON vcard_search(lemail); CREATE INDEX i_vcard_search_lorgname ON vcard_search(lorgname); CREATE INDEX i_vcard_search_lorgunit ON vcard_search(lorgunit); + +--- To update from 0.9.8: +-- CREATE SEQUENCE spool_seq_seq; +-- ALTER TABLE spool ADD COLUMN seq integer; +-- ALTER TABLE spool ALTER COLUMN seq SET DEFAULT nextval('spool_seq_seq'); +-- UPDATE spool SET seq = DEFAULT; +-- ALTER TABLE spool ALTER COLUMN seq SET NOT NULL; + +--- To update from 1.x: +-- ALTER TABLE rosterusers ADD COLUMN askmessage text AFTER ask;