./ct_report/coverage/service_admin_extra_stanza.COVER.html

1 %%%-------------------------------------------------------------------
2 %%% File : service_admin_extra_stanza.erl
3 %%% Author : Badlop <badlop@process-one.net>, Piotr Nosek <piotr.nosek@erlang-solutions.com>
4 %%% Purpose : Contributed administrative functions and commands
5 %%% Created : 10 Aug 2008 by Badlop <badlop@process-one.net>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2008 ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 %%%
24 %%%-------------------------------------------------------------------
25
26 -module(service_admin_extra_stanza).
27 -author('badlop@process-one.net').
28
29 -export([
30 commands/0,
31
32 send_message_headline/4,
33 send_message_chat/3,
34 send_stanza_c2s/4
35 ]).
36
37 -ignore_xref([commands/0, send_message_chat/3, send_message_headline/4, send_stanza_c2s/4]).
38
39 -include("mongoose.hrl").
40 -include("ejabberd_commands.hrl").
41 -include("jlib.hrl").
42 -include_lib("exml/include/exml.hrl").
43
44 %%%
45 %%% Register commands
46 %%%
47
48 -spec commands() -> [ejabberd_commands:cmd(), ...].
49 commands() ->
50 152 [
51 #ejabberd_commands{name = send_message_chat, tags = [stanza],
52 desc = "Send a chat message to a local or remote bare of full JID",
53 module = ?MODULE, function = send_message_chat,
54 args = [{from, binary}, {to, binary}, {body, binary}],
55 result = {res, restuple}},
56 #ejabberd_commands{name = send_message_headline, tags = [stanza],
57 desc = "Send a headline message to a local or remote bare of full JID",
58 module = ?MODULE, function = send_message_headline,
59 args = [{from, binary}, {to, binary},
60 {subject, binary}, {body, binary}],
61 result = {res, restuple}},
62 #ejabberd_commands{name = send_stanza_c2s, tags = [stanza],
63 desc = "Send a stanza as if sent from a c2s session",
64 module = ?MODULE, function = send_stanza_c2s,
65 args = [{user, binary}, {host, binary},
66 {resource, binary}, {stanza, binary}],
67 result = {res, restuple}}
68 ].
69
70 %%%
71 %%% Stanza
72 %%%
73
74 %% @doc Send a chat message to a Jabber account.
75 -spec send_message_chat(From :: binary(), To :: binary(),
76 Body :: binary() | string()) -> {Res, string()} when
77 Res :: bad_jid | ok.
78 send_message_chat(From, To, Body) ->
79 2 Packet = build_packet(message_chat, [Body]),
80 2 send_packet_all_resources(From, To, Packet).
81
82
83 %% @doc Send a headline message to a Jabber account.
84 -spec send_message_headline(From :: binary(), To :: binary(),
85 Subject:: binary() | string(),
86 Body :: binary() | string()) -> {Res, string()} when
87 Res :: ok | bad_jid.
88 send_message_headline(From, To, Subject, Body) ->
89 2 Packet = build_packet(message_headline, [Subject, Body]),
90 2 send_packet_all_resources(From, To, Packet).
91
92
93 %% @doc Send a packet to a Jabber account.
94 %% If a resource was specified in the JID, the packet is sent only to that
95 %% specific resource.
96 %% If no resource was specified in the JID, and the user is remote or local but
97 %% offline, the packet is sent to the bare JID.
98 %% If the user is local and is online in several resources, the packet is sent
99 %% to all its resources.
100 -spec send_packet_all_resources(
101 FromJIDStr :: binary() | jid:jid(),
102 ToJIDString :: binary() | jid:jid(),
103 exml:element()) ->
104 {Res, string()} when
105 Res :: bad_jid | ok.
106 send_packet_all_resources(FromJIDString, ToJIDString, Packet) when is_binary(FromJIDString) ->
107 4 case jid:from_binary(FromJIDString) of
108 error ->
109 2 {bad_jid, "Sender JID is invalid"};
110 FromJID ->
111 2 send_packet_all_resources(FromJID, ToJIDString, Packet),
112 2 {ok, ""}
113 end;
114 send_packet_all_resources(FromJID, ToJIDString, Packet) when is_binary(ToJIDString) ->
115 2 case jid:from_binary(ToJIDString) of
116 error ->
117
:-(
{bad_jid, "Receiver JID is invalid"};
118 ToJID ->
119 2 send_packet_all_resources(FromJID, ToJID, Packet),
120 2 {ok, ""}
121 end;
122 send_packet_all_resources(#jid{} = FromJID, #jid{} = ToJID, Packet) ->
123 2 case ToJID#jid.resource of
124 <<"">> ->
125 1 send_packet_all_resources_2(FromJID, ToJID, Packet),
126 1 {ok, ""};
127 _Res ->
128 1 route_packet(FromJID, ToJID, Packet),
129 1 {ok, ""}
130 end.
131
132
133 -spec send_packet_all_resources_2(FromJID :: jid:jid(),
134 ToJID :: jid:jid(),
135 exml:element()) -> ok.
136 send_packet_all_resources_2(FromJID, ToJID, Packet) ->
137 1 case ejabberd_sm:get_user_resources(ToJID) of
138 [] ->
139
:-(
route_packet(FromJID, ToJID, Packet);
140 ToResources ->
141 1 lists:foreach(
142 fun(ToResource) ->
143 2 route_packet(FromJID, jid:replace_resource(ToJID, ToResource), Packet)
144 end,
145 ToResources)
146 end.
147
148
149 -spec route_packet(jid:jid(), jid:jid(), exml:element()) -> mongoose_acc:t().
150 route_packet(FromJID, ToJID, Packet) ->
151 3 ejabberd_router:route(FromJID, ToJID, Packet).
152
153
154 -spec build_packet('message_chat' | 'message_headline',
155 SubjectBody :: [binary() | string(), ...]) -> exml:element().
156 build_packet(message_chat, [Body]) ->
157 2 #xmlel{ name = <<"message">>,
158 attrs = [{<<"type">>, <<"chat">>}, {<<"id">>, mongoose_bin:gen_from_crypto()}],
159 children = [#xmlel{ name = <<"body">>, children = [#xmlcdata{content = Body}]}]
160 };
161 build_packet(message_headline, [Subject, Body]) ->
162 2 #xmlel{ name = <<"message">>,
163 attrs = [{<<"type">>, <<"headline">>}, {<<"id">>, mongoose_bin:gen_from_crypto()}],
164 children = [#xmlel{ name = <<"subject">>, children = [#xmlcdata{content = Subject}]},
165 #xmlel{ name = <<"body">>, children = [#xmlcdata{content = Body}]}
166 ]
167 }.
168
169
170 -spec send_stanza_c2s(jid:user(), jid:server(), jid:resource(),
171 Stanza :: binary()) -> {Res, string()} when
172 Res :: user_does_not_exist | bad_stanza | ok.
173 send_stanza_c2s(Username, Host, Resource, Stanza) ->
174 3 C2sPid = ejabberd_sm:get_session_pid(jid:make(Username, Host, Resource)),
175 3 case C2sPid of
176 none ->
177 1 {user_does_not_exist,
178 io_lib:format("User ~s@~s/~s does not exist", [Username, Host, Resource])};
179 _ ->
180 2 case exml:parse(Stanza) of
181 {ok, XmlEl} ->
182 1 p1_fsm_old:send_event(C2sPid, {xmlstreamelement, XmlEl}),
183 1 {ok, "Stanza has been sent"};
184 {error, _} ->
185 1 {bad_stanza, "Stanza is incorrect"}
186 end
187 end.
188
Line Hits Source