diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index c6801d54e..c3d206e3f 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -91,6 +91,18 @@ get_commands_spec() -> "List of scopes to allow, separated by ';'"], result = {result, {tuple, [{token, string}, {scopes, string}, {expires_in, string}]}} }, + #ejabberd_commands{name = oauth_issue_token, tags = [oauth], + desc = "Issue an [OAuth](https://docs.ejabberd.im/developer/ejabberd-api/oauth/) token for the given jid", + module = ?MODULE, function = oauth_issue_token, + version = 1, + args = [{jid, string}, {ttl, integer}, {scopes, {list, {scope, binary}}}], + policy = restricted, + args_example = ["user@server.com", 3600, ["connected_users_number", "muc_online_rooms"]], + args_desc = ["Jid for which issue token", + "Time to live of generated token in seconds", + "List of scopes to allow"], + result = {result, {tuple, [{token, string}, {scopes, {list, {scope, string}}}, {expires_in, string}]}} + }, #ejabberd_commands{name = oauth_list_tokens, tags = [oauth], desc = "List [OAuth](https://docs.ejabberd.im/developer/ejabberd-api/oauth/) tokens, user, scope, and seconds to expire (only Mnesia)", longdesc = "List OAuth tokens, their user and scope, and how many seconds remain until expirity", @@ -135,8 +147,10 @@ get_commands_spec() -> } ]. -oauth_issue_token(Jid, TTLSeconds, ScopesString) -> +oauth_issue_token(Jid, TTLSeconds, [Head|_] = ScopesString) when is_integer(Head) -> Scopes = [list_to_binary(Scope) || Scope <- string:tokens(ScopesString, ";")], + oauth_issue_token(Jid, TTLSeconds, Scopes); +oauth_issue_token(Jid, TTLSeconds, Scopes) -> try jid:decode(list_to_binary(Jid)) of #jid{luser =Username, lserver = Server} -> Ctx1 = #oauth_ctx{password = admin_generated}, diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 70374aa44..cb9deab1d 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -511,6 +511,20 @@ get_commands_spec() -> args_desc = ["User name", "Server name", "Contact user name", "Contact server name", "Nickname", "Group", "Subscription"], result = {res, rescode}}, + #ejabberd_commands{name = add_rosteritem, tags = [roster], + desc = "Add an item to a user's roster (supports ODBC)", + module = ?MODULE, function = add_rosteritem, + version = 1, + args = [{localuser, binary}, {localhost, binary}, + {user, binary}, {host, binary}, + {nick, binary}, {groups, {list, {group, binary}}}, + {subs, binary}], + args_rename = [{localserver, localhost}, {server, host}], + args_example = [<<"user1">>,<<"myserver.com">>,<<"user2">>, <<"myserver.com">>, + <<"User 2">>, [<<"Friends">>, <<"Team 1">>], <<"both">>], + args_desc = ["User name", "Server name", "Contact user name", "Contact server name", + "Nickname", "Groups", "Subscription"], + result = {res, rescode}}, %%{"", "subs= none, from, to or both"}, %%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"}, %%{"", "will add mike@server.com to peter@localhost roster"}, @@ -697,6 +711,18 @@ get_commands_spec() -> args_desc = ["Group identifier", "Group server name", "Group name", "Group description", "Groups to display"], result = {res, rescode}}, + #ejabberd_commands{name = srg_create, tags = [shared_roster_group], + desc = "Create a Shared Roster Group", + module = ?MODULE, function = srg_create, + version = 1, + args = [{group, binary}, {host, binary}, + {label, binary}, {description, binary}, {display, {list, {group, binary}}}], + args_rename = [{name, label}], + args_example = [<<"group3">>, <<"myserver.com">>, <<"Group3">>, + <<"Third group">>, [<<"group1">>, <<"group2">>]], + args_desc = ["Group identifier", "Group server name", "Group name", + "Group description", "List of groups to display"], + result = {res, rescode}}, #ejabberd_commands{name = srg_delete, tags = [shared_roster_group], desc = "Delete a Shared Roster Group", module = ?MODULE, function = srg_delete, @@ -1301,14 +1327,16 @@ update_vcard_els(Data, ContentList, Els1) -> %%% Roster %%% -add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) -> +add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) when is_binary(Group) -> + add_rosteritem(LocalUser, LocalServer, User, Server, Nick, [Group], Subs); +add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Groups, Subs) -> case {jid:make(LocalUser, LocalServer), jid:make(User, Server)} of {error, _} -> throw({error, "Invalid 'localuser'/'localserver'"}); {_, error} -> throw({error, "Invalid 'user'/'server'"}); {Jid, _Jid2} -> - RosterItem = build_roster_item(User, Server, {add, Nick, Subs, Group}), + RosterItem = build_roster_item(User, Server, {add, Nick, Subs, Groups}), case mod_roster:set_item_and_notify_clients(Jid, RosterItem, true) of ok -> ok; _ -> error @@ -1423,6 +1451,11 @@ push_roster_item(LU, LS, R, U, S, Action) -> ejabberd_router:route( xmpp:set_from_to(ResIQ, jid:remove_resource(LJID), LJID)). +build_roster_item(U, S, {add, Nick, Subs, Groups}) when is_list(Groups) -> + #roster_item{jid = jid:make(U, S), + name = Nick, + subscription = misc:binary_to_atom(Subs), + groups = Groups}; build_roster_item(U, S, {add, Nick, Subs, Group}) -> Groups = binary:split(Group,<<";">>, [global, trim]), #roster_item{jid = jid:make(U, S), @@ -1503,11 +1536,14 @@ private_set2(Username, Host, Xml) -> %%% Shared Roster Groups %%% -srg_create(Group, Host, Label, Description, Display) -> +srg_create(Group, Host, Label, Description, Display) when is_binary(Display) -> DisplayList = case Display of - <<>> -> []; - _ -> ejabberd_regexp:split(Display, <<"\\\\n">>) + <<>> -> []; + _ -> ejabberd_regexp:split(Display, <<"\\\\n">>) end, + srg_create(Group, Host, Label, Description, DisplayList); + +srg_create(Group, Host, Label, Description, DisplayList) -> Opts = [{label, Label}, {displayed_groups, DisplayList}, {description, Description}], diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 8b5358ce8..13f196278 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -308,6 +308,22 @@ get_commands_spec() -> args = [{name, binary}, {service, binary}, {password, binary}, {reason, binary}, {users, binary}], result = {res, rescode}}, + #ejabberd_commands{name = send_direct_invitation, tags = [muc_room], + desc = "Send a direct invitation to several destinations", + longdesc = "Since ejabberd 20.12, this command is " + "asynchronous: the API call may return before the " + "server has send all the invitations.\n\n" + "`password` and `message` can be set to `none`.", + module = ?MODULE, function = send_direct_invitation, + version = 1, + args_desc = ["Room name", "MUC service", "Password, or `none`", + "Reason text, or `none`", "List of users JIDs"], + args_example = [<<"room1">>, <<"muc.example.com">>, + <<>>, <<"Check this out!">>, + ["user2@localhost", "user3@example.com"]], + args = [{name, binary}, {service, binary}, {password, binary}, + {reason, binary}, {users, {list, {jid, binary}}}], + result = {res, rescode}}, #ejabberd_commands{name = change_room_option, tags = [muc_room], desc = "Change an option in a MUC room", @@ -344,6 +360,20 @@ get_commands_spec() -> args = [{user, binary}, {nick, binary}, {room, binary}, {nodes, binary}], result = {nodes, {list, {node, string}}}}, + #ejabberd_commands{name = subscribe_room, tags = [muc_room, muc_sub], + desc = "Subscribe to a MUC conference", + module = ?MODULE, function = subscribe_room, + version = 1, + args_desc = ["User JID", "a user's nick", + "the room to subscribe", "list of nodes"], + args_example = ["tom@localhost", "Tom", "room1@conference.localhost", + ["urn:xmpp:mucsub:nodes:messages", "urn:xmpp:mucsub:nodes:affiliations"]], + result_desc = "The list of nodes that has subscribed", + result_example = ["urn:xmpp:mucsub:nodes:messages", + "urn:xmpp:mucsub:nodes:affiliations"], + args = [{user, binary}, {nick, binary}, {room, binary}, + {nodes, {list, {node, binary}}}], + result = {nodes, {list, {node, string}}}}, #ejabberd_commands{name = subscribe_room_many, tags = [muc_room, muc_sub], desc = "Subscribe several users to a MUC conference", note = "added in 22.05", @@ -367,6 +397,30 @@ get_commands_spec() -> {room, binary}, {nodes, binary}], result = {res, rescode}}, + #ejabberd_commands{name = subscribe_room_many, tags = [muc_room, muc_sub], + desc = "Subscribe several users to a MUC conference", + note = "added in 22.05", + longdesc = "This command accepts up to 50 users at once " + "(this is configurable with the *`mod_muc_admin`* option " + "`subscribe_room_many_max_users`)", + module = ?MODULE, function = subscribe_room_many, + version = 1, + args_desc = ["Users JIDs and nicks", + "the room to subscribe", + "nodes separated by commas: `,`"], + args_example = [[{"tom@localhost", "Tom"}, + {"jerry@localhost", "Jerry"}], + "room1@conference.localhost", + ["urn:xmpp:mucsub:nodes:messages", "urn:xmpp:mucsub:nodes:affiliations"]], + args = [{users, {list, + {user, {tuple, + [{jid, binary}, + {nick, binary} + ]}} + }}, + {room, binary}, + {nodes, {list, {node, binary}}}], + result = {res, rescode}}, #ejabberd_commands{name = unsubscribe_room, tags = [muc_room, muc_sub], desc = "Unsubscribe from a MUC conference", module = ?MODULE, function = unsubscribe_room, @@ -1074,20 +1128,22 @@ get_room_occupants_number(Room, Host) -> %%---------------------------- %% http://xmpp.org/extensions/xep-0249.html -send_direct_invitation(RoomName, RoomService, Password, Reason, UsersString) -> +send_direct_invitation(RoomName, RoomService, Password, Reason, UsersString) when is_binary(UsersString) -> + UsersStrings = binary:split(UsersString, <<":">>, [global]), + send_direct_invitation(RoomName, RoomService, Password, Reason, UsersStrings); +send_direct_invitation(RoomName, RoomService, Password, Reason, UsersStrings) -> case jid:make(RoomName, RoomService) of error -> throw({error, "Invalid 'roomname' or 'service'"}); RoomJid -> XmlEl = build_invitation(Password, Reason, RoomJid), - Users = get_users_to_invite(RoomJid, UsersString), + Users = get_users_to_invite(RoomJid, UsersStrings), [send_direct_invitation(RoomJid, UserJid, XmlEl) || UserJid <- Users], ok end. -get_users_to_invite(RoomJid, UsersString) -> - UsersStrings = binary:split(UsersString, <<":">>, [global]), +get_users_to_invite(RoomJid, UsersStrings) -> OccupantsTuples = get_room_occupants(RoomJid#jid.luser, RoomJid#jid.lserver), OccupantsJids = [jid:decode(JidString) @@ -1439,8 +1495,10 @@ set_room_affiliation(Name, Service, JID, AffiliationString) -> subscribe_room(_User, Nick, _Room, _Nodes) when Nick == <<"">> -> throw({error, "Nickname must be set"}); -subscribe_room(User, Nick, Room, Nodes) -> +subscribe_room(User, Nick, Room, Nodes) when is_binary(Nodes) -> NodeList = re:split(Nodes, "\\h*,\\h*"), + subscribe_room(User, Nick, Room, NodeList); +subscribe_room(User, Nick, Room, NodeList) -> try jid:decode(Room) of #jid{luser = Name, lserver = Host} when Name /= <<"">> -> try jid:decode(User) of