1 diff --git a/doc/guide.tex b/doc/guide.tex
2 index 5de409d..ac3dba8 100644
5 @@ -4052,6 +4052,17 @@ Options:
8 \iqdiscitem{\ns{vcard-temp}}
9 +\titem{access\_get}\ind{options!accessget} Access rule that defines
10 + who is allowed to see vCard of local users.
11 + If a rule returns `deny' on the requester
12 + user name, that user cannot see vCards of local users.
13 + By default anybody can see the vCards of local users.
14 +\titem{access\_set}\ind{options!accessset} Access rule that defines
15 + who is allowed to modify his vCard.
16 + If a rule returns `deny' on the requester
17 + user name, that user cannot modify his vCard.
18 + By default each local account can modify his own local vCard.
19 + Notice that vCard of a user can only be edited by the user himself.
20 \titem{\{search, true|false\}}\ind{options!search}This option specifies whether the search
21 functionality is enabled or not
22 If disabled, the option \term{host} will be ignored and the
23 @@ -4087,14 +4098,17 @@ Examples:
26 \item The second situation differs in a way that search results are not limited,
27 - and that all virtual hosts will be searched instead of only the current one:
28 + and that all virtual hosts will be searched instead of only the current one.
29 + Also, vCards of local users can only be seen by Local users.
31 +{access, vcard_get, [{allow, local}]}.
35 {mod_vcard, [{search, true},
37 - {allow_return_all, true}]},
38 + {allow_return_all, true},
39 + {access_get, vcard_get}]},
43 @@ -4128,6 +4142,11 @@ consists of the following \modvcardldap{}-specific options:
46 \iqdiscitem{\ns{vcard-temp}}
47 +\titem{access\_get}\ind{options!accessget} Access rule that defines
48 + who is allowed to see vCard of local users.
49 + If a rule returns `deny' on the requester
50 + user name, that user cannot see vCards of local users.
51 + By default anybody can see the vCards of local users.
52 \titem{\{search, true|false\}}\ind{options!search}This option specifies whether the search
53 functionality is enabled (value: \term{true}) or disabled (value:
54 \term{false}). If disabled, the option \term{host} will be ignored and the
55 diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
56 index 4384087..c54e8ea 100644
57 --- a/src/mod_vcard.erl
58 +++ b/src/mod_vcard.erl
59 @@ -174,7 +174,9 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
62 #jid{user = User, lserver = LServer} = From,
63 - case lists:member(LServer, ?MYHOSTS) of
64 + Access = gen_mod:get_module_opt(LServer, ?MODULE, access_set, all),
65 + case lists:member(LServer, ?MYHOSTS) andalso
66 + (acl:match_rule(LServer, Access, From) == allow) of
68 set_vcard(User, LServer, SubEl),
69 IQ#iq{type = result, sub_el = []};
70 @@ -183,19 +185,28 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
73 #jid{luser = LUser, lserver = LServer} = To,
74 - US = {LUser, LServer},
76 - mnesia:read({vcard, US})
78 - Els = case mnesia:transaction(F) of
83 - {aborted, _Reason} ->
86 - IQ#iq{type = result, sub_el = Els}
87 + Access = gen_mod:get_module_opt(LServer, ?MODULE, access_get, all),
88 + case acl:match_rule(LServer, Access, From) of
90 + Els = get_vcard(LUser, LServer),
91 + IQ#iq{type = result, sub_el = Els};
93 + IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
97 +get_vcard(LUser, LServer) ->
98 + US = {LUser, LServer},
100 + mnesia:read({vcard, US})
102 + case mnesia:transaction(F) of
104 + lists:map(fun(R) ->
107 + {aborted, _Reason} ->
111 set_vcard(User, LServer, VCARD) ->
112 diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl
113 index f4078df..074bdf7 100644
114 --- a/src/mod_vcard_ldap.erl
115 +++ b/src/mod_vcard_ldap.erl
116 @@ -241,38 +241,47 @@ process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ)
120 -process_sm_iq(_From, #jid{lserver=LServer} = To, #iq{sub_el = SubEl} = IQ) ->
121 - case catch process_vcard_ldap(To, IQ, LServer) of
122 +process_sm_iq(From, #jid{lserver=LServer} = To, #iq{sub_el = SubEl} = IQ) ->
123 + case catch process_vcard_ldap(From, To, IQ, LServer) of
125 IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]};
130 -process_vcard_ldap(To, IQ, Server) ->
131 +process_vcard_ldap(From, To, IQ, Server) ->
132 {ok, State} = eldap_utils:get_state(Server, ?PROCNAME),
133 #iq{type = Type, sub_el = SubEl} = IQ,
136 IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
138 - #jid{luser = LUser} = To,
139 - LServer = State#state.serverhost,
140 - case ejabberd_auth:is_user_exists(LUser, LServer) of
142 - VCardMap = State#state.vcard_map,
143 - case find_ldap_user(LUser, State) of
144 - #eldap_entry{attributes = Attributes} ->
145 - Vcard = ldap_attributes_to_vcard(Attributes, VCardMap, {LUser, LServer}),
146 - IQ#iq{type = result, sub_el = Vcard};
148 - IQ#iq{type = result, sub_el = []}
151 - IQ#iq{type = result, sub_el = []}
153 + process_vcard_ldap_get_maybe(From, To, IQ, State)
156 +process_vcard_ldap_get_maybe(From, To, IQ, State) ->
157 + #jid{luser = LUser} = To,
158 + #jid{lserver = FromLServer} = From,
159 + LServer = State#state.serverhost,
160 + Access = gen_mod:get_module_opt(LServer, ?MODULE, access_get, all),
161 + case ejabberd_auth:is_user_exists(LUser, LServer) andalso
162 + (acl:match_rule(FromLServer, Access, From) == allow) of
164 + process_vcard_ldap_get(LUser, LServer, IQ, State);
166 + IQ#iq{type = result, sub_el = []}
169 +process_vcard_ldap_get(LUser, LServer, IQ, State) ->
170 + VCardMap = State#state.vcard_map,
171 + case find_ldap_user(LUser, State) of
172 + #eldap_entry{attributes = Attributes} ->
173 + Vcard = ldap_attributes_to_vcard(Attributes, VCardMap, {LUser, LServer}),
174 + IQ#iq{type = result, sub_el = Vcard};
176 + IQ#iq{type = result, sub_el = []}
179 handle_call(get_state, _From, State) ->
180 {reply, {ok, State}, State};
181 handle_call(stop, _From, State) ->
182 diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl
183 index 30c2888..d239823 100644
184 --- a/src/mod_vcard_odbc.erl
185 +++ b/src/mod_vcard_odbc.erl
186 @@ -138,7 +138,9 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
189 #jid{user = User, lserver = LServer} = From,
190 - case lists:member(LServer, ?MYHOSTS) of
191 + Access = gen_mod:get_module_opt(LServer, ?MODULE, access_set, all),
192 + case lists:member(LServer, ?MYHOSTS) andalso
193 + (acl:match_rule(LServer, Access, From) == allow) of
195 set_vcard(User, LServer, SubEl),
196 IQ#iq{type = result, sub_el = []};
197 @@ -147,24 +149,34 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
200 #jid{luser = LUser, lserver = LServer} = To,
201 - Username = ejabberd_odbc:escape(LUser),
202 - case catch odbc_queries:get_vcard(LServer, Username) of
203 - {selected, ["vcard"], [{SVCARD}]} ->
204 - case xml_stream:parse_element(SVCARD) of
205 - {error, _Reason} ->
206 - IQ#iq{type = error,
207 - sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
209 - IQ#iq{type = result, sub_el = [VCARD]}
211 - {selected, ["vcard"], []} ->
212 - IQ#iq{type = result, sub_el = []};
214 - IQ#iq{type = error,
215 - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
216 + Access = gen_mod:get_module_opt(LServer, ?MODULE, access_get, all),
217 + case acl:match_rule(LServer, Access, From) of
219 + get_vcard(LUser, LServer, SubEl, IQ);
221 + IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
225 +get_vcard(LUser, LServer, SubEl, IQ) ->
226 + Username = ejabberd_odbc:escape(LUser),
227 + case catch odbc_queries:get_vcard(LServer, Username) of
228 + {selected, ["vcard"], [{SVCARD}]} ->
229 + case xml_stream:parse_element(SVCARD) of
230 + {error, _Reason} ->
231 + IQ#iq{type = error,
232 + sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
234 + IQ#iq{type = result, sub_el = [VCARD]}
236 + {selected, ["vcard"], []} ->
237 + IQ#iq{type = result, sub_el = []};
239 + IQ#iq{type = error,
240 + sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
244 set_vcard(User, LServer, VCARD) ->
245 FN = xml:get_path_s(VCARD, [{elem, "FN"}, cdata]),
246 Family = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "FAMILY"}, cdata]),