./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 166 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 166 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 166 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 166 [
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_vcard_content(jid:jid(), any()) ->
174 {error, string()} | list(binary()).
175 get_vcard_content(#jid{lserver = LServer} = NoResJID, Data) ->
176 6 JID = jid:replace_resource(NoResJID, atom_to_binary(?MODULE)),
177 6 IQ = #iq{type = get, xmlns = ?NS_VCARD, sub_el = []},
178 6 {ok, HostType} = mongoose_domain_api:get_domain_host_type(LServer),
179 6 Acc = mongoose_acc:new(#{ location => ?LOCATION,
180 from_jid => JID,
181 to_jid => JID,
182 lserver => JID#jid.lserver,
183 host_type => HostType,
184 element => jlib:iq_to_xml(IQ) }),
185 6 Extra = #{},
186 6 {_, IQr} = mod_vcard:process_sm_iq(Acc, JID, JID, IQ, Extra),
187 6 case IQr#iq.sub_el of
188 [#xmlel{} = A1] ->
189 5 case get_vcard(Data, A1) of
190 [] ->
191 2 {error, "Value not found in vcard"};
192 ElemList ->
193 3 [exml_query:cdata(Elem) || Elem <- ElemList]
194 end;
195 _ ->
196 1 {error, "Vcard not found"}
197 end.
198
199
200 -spec get_vcard([binary()], exml:element()) -> [exml:element()].
201 get_vcard([Data1, Data2], A1) ->
202 4 A2List = exml_query:subelements(A1, Data1),
203 4 lists:flatten([get_vcard([Data2], A2) || A2 <- A2List]);
204 get_vcard([Data], A1) ->
205 4 exml_query:subelements(A1, Data).
206
207 -spec set_vcard_content(jid:jid(), Data :: [binary()],
208 ContentList :: binary() | [binary()]) -> {ok, string()}.
209 set_vcard_content(JID, D, SomeContent) when is_binary(SomeContent) ->
210 2 set_vcard_content(JID, D, [SomeContent]);
211 set_vcard_content(JID, Data, ContentList) ->
212 3 IQ = #iq{type = get, xmlns = ?NS_VCARD, sub_el = []},
213 3 {ok, HostType} = mongoose_domain_api:get_domain_host_type(JID#jid.lserver),
214 3 Acc = mongoose_acc:new(#{ location => ?LOCATION,
215 from_jid => JID,
216 to_jid => JID,
217 lserver => JID#jid.lserver,
218 host_type => HostType,
219 element => jlib:iq_to_xml(IQ) }),
220
221 3 Extra = #{},
222 3 {Acc1, IQr} = mod_vcard:process_sm_iq(Acc, JID, JID, IQ, Extra),
223
224 %% Get old vcard
225 3 A4 = case IQr#iq.sub_el of
226 [A1] ->
227 2 {_, _, _, A2} = A1,
228 2 update_vcard_els(Data, ContentList, A2);
229 _ ->
230 1 update_vcard_els(Data, ContentList, [])
231 end,
232
233 %% Build new vcard
234 3 SubEl = #xmlel{name = <<"vCard">>, attrs = [{<<"xmlns">>, <<"vcard-temp">>}], children = A4},
235 3 IQ2 = #iq{type = set, sub_el = SubEl},
236 3 Extra = #{},
237 3 mod_vcard:process_sm_iq(Acc1, JID, JID, IQ2, Extra),
238 3 {ok, ""}.
239
240 -spec update_vcard_els(Data :: [binary(), ...],
241 ContentList :: [binary() | string()],
242 Els :: [jlib:xmlcdata() | exml:element()]
243 ) -> [jlib:xmlcdata() | exml:element()].
244 update_vcard_els(Data, ContentList, Els1) ->
245 3 Els2 = lists:keysort(2, Els1),
246 3 [Data1 | Data2] = Data,
247 3 NewEls = case Data2 of
248 [] ->
249 1 [#xmlel{ name = Data1, children = [#xmlcdata{content = Content}] }
250 1 || Content <- ContentList];
251 [D2] ->
252 2 OldEl = case lists:keysearch(Data1, 2, Els2) of
253 1 {value, A} -> A;
254 1 false -> #xmlel{ name = Data1 }
255 end,
256 2 ContentOld1 = OldEl#xmlel.children,
257 2 Content2 = [#xmlel{ name = D2, children = [#xmlcdata{content=Content}]}
258 2 || Content <- ContentList],
259 2 ContentOld2 = [A || {_, X, _, _} = A <- ContentOld1, X/=D2],
260 2 ContentOld3 = lists:keysort(2, ContentOld2),
261 2 ContentNew = lists:keymerge(2, Content2, ContentOld3),
262 2 [#xmlel{ name = Data1, children = ContentNew}]
263 end,
264 3 Els3 = lists:keydelete(Data1, 2, Els2),
265 3 lists:keymerge(2, NewEls, Els3).
Line Hits Source