* src/eldap/eldap_filter: Forgot to add eldap_filter.erl in ejabberd-1.1.2 branch

SVN Revision: 627
This commit is contained in:
Mickaël Rémond 2006-09-24 15:31:21 +00:00
parent 79f5d2772e
commit 5b9526d998
1 changed files with 285 additions and 0 deletions

285
src/eldap/eldap_filter.erl Normal file
View File

@ -0,0 +1,285 @@
%%%====================================================
%%% File: eldap_filter.erl
%%% Purpose: Converts String Representation of
%%% LDAP Search Filter (RFC 2254)
%%% to eldap's representation of filter
%%% Author: Evgeniy Khramtsov <xramtsov@gmail.com>
%%% License: GPL
%%%====================================================
-module(eldap_filter).
-author('xram@jabber.ru').
%%%======================
%%% Export functions
%%%======================
-export([parse/1,
parse/2,
do_sub/2
]).
%%%-------------------------------------------------------------------------
%%% Arity: parse/1
%%% Function: parse(RFC2254_Filter) -> {ok, EldapFilter} |
%%% {error, bad_filter}
%%%
%%% RFC2254_Filter = string().
%%%
%%% Description: Converts String Representation of LDAP Search Filter (RFC 2254)
%%% to eldap's representation of filter.
%%%
%%% Example:
%%% > eldap_filter:parse("(&(!(uid<=100))(mail=*))").
%%%
%%% {ok,{'and',[{'not',{lessOrEqual,{'AttributeValueAssertion',"uid","100"}}},
%%% {present,"mail"}]}}
%%%-------------------------------------------------------------------------
parse(RFC2254_Filter) ->
parse(RFC2254_Filter, []).
%%%-------------------------------------------------------------------------
%%% Arity: parse/2
%%% Function: parse(RFC2254_Filter, [SubstValue |...]) ->
%%% {ok, EldapFilter} |
%%% {error, bad_filter} |
%%% {error, bad_regexp} |
%%% {error, max_substitute_recursion}
%%%
%%% SubstValue = {RegExp, Value} | {RegExp, Value, N},
%%% RFC2254_Filter = RegExp = Value = string(),
%%% N = integer().
%%%
%%% Description: The same as parse/1, but substitutes N or all occurences
%%% of RegExp with Value *after* parsing.
%%%
%%% Example:
%%% > eldap_filter:parse(
%%% "(|(mail=%u@%d)(jid=%u@%d))",
%%% [{"%u", "xramtsov"},{"%d","gmail.com"}]).
%%%
%%% {ok,{'or',[{equalityMatch,{'AttributeValueAssertion',
%%% "mail",
%%% "xramtsov@gmail.com"}},
%%% {equalityMatch,{'AttributeValueAssertion',
%%% "jid",
%%% "xramtsov@gmail.com"}}]}}
%%%--------------------------------------------------------------------------
parse(RFC2254_Filter, ListOfSubValues) ->
case catch convert_filter(parse_filter(RFC2254_Filter), ListOfSubValues) of
[EldapFilter] when is_tuple(EldapFilter) ->
{ok, EldapFilter};
{regexp, Error} ->
{error, Error};
_ ->
{error, bad_filter}
end.
%%%==========================
%%% Internal functions
%%%==========================
%%%----------------------
%%% split/1,4
%%%----------------------
split(Filter) ->
split(Filter, 0, [], []).
split([], _, _, Result) ->
Result;
split([H|T], Num, Rest, Result) ->
NewNum = case H of
$( -> Num + 1;
$) -> Num - 1;
_ -> Num
end,
if
NewNum == 0 ->
X = Rest++[H],
LenX = length(X),
if
LenX > 2 ->
split(T, 0, [], Result ++ [lists:sublist(X, 2, LenX-2)]);
true ->
split(T, 0, Rest, Result)
end;
true ->
split(T, NewNum, Rest++[H], Result)
end.
%%%-----------------------
%%% parse_filter/1
%%%-----------------------
parse_filter(Filter) ->
case Filter of
[$! | T] ->
{'not', parse_filter(T)};
[$| | T] ->
{'or', parse_filter(T)};
[$& | T] ->
{'and', parse_filter(T)};
[$( | _] ->
parse_filter(split(Filter));
[List | _] when is_list(List) ->
[parse_filter(X) || X <- Filter];
_ ->
Filter
end.
%%%--------------------
%%% convert_filter/2
%%%--------------------
convert_filter({'not', [Val | _]}, Replace) ->
eldap:'not'(convert_filter(Val, Replace));
convert_filter({'or', Vals}, Replace) ->
eldap:'or'([convert_filter(X, Replace) || X <- Vals]);
convert_filter({'and', Vals}, Replace) ->
eldap:'and'([convert_filter(X, Replace) || X <- Vals]);
convert_filter([H|_] = Filter, Replace) when is_integer(H) ->
parse_attr(Filter, Replace);
convert_filter(Filter, Replace) when is_list(Filter) ->
[convert_filter(X, Replace) || X <- Filter].
%%%-----------------
%%% parse_attr/2,3
%%%-----------------
parse_attr(Attr, ListOfSubValues) ->
{Action, [_|_] = Name, [_|_] = Value} = split_attribute(Attr),
parse_attr(Action, {Name, Value}, ListOfSubValues).
parse_attr(approx, {Name, Value}, ListOfSubValues) ->
NewValue = do_sub(Value, ListOfSubValues),
eldap:approxMatch(Name, NewValue);
parse_attr(greater, {Name, Value}, ListOfSubValues) ->
NewValue = do_sub(Value, ListOfSubValues),
eldap:greaterOrEqual(Name, NewValue);
parse_attr(less, {Name, Value}, ListOfSubValues) ->
NewValue = do_sub(Value, ListOfSubValues),
eldap:lessOrEqual(Name, NewValue);
parse_attr(equal, {Name, Value}, ListOfSubValues) ->
{ok, RegSList} = regexp:split(remove_extra_asterisks(Value), "[*]"),
Pattern = case [do_sub(X, ListOfSubValues) || X <- RegSList] of
[Head | Tail] when Tail /= [] ->
{Head, lists:sublist(Tail, length(Tail)-1), lists:last(Tail)};
R ->
R
end,
case Pattern of
[V] ->
eldap:equalityMatch(Name, V);
{[], [], []} ->
eldap:present(Name);
{"", Any, ""} ->
eldap:substrings(Name, [{any, X} || X<-Any]);
{H, Any, ""} ->
eldap:substrings(Name, [{initial, H}]++[{any, X} || X<-Any]);
{"", Any, T} ->
eldap:substrings(Name, [{any, X} || X<-Any]++[{final, T}]);
{H, Any, T} ->
eldap:substrings(Name, [{initial, H}]++[{any, X} || X<-Any]++[{final, T}])
end;
parse_attr(_, _, _) ->
false.
%%%--------------------
%%% do_sub/2,3
%%%--------------------
-define(MAX_RECURSION, 100).
do_sub(S, []) ->
S;
do_sub([], _) ->
[];
do_sub(S, [{RegExp, New} | T]) ->
Result = do_sub(S, {RegExp, replace_amps(New)}, 1),
do_sub(Result, T);
do_sub(S, [{RegExp, New, Times} | T]) ->
Result = do_sub(S, {RegExp, replace_amps(New), Times}, 1),
do_sub(Result, T).
do_sub(S, {RegExp, New}, Iter) ->
case regexp:sub(S, RegExp, New) of
{ok, NewS, 0} ->
NewS;
{ok, NewS, _} when Iter =< ?MAX_RECURSION ->
do_sub(NewS, {RegExp, New}, Iter+1);
{ok, _, _} when Iter > ?MAX_RECURSION ->
throw({regexp, max_substitute_recursion});
_ ->
throw({regexp, bad_regexp})
end;
do_sub(S, {_, _, N}, _) when N<1 ->
S;
do_sub(S, {RegExp, New, Times}, Iter) ->
case regexp:sub(S, RegExp, New) of
{ok, NewS, 0} ->
NewS;
{ok, NewS, _} when Iter < Times ->
do_sub(NewS, {RegExp, New, Times}, Iter+1);
{ok, NewS, _} ->
NewS;
_ ->
throw({regexp, bad_regexp})
end.
remove_extra_asterisks(String) ->
{Res, _} = lists:foldl(
fun(X, {Acc, Last}) ->
case X of
$* when Last==$* ->
{Acc, X};
_ ->
{Acc ++ [X], X}
end
end,
{"", ""}, String),
Res.
replace_amps(String) ->
lists:foldl(
fun(X, Acc) ->
if
X == $& ->
Acc ++ "\\&";
true ->
Acc ++ [X]
end
end,
"", String).
split_attribute(String) ->
split_attribute(String, "", $0).
split_attribute([], _, _) ->
{error, "", ""};
split_attribute([H|Tail], Acc, Last) ->
case H of
$= when Last==$> ->
{greater, lists:sublist(Acc, 1, length(Acc)-1), Tail};
$= when Last==$< ->
{less, lists:sublist(Acc, 1, length(Acc)-1), Tail};
$= when Last==$~ ->
{approx, lists:sublist(Acc, 1, length(Acc)-1), Tail};
$= when Last==$: ->
{equal, lists:sublist(Acc, 1, length(Acc)-1), Tail};
$= ->
{equal, Acc, Tail};
_ ->
split_attribute(Tail, Acc++[H], H)
end.