./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 2 JID = jid:make(User, Host, <<>>),
129 2 case ejabberd_auth:does_user_exist(JID) of
130 true ->
131 2 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 4 JID = jid:make(User, Host, <<>>),
140 4 case ejabberd_auth:does_user_exist(JID) of
141 true ->
142 4 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 1 JID = jid:make(User, Host, <<>>),
151 1 case ejabberd_auth:does_user_exist(JID) of
152 true ->
153 1 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 2 JID = jid:make(User, Host, <<>>),
162 2 case ejabberd_auth:does_user_exist(JID) of
163 true ->
164 2 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 6 case gen_mod:get_module_opt(Server, ?MODULE, module_resource, none) of
176 6 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 6 JID = jid:replace_resource(NoResJID, list_to_binary(get_module_resource(LServer))),
185 6 IQ = #iq{type = get, xmlns = ?NS_VCARD, sub_el = []},
186 6 {ok, HostType} = mongoose_domain_api:get_domain_host_type(LServer),
187 6 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 6 Extra = #{},
194 6 {_, IQr} = mod_vcard:process_sm_iq(Acc, JID, JID, IQ, Extra),
195 6 case IQr#iq.sub_el of
196 [#xmlel{} = A1] ->
197 5 case get_vcard(Data, A1) of
198 [] ->
199 2 {error, "Value not found in vcard"};
200 ElemList ->
201 3 [exml_query:cdata(Elem) || Elem <- ElemList]
202 end;
203 _ ->
204 1 {error, "Vcard not found"}
205 end.
206
207
208 -spec get_vcard([binary()], exml:element()) -> [exml:element()].
209 get_vcard([Data1, Data2], A1) ->
210 4 A2List = exml_query:subelements(A1, Data1),
211 4 lists:flatten([get_vcard([Data2], A2) || A2 <- A2List]);
212 get_vcard([Data], A1) ->
213 4 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 2 set_vcard_content(JID, D, [SomeContent]);
219 set_vcard_content(JID, Data, ContentList) ->
220 3 IQ = #iq{type = get, xmlns = ?NS_VCARD, sub_el = []},
221 3 {ok, HostType} = mongoose_domain_api:get_domain_host_type(JID#jid.lserver),
222 3 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 3 Extra = #{},
230 3 {Acc1, IQr} = mod_vcard:process_sm_iq(Acc, JID, JID, IQ, Extra),
231
232 %% Get old vcard
233 3 A4 = case IQr#iq.sub_el of
234 [A1] ->
235 2 {_, _, _, A2} = A1,
236 2 update_vcard_els(Data, ContentList, A2);
237 _ ->
238 1 update_vcard_els(Data, ContentList, [])
239 end,
240
241 %% Build new vcard
242 3 SubEl = #xmlel{name = <<"vCard">>, attrs = [{<<"xmlns">>, <<"vcard-temp">>}], children = A4},
243 3 IQ2 = #iq{type = set, sub_el = SubEl},
244 3 Extra = #{},
245 3 mod_vcard:process_sm_iq(Acc1, JID, JID, IQ2, Extra),
246 3 {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 3 Els2 = lists:keysort(2, Els1),
254 3 [Data1 | Data2] = Data,
255 3 NewEls = case Data2 of
256 [] ->
257 1 [#xmlel{ name = Data1, children = [#xmlcdata{content = Content}] }
258 1 || Content <- ContentList];
259 [D2] ->
260 2 OldEl = case lists:keysearch(Data1, 2, Els2) of
261 1 {value, A} -> A;
262 1 false -> #xmlel{ name = Data1 }
263 end,
264 2 ContentOld1 = OldEl#xmlel.children,
265 2 Content2 = [#xmlel{ name = D2, children = [#xmlcdata{content=Content}]}
266 2 || Content <- ContentList],
267 2 ContentOld2 = [A || {_, X, _, _} = A <- ContentOld1, X/=D2],
268 2 ContentOld3 = lists:keysort(2, ContentOld2),
269 2 ContentNew = lists:keymerge(2, Content2, ContentOld3),
270 2 [#xmlel{ name = Data1, children = ContentNew}]
271 end,
272 3 Els3 = lists:keydelete(Data1, 2, Els2),
273 3 lists:keymerge(2, NewEls, Els3).
Line Hits Source