./ct_report/coverage/service_admin_extra_vcard.COVER.html

1 %%%-------------------------------------------------------------------
2 %%% File : service_admin_extra_vcard.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_vcard).
27 -author('badlop@process-one.net').
28
29 -export([
30 commands/0,
31
32 get_vcard/3,
33 get_vcard/4,
34 set_vcard/4,
35 set_vcard/5
36 ]).
37
38 -ignore_xref([commands/0, get_vcard/3, get_vcard/4, set_vcard/5, set_vcard/4, set_vcard/5]).
39
40 -include("mongoose.hrl").
41 -include("ejabberd_commands.hrl").
42 -include("mod_roster.hrl").
43 -include("jlib.hrl").
44 -include_lib("exml/include/exml.hrl").
45
46 %%%
47 %%% Register commands
48 %%%
49
50 -spec commands() -> [ejabberd_commands:cmd(), ...].
51 commands() ->
52 164 Vcard1FieldsString = "Some vcard field names in get/set_vcard are:\n"
53 " FN - Full Name\n"
54 " NICKNAME - Nickname\n"
55 " BDAY - Birthday\n"
56 " TITLE - Work: Position\n"
57 " ROLE - Work: Role",
58
59 164 Vcard2FieldsString = "Some vcard field names and subnames in get/set_vcard2 are:\n"
60 " N FAMILY - Family name\n"
61 " N GIVEN - Given name\n"
62 " N MIDDLE - Middle name\n"
63 " ADR CTRY - Address: Country\n"
64 " ADR LOCALITY - Address: City\n"
65 " EMAIL USERID - E-Mail Address\n"
66 " ORG ORGNAME - Work: Company\n"
67 " ORG ORGUNIT - Work: Department",
68
69 164 VcardXEP = "For a full list of vCard fields check XEP-0054: vcard-temp at "
70 "http://www.xmpp.org/extensions/xep-0054.html",
71
72 164 [
73 #ejabberd_commands{name = get_vcard, tags = [vcard],
74 desc = "Get content from a vCard field",
75 longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++ "\n\n"
76 ++ VcardXEP,
77 module = ?MODULE, function = get_vcard,
78 args = [{user, binary}, {host, binary}, {name, binary}],
79 result = {content, binary}},
80 #ejabberd_commands{name = get_vcard2, tags = [vcard],
81 desc = "Get content from a vCard field",
82 longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n"
83 ++ VcardXEP,
84 module = ?MODULE, function = get_vcard,
85 args = [{user, binary}, {host, binary},
86 {name, binary}, {subname, binary}],
87 result = {content, binary}},
88 #ejabberd_commands{name = get_vcard2_multi, tags = [vcard],
89 desc = "Get multiple contents from a vCard field",
90 longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n"
91 ++ VcardXEP,
92 module = ?MODULE, function = get_vcard,
93 args = [{user, binary}, {host, binary},
94 {name, binary}, {subname, binary}],
95 result = {contents, {list, {value, binary}}}},
96 #ejabberd_commands{name = set_vcard, tags = [vcard],
97 desc = "Set content in a vCard field",
98 longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++ "\n\n"
99 ++ VcardXEP,
100 module = ?MODULE, function = set_vcard,
101 args = [{user, binary}, {host, binary},
102 {name, binary}, {content, binary}],
103 result = {res, restuple}},
104 #ejabberd_commands{name = set_vcard2, tags = [vcard],
105 desc = "Set content in a vCard subfield",
106 longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n"
107 ++ VcardXEP,
108 module = ?MODULE, function = set_vcard,
109 args = [{user, binary}, {host, binary}, {name, binary},
110 {subname, binary}, {content, binary}],
111 result = {res, restuple}},
112 #ejabberd_commands{name = set_vcard2_multi, tags = [vcard],
113 desc = "Set multiple contents in a vCard subfield",
114 longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n"
115 ++ VcardXEP,
116 module = ?MODULE, function = set_vcard,
117 args = [{user, binary}, {host, binary}, {name, binary},
118 {subname, binary}, {contents, {list, binary}}],
119 result = {res, restuple}}
120 ].
121
122 %%%
123 %%% Vcard
124 %%%
125 -spec get_vcard(jid:user(), jid:server(), any())
126 -> {error, string()} | [binary()].
127 get_vcard(User, Host, Name) ->
128
:-(
JID = jid:make(User, Host, <<>>),
129
:-(
case ejabberd_auth:does_user_exist(JID) of
130 true ->
131
:-(
get_vcard_content(JID, [Name]);
132 false ->
133
:-(
{error, io_lib:format("User ~s@~s does not exist", [User, Host])}
134 end.
135
136 -spec get_vcard(jid:user(), jid:server(), any(), any())
137 -> {error, string()} | [binary()].
138 get_vcard(User, Host, Name, Subname) ->
139
:-(
JID = jid:make(User, Host, <<>>),
140
:-(
case ejabberd_auth:does_user_exist(JID) of
141 true ->
142
:-(
get_vcard_content(JID, [Name, Subname]);
143 false ->
144
:-(
{error, io_lib:format("User ~s@~s does not exist", [User, Host])}
145 end.
146
147 -spec set_vcard(jid:user(), jid:server(), [binary()],
148 binary() | [binary()]) -> {ok, string()} | {user_does_not_exist, string()}.
149 set_vcard(User, Host, Name, SomeContent) ->
150
:-(
JID = jid:make(User, Host, <<>>),
151
:-(
case ejabberd_auth:does_user_exist(JID) of
152 true ->
153
:-(
set_vcard_content(JID, [Name], SomeContent);
154 false ->
155
:-(
{user_does_not_exist, io_lib:format("User ~s@~s does not exist", [User, Host])}
156 end.
157
158 -spec set_vcard(jid:user(), jid:server(), [binary()], [binary()],
159 binary() | [binary()]) -> {ok, string()} | {user_does_not_exist, string()}.
160 set_vcard(User, Host, Name, Subname, SomeContent) ->
161
:-(
JID = jid:make(User, Host, <<>>),
162
:-(
case ejabberd_auth:does_user_exist(JID) of
163 true ->
164
:-(
set_vcard_content(JID, [Name, Subname], SomeContent);
165 false ->
166
:-(
{user_does_not_exist, io_lib:format("User ~s@~s does not exist", [User, Host])}
167 end.
168
169
170 %%
171 %% Internal vcard
172
173 -spec get_module_resource(jid:server()) -> string().
174 get_module_resource(Server) ->
175
:-(
case gen_mod:get_module_opt(Server, ?MODULE, module_resource, none) of
176
:-(
none -> atom_to_list(?MODULE);
177
:-(
R when is_list(R) -> R
178 end.
179
180
181 -spec get_vcard_content(jid:jid(), any()) ->
182 {error, string()} | list(binary()).
183 get_vcard_content(#jid{lserver = LServer} = NoResJID, Data) ->
184
:-(
JID = jid:replace_resource(NoResJID, list_to_binary(get_module_resource(LServer))),
185
:-(
IQ = #iq{type = get, xmlns = ?NS_VCARD, sub_el = []},
186
:-(
{ok, HostType} = mongoose_domain_api:get_domain_host_type(LServer),
187
:-(
Acc = mongoose_acc:new(#{ location => ?LOCATION,
188 from_jid => JID,
189 to_jid => JID,
190 lserver => JID#jid.lserver,
191 host_type => HostType,
192 element => jlib:iq_to_xml(IQ) }),
193
:-(
Extra = #{},
194
:-(
{_, IQr} = mod_vcard:process_sm_iq(Acc, JID, JID, IQ, Extra),
195
:-(
case IQr#iq.sub_el of
196 [#xmlel{} = A1] ->
197
:-(
case get_vcard(Data, A1) of
198 [] ->
199
:-(
{error, "Value not found in vcard"};
200 ElemList ->
201
:-(
[exml_query:cdata(Elem) || Elem <- ElemList]
202 end;
203 _ ->
204
:-(
{error, "Vcard not found"}
205 end.
206
207
208 -spec get_vcard([binary()], exml:element()) -> [exml:element()].
209 get_vcard([Data1, Data2], A1) ->
210
:-(
A2List = exml_query:subelements(A1, Data1),
211
:-(
lists:flatten([get_vcard([Data2], A2) || A2 <- A2List]);
212 get_vcard([Data], A1) ->
213
:-(
exml_query:subelements(A1, Data).
214
215 -spec set_vcard_content(jid:jid(), Data :: [binary()],
216 ContentList :: binary() | [binary()]) -> {ok, string()}.
217 set_vcard_content(JID, D, SomeContent) when is_binary(SomeContent) ->
218
:-(
set_vcard_content(JID, D, [SomeContent]);
219 set_vcard_content(JID, Data, ContentList) ->
220
:-(
IQ = #iq{type = get, xmlns = ?NS_VCARD, sub_el = []},
221
:-(
{ok, HostType} = mongoose_domain_api:get_domain_host_type(JID#jid.lserver),
222
:-(
Acc = mongoose_acc:new(#{ location => ?LOCATION,
223 from_jid => JID,
224 to_jid => JID,
225 lserver => JID#jid.lserver,
226 host_type => HostType,
227 element => jlib:iq_to_xml(IQ) }),
228
229
:-(
Extra = #{},
230
:-(
{Acc1, IQr} = mod_vcard:process_sm_iq(Acc, JID, JID, IQ, Extra),
231
232 %% Get old vcard
233
:-(
A4 = case IQr#iq.sub_el of
234 [A1] ->
235
:-(
{_, _, _, A2} = A1,
236
:-(
update_vcard_els(Data, ContentList, A2);
237 _ ->
238
:-(
update_vcard_els(Data, ContentList, [])
239 end,
240
241 %% Build new vcard
242
:-(
SubEl = #xmlel{name = <<"vCard">>, attrs = [{<<"xmlns">>, <<"vcard-temp">>}], children = A4},
243
:-(
IQ2 = #iq{type = set, sub_el = SubEl},
244
:-(
Extra = #{},
245
:-(
mod_vcard:process_sm_iq(Acc1, JID, JID, IQ2, Extra),
246
:-(
{ok, ""}.
247
248 -spec update_vcard_els(Data :: [binary(), ...],
249 ContentList :: [binary() | string()],
250 Els :: [jlib:xmlcdata() | exml:element()]
251 ) -> [jlib:xmlcdata() | exml:element()].
252 update_vcard_els(Data, ContentList, Els1) ->
253
:-(
Els2 = lists:keysort(2, Els1),
254
:-(
[Data1 | Data2] = Data,
255
:-(
NewEls = case Data2 of
256 [] ->
257
:-(
[#xmlel{ name = Data1, children = [#xmlcdata{content = Content}] }
258
:-(
|| Content <- ContentList];
259 [D2] ->
260
:-(
OldEl = case lists:keysearch(Data1, 2, Els2) of
261
:-(
{value, A} -> A;
262
:-(
false -> #xmlel{ name = Data1 }
263 end,
264
:-(
ContentOld1 = OldEl#xmlel.children,
265
:-(
Content2 = [#xmlel{ name = D2, children = [#xmlcdata{content=Content}]}
266
:-(
|| Content <- ContentList],
267
:-(
ContentOld2 = [A || {_, X, _, _} = A <- ContentOld1, X/=D2],
268
:-(
ContentOld3 = lists:keysort(2, ContentOld2),
269
:-(
ContentNew = lists:keymerge(2, Content2, ContentOld3),
270
:-(
[#xmlel{ name = Data1, children = ContentNew}]
271 end,
272
:-(
Els3 = lists:keydelete(Data1, 2, Els2),
273
:-(
lists:keymerge(2, NewEls, Els3).
Line Hits Source