diff options
author | Alexey Shchepin <alexey@process-one.net> | 2012-01-25 12:02:16 +0200 |
---|---|---|
committer | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2014-07-10 13:04:39 +0400 |
commit | 47763c10e3072208d762b4808ab8d66d02628f16 (patch) | |
tree | 2acf2eaccad388fde33396511a3a905777700163 /src/mod_vcard_riak.erl | |
parent | Add start_module/2 (diff) |
Preliminary Riak support
Diffstat (limited to 'src/mod_vcard_riak.erl')
-rw-r--r-- | src/mod_vcard_riak.erl | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/src/mod_vcard_riak.erl b/src/mod_vcard_riak.erl new file mode 100644 index 00000000..44ce35ff --- /dev/null +++ b/src/mod_vcard_riak.erl @@ -0,0 +1,209 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_vcard_riak.erl +%%% Author : Alexey Shchepin <alexey@process-one.net> +%%% Purpose : vCard support via Riak +%%% Created : 6 Jan 2012 by Alexey Shchepin <alexey@process-one.net> +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2011 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with this program; if not, write to the Free Software +%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +-module(mod_vcard_riak). +-author('alexey@process-one.net'). + +-behaviour(gen_mod). + +-export([start/2, stop/1, + get_sm_features/5, + process_local_iq/3, + process_sm_iq/3, + remove_user/2]). + +-include("ejabberd.hrl"). +-include("jlib.hrl"). + + +-define(JUD_MATCHES, 30). +-define(PROCNAME, ejabberd_mod_vcard). + +start(Host, Opts) -> + ejabberd_hooks:add(remove_user, Host, + ?MODULE, remove_user, 50), + IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, + ?MODULE, process_local_iq, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, + ?MODULE, process_sm_iq, IQDisc), + ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + ok. + +stop(Host) -> + ejabberd_hooks:delete(remove_user, Host, + ?MODULE, remove_user, 50), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), + ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + ok. + +get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> + Acc; + +get_sm_features(Acc, _From, _To, Node, _Lang) -> + case Node of + [] -> + case Acc of + {result, Features} -> + {result, [?NS_VCARD | Features]}; + empty -> + {result, [?NS_VCARD]} + end; + _ -> + Acc + end. + +process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> + case Type of + set -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + get -> + IQ#iq{type = result, + sub_el = [{xmlelement, "vCard", + [{"xmlns", ?NS_VCARD}], + [{xmlelement, "FN", [], + [{xmlcdata, "ejabberd"}]}, + {xmlelement, "URL", [], + [{xmlcdata, ?EJABBERD_URI}]}, + {xmlelement, "DESC", [], + [{xmlcdata, + translate:translate( + Lang, + "Erlang Jabber Server") ++ + "\nCopyright (c) 2002-2011 ProcessOne"}]}, + {xmlelement, "BDAY", [], + [{xmlcdata, "2002-11-16"}]} + ]}]} + end. + + +process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> + case Type of + set -> + #jid{user = User, lserver = LServer} = From, + case lists:member(LServer, ?MYHOSTS) of + true -> + set_vcard(User, LServer, SubEl), + IQ#iq{type = result, sub_el = []}; + false -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + end; + get -> + #jid{luser = LUser, lserver = LServer} = To, + Username = list_to_binary(LUser), + case catch ejabberd_riak:get(LServer, <<"vcard">>, Username) of + {ok, SVCARD} -> + case xml_stream:parse_element(SVCARD) of + {error, _Reason} -> + IQ#iq{type = error, + sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; + VCARD -> + IQ#iq{type = result, sub_el = [VCARD]} + end; + {error, notfound} -> + IQ#iq{type = result, sub_el = []}; + _ -> + IQ#iq{type = error, + sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + end + end. + +set_vcard(User, LServer, VCARD) -> + FN = xml:get_path_s(VCARD, [{elem, "FN"}, cdata]), + Family = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "FAMILY"}, cdata]), + Given = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "GIVEN"}, cdata]), + Middle = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "MIDDLE"}, cdata]), + Nickname = xml:get_path_s(VCARD, [{elem, "NICKNAME"}, cdata]), + BDay = xml:get_path_s(VCARD, [{elem, "BDAY"}, cdata]), + CTRY = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "CTRY"}, cdata]), + Locality = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "LOCALITY"},cdata]), + EMail1 = xml:get_path_s(VCARD, [{elem, "EMAIL"}, {elem, "USERID"},cdata]), + EMail2 = xml:get_path_s(VCARD, [{elem, "EMAIL"}, cdata]), + OrgName = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGNAME"}, cdata]), + OrgUnit = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGUNIT"}, cdata]), + EMail = case EMail1 of + "" -> + EMail2; + _ -> + EMail1 + end, + + LUser = jlib:nodeprep(User), + LFN = stringprep:tolower(FN), + LFamily = stringprep:tolower(Family), + LGiven = stringprep:tolower(Given), + LMiddle = stringprep:tolower(Middle), + LNickname = stringprep:tolower(Nickname), + LBDay = stringprep:tolower(BDay), + LCTRY = stringprep:tolower(CTRY), + LLocality = stringprep:tolower(Locality), + LEMail = stringprep:tolower(EMail), + LOrgName = stringprep:tolower(OrgName), + LOrgUnit = stringprep:tolower(OrgUnit), + + if + (LUser == error) or + (LFN == error) or + (LFamily == error) or + (LGiven == error) or + (LMiddle == error) or + (LNickname == error) or + (LBDay == error) or + (LCTRY == error) or + (LLocality == error) or + (LEMail == error) or + (LOrgName == error) or + (LOrgUnit == error) -> + {error, badarg}; + true -> + Username = list_to_binary(LUser), + SVCARD = xml:element_to_binary(VCARD), + + ejabberd_riak:put( + LServer, <<"vcard">>, Username, SVCARD, + [{<<"bday_bin">>, list_to_binary(LBDay)}, + {<<"ctry_bin">>, list_to_binary(LCTRY)}, + {<<"email_bin">>, list_to_binary(LEMail)}, + {<<"fn_bin">>, list_to_binary(LFN)}, + {<<"family_bin">>, list_to_binary(LFamily)}, + {<<"given_bin">>, list_to_binary(LGiven)}, + {<<"locality_bin">>, list_to_binary(LLocality)}, + {<<"middle_bin">>, list_to_binary(LMiddle)}, + {<<"nickname_bin">>, list_to_binary(LNickname)}, + {<<"orgname_bin">>, list_to_binary(LOrgName)}, + {<<"orgunit_bin">>, list_to_binary(LOrgUnit)}, + {<<"user_bin">>, Username}]), + + ejabberd_hooks:run(vcard_set, LServer, [LUser, LServer, VCARD]) + end. + +remove_user(User, Server) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + Username = list_to_binary(LUser), + ejabberd_riak:delete(LServer, <<"vcard">>, Username), + ok. |