mirror of
https://github.com/processone/ejabberd.git
synced 2024-10-09 15:06:54 +02:00
*** empty log message ***
SVN Revision: 51
This commit is contained in:
parent
b88ff5f323
commit
aed24c637f
2
TODO
2
TODO
@ -5,6 +5,6 @@ admin interface
|
||||
S2S timeouts
|
||||
rewrite S2S key validation
|
||||
iq:browse(?)
|
||||
SVR DNS records
|
||||
SRV DNS records
|
||||
karma
|
||||
SSL
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
<H3 ALIGN=center>Alexey Shchepin<BR><A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR><A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3>
|
||||
|
||||
<H3 ALIGN=center>January 23, 2003</H3> <DIV ALIGN=center><IMG SRC="logo.png">
|
||||
<H3 ALIGN=center>January 26, 2003</H3> <DIV ALIGN=center><IMG SRC="logo.png">
|
||||
|
||||
</DIV><BR>
|
||||
<BR>
|
||||
@ -115,8 +115,8 @@ runned on them. Each element of list is a tuple with following elements:
|
||||
|
||||
<LI> <TT>ejabberd_s2s_in</TT>: serves incoming S2S connections;
|
||||
|
||||
<LI> <TT>ejabberd_service</TT>: serves connections to Jabber services (i.e.
|
||||
that use <TT>jabber:component:accept</TT> namespace).
|
||||
<LI> <TT>ejabberd_service</TT>: serves connections to Jabber services
|
||||
(i. e. that use <TT>jabber:component:accept</TT> namespace).
|
||||
</UL>For example, following configuration defines that C2S connections listened on
|
||||
port 5222, S2S on port 5269 and that service <TT>conference.jabber.org</TT>
|
||||
must be connected to port 8888 with password ``<TT>secret</TT>''.<BR>
|
||||
@ -171,15 +171,13 @@ Example:
|
||||
{access, configure, [{allow, admin}]}.
|
||||
{access, something, [{deny, badmans},
|
||||
{allow, all}]}.
|
||||
</PRE>TBD<BR>
|
||||
<BR>
|
||||
<!--TOC subsubsection Modules-->
|
||||
</PRE><!--TOC subsubsection Modules-->
|
||||
|
||||
<H4>3.1.4 Modules</H4><!--SEC END -->
|
||||
|
||||
<A NAME="sec:configmodules"></A>Option <TT>modules</TT> defines list of modules that will be loaded after
|
||||
<TT>ejabberd</TT> startup. Each list element is a tuple where first element is a
|
||||
name of module and second is list of options to this module. Refer to
|
||||
name of module and second is list of options to this module. See
|
||||
section <A HREF="#sec:modules">5</A> for detailed information on each module.<BR>
|
||||
<BR>
|
||||
Example:
|
||||
@ -205,7 +203,7 @@ Example:
|
||||
<TT>mod_configure</TT> loaded (see section <A HREF="#sec:modconfigure">5.4</A>). Also highly
|
||||
recommended to load <TT>mod_disco</TT> (see section <A HREF="#sec:moddisco">5.5</A>), because
|
||||
<TT>mod_configure</TT> highly integrates with it. Also recommended to use
|
||||
disco-capable client.<BR>
|
||||
disco- and xdata-capable client.<BR>
|
||||
<BR>
|
||||
TBD<BR>
|
||||
<BR>
|
||||
|
@ -30,7 +30,7 @@
|
||||
\author{Alexey Shchepin \\
|
||||
\ahrefurl{mailto:alexey@sevcom.net} \\
|
||||
\ahrefurl{xmpp:aleksey@jabber.ru}}
|
||||
\date{January 23, 2003}
|
||||
\date{January 26, 2003}
|
||||
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
@ -78,7 +78,7 @@ To compile \ejabberd{}, you need following packages:
|
||||
|
||||
Currently no stable version released.
|
||||
|
||||
Latest alpha version can be retrieved via CVS. Do following steps:
|
||||
Latest alpha version can be retrieved via CVS\@. Do following steps:
|
||||
\begin{itemize}
|
||||
\item \texttt{export CVSROOT=:pserver:cvs@www.jabber.ru:/var/spool/cvs}
|
||||
\item \texttt{cvs login}
|
||||
@ -119,7 +119,7 @@ values.
|
||||
\label{sec:confighostname}
|
||||
|
||||
Option \texttt{hostname} defines name of \Jabber{} domain that \ejabberd{}
|
||||
serves. E.\,g. to use \texttt{jabber.org} domain add following line in config:
|
||||
serves. E.\,g.\ to use \texttt{jabber.org} domain add following line in config:
|
||||
\begin{verbatim}
|
||||
{host, "jabber.org"}.
|
||||
\end{verbatim}
|
||||
@ -144,8 +144,8 @@ Currently three modules implemented:
|
||||
\begin{itemize}
|
||||
\item \texttt{ejabberd\_c2s}: serves C2S connections;
|
||||
\item \texttt{ejabberd\_s2s\_in}: serves incoming S2S connections;
|
||||
\item \texttt{ejabberd\_service}: serves connections to \Jabber{} services (i.e.
|
||||
that use \texttt{jabber:component:accept} namespace).
|
||||
\item \texttt{ejabberd\_service}: serves connections to \Jabber{} services
|
||||
(i.\,e.\ that use \texttt{jabber:component:accept} namespace).
|
||||
\end{itemize}
|
||||
|
||||
For example, following configuration defines that C2S connections listened on
|
||||
@ -218,7 +218,7 @@ Example:
|
||||
|
||||
Option \texttt{modules} defines list of modules that will be loaded after
|
||||
\ejabberd{} startup. Each list element is a tuple where first element is a
|
||||
name of module and second is list of options to this module. Refer to
|
||||
name of module and second is list of options to this module. See
|
||||
section~\ref{sec:modules} for detailed information on each module.
|
||||
|
||||
Example:
|
||||
@ -246,7 +246,7 @@ To use facility of online reconfiguration of \ejabberd{} needed to have
|
||||
\modconfigure{} loaded (see section~\ref{sec:modconfigure}). Also highly
|
||||
recommended to load \moddisco{} (see section~\ref{sec:moddisco}), because
|
||||
\modconfigure{} highly integrates with it. Also recommended to use
|
||||
disco-capable client.
|
||||
disco- and xdata-capable client.
|
||||
|
||||
TBD
|
||||
|
||||
@ -258,12 +258,12 @@ TBD
|
||||
\label{sec:howitworks}
|
||||
|
||||
\Jabber{} domain is served by one or more \ejabberd{} nodes. This nodes can be
|
||||
runned on different computers that can be connected via network. They all must
|
||||
runned on different machines that can be connected via network. They all must
|
||||
have access to connect to port 4369 of all another nodes, and must have same
|
||||
magic cookie (see Erlang/OTP documentation, in short file
|
||||
\texttt{\~ejabberd/.erlang.cookie} must be the same on all nodes). This is
|
||||
needed because all nodes exchange information about connected users, S2S
|
||||
connection ,registered services, etc...
|
||||
connection, registered services, etc\ldots
|
||||
|
||||
Each \ejabberd{} node run following modules:
|
||||
\begin{itemize}
|
||||
@ -322,7 +322,7 @@ Following options used by many modules, so they described in separate section.
|
||||
\subsubsection{Option \texttt{iqdisc}}
|
||||
|
||||
Many modules define handlers for processing IQ queries of different namespaces
|
||||
to this server or to user (e.\,g. to \texttt{myjabber.org} or to
|
||||
to this server or to user (e.\,g.\ to \texttt{myjabber.org} or to
|
||||
\texttt{user@myjabber.org}). This option defines processing discipline of this
|
||||
queries. Possible values are:
|
||||
\begin{description}
|
||||
|
@ -19,6 +19,9 @@ start() ->
|
||||
|
||||
init() ->
|
||||
register(ejabberd, self()),
|
||||
% Profiling
|
||||
%eprof:start(),
|
||||
%eprof:profile([self()]),
|
||||
%erlang:system_flag(fullsweep_after, 0),
|
||||
error_logger:logfile({open, ?ERROR_LOG_PATH}),
|
||||
randoms:start(),
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
-define(VERSION, "0.0.1-alpha").
|
||||
|
||||
%-define(ejabberd_debug, true).
|
||||
%-define(DBGFSM, true).
|
||||
-define(ejabberd_debug, true).
|
||||
-define(DBGFSM, true).
|
||||
|
||||
-ifdef(ejabberd_debug).
|
||||
-define(DEBUG(Format, Args), io:format("D(~p:~p:~p) : "++Format++"~n",
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
%-define(MYNAME,"e.localhost").
|
||||
-define(MYNAME, ejabberd_config:get_global_option(host)).
|
||||
-define(S2STIMEOUT, 1200000).
|
||||
|
||||
-define(MSGS_DIR, "msgs").
|
||||
-define(CONFIG_PATH, "ejabberd.cfg").
|
||||
|
@ -23,7 +23,8 @@
|
||||
try_register/2,
|
||||
dirty_get_registered_users/0,
|
||||
get_password_s/1,
|
||||
is_user_exists/1]).
|
||||
is_user_exists/1,
|
||||
remove_user/1]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1,
|
||||
@ -198,3 +199,10 @@ is_user_exists(User) ->
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
remove_user(User) ->
|
||||
LUser = jlib:tolower(User),
|
||||
F = fun() ->
|
||||
mnesia:delete({passwd, LUser})
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
@ -106,18 +106,6 @@ have_connection(FromTo) ->
|
||||
false
|
||||
end.
|
||||
|
||||
%get_key(FromTo) ->
|
||||
% F = fun() ->
|
||||
% [E] = mnesia:read({s2s, FromTo}),
|
||||
% E
|
||||
% end,
|
||||
% case mnesia:transaction(F) of
|
||||
% {atomic, E} ->
|
||||
% E#s2s.key;
|
||||
% _ ->
|
||||
% ""
|
||||
% end.
|
||||
|
||||
get_key(FromTo) ->
|
||||
case catch mnesia:dirty_read(s2s, FromTo) of
|
||||
[E] ->
|
||||
@ -159,24 +147,7 @@ do_route(From, To, Packet) ->
|
||||
{User, Server, Resource} = To,
|
||||
FromTo = {MyServer, Server},
|
||||
Key = randoms:get_string(),
|
||||
F = fun() ->
|
||||
case mnesia:read({local_s2s, FromTo}) of
|
||||
[] ->
|
||||
case mnesia:read({s2s, FromTo}) of
|
||||
[Er] ->
|
||||
{remote, Er#s2s.node};
|
||||
[] ->
|
||||
% TODO
|
||||
mnesia:write(#s2s{fromto = FromTo,
|
||||
node = node(),
|
||||
key = Key}),
|
||||
new
|
||||
end;
|
||||
[El] ->
|
||||
{local, El#local_s2s.pid}
|
||||
end
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
case find_connection(FromTo, Key) of
|
||||
{atomic, {local, Pid}} ->
|
||||
?DEBUG("sending to process ~p~n", [Pid]),
|
||||
% TODO
|
||||
@ -211,6 +182,38 @@ do_route(From, To, Packet) ->
|
||||
false
|
||||
end.
|
||||
|
||||
find_connection(FromTo, Key) ->
|
||||
F = fun() ->
|
||||
case mnesia:read({local_s2s, FromTo}) of
|
||||
[] ->
|
||||
case mnesia:read({s2s, FromTo}) of
|
||||
[Er] ->
|
||||
{remote, Er#s2s.node};
|
||||
[] ->
|
||||
mnesia:write(#s2s{fromto = FromTo,
|
||||
node = node(),
|
||||
key = Key}),
|
||||
new
|
||||
end;
|
||||
[El] ->
|
||||
{local, El#local_s2s.pid}
|
||||
end
|
||||
end,
|
||||
case catch mnesia:dirty_read({local_s2s, FromTo}) of
|
||||
{'EXIT', Reason} ->
|
||||
{aborted, Reason};
|
||||
[] ->
|
||||
case catch mnesia:dirty_read({s2s, FromTo}) of
|
||||
[Er] ->
|
||||
{atomic, {remote, Er#s2s.node}};
|
||||
[] ->
|
||||
mnesia:transaction(F)
|
||||
end;
|
||||
[El] ->
|
||||
{atomic, {local, El#local_s2s.pid}}
|
||||
end.
|
||||
|
||||
|
||||
send_element(Pid, El) ->
|
||||
Pid ! {send_element, El}.
|
||||
|
||||
|
@ -250,12 +250,15 @@ stream_established({xmlstreamelement, El}, StateData) ->
|
||||
error
|
||||
end
|
||||
end,
|
||||
{next_state, stream_established, StateData};
|
||||
{next_state, stream_established, StateData, ?S2STIMEOUT};
|
||||
|
||||
stream_established({xmlstreamend, Name}, StateData) ->
|
||||
% TODO
|
||||
{stop, normal, StateData};
|
||||
|
||||
stream_established(timeout, StateData) ->
|
||||
{stop, normal, StateData};
|
||||
|
||||
stream_established(closed, StateData) ->
|
||||
% TODO
|
||||
{stop, normal, StateData}.
|
||||
|
@ -175,7 +175,7 @@ wait_for_validation({xmlstreamelement, El}, StateData) ->
|
||||
case Type of
|
||||
"valid" ->
|
||||
send_queue(StateData#state.socket, StateData#state.queue),
|
||||
{next_state, stream_established, StateData};
|
||||
{next_state, stream_established, StateData, ?S2STIMEOUT};
|
||||
_ ->
|
||||
% TODO: bounce packets
|
||||
{stop, normal, StateData}
|
||||
@ -212,6 +212,7 @@ wait_for_validation(closed, StateData) ->
|
||||
|
||||
|
||||
stream_established({xmlstreamelement, El}, StateData) ->
|
||||
io:format("s2s out~n"),
|
||||
case is_verify_res(El) of
|
||||
{verify, VTo, VFrom, VId, VType} ->
|
||||
case StateData#state.verify of
|
||||
@ -228,36 +229,36 @@ stream_established({xmlstreamelement, El}, StateData) ->
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
{xmlelement, Name, Attrs, Els} = El,
|
||||
% TODO
|
||||
From = xml:get_attr_s("from", Attrs),
|
||||
FromJID1 = jlib:string_to_jid(From),
|
||||
FromJID = case FromJID1 of
|
||||
{Node, Server, Resource} ->
|
||||
if Server == StateData#state.server -> FromJID1;
|
||||
true -> error
|
||||
end;
|
||||
_ -> error
|
||||
end,
|
||||
To = xml:get_attr_s("to", Attrs),
|
||||
ToJID = case To of
|
||||
"" -> error;
|
||||
_ -> jlib:string_to_jid(To)
|
||||
end,
|
||||
if ((Name == "iq") or (Name == "message") or (Name == "presence")) and
|
||||
(ToJID /= error) and (FromJID /= error) ->
|
||||
ejabberd_router:route(FromJID, ToJID, El);
|
||||
true ->
|
||||
error
|
||||
end,
|
||||
{next_state, stream_established, StateData};
|
||||
%{xmlelement, Name, Attrs, Els} = El,
|
||||
%From = xml:get_attr_s("from", Attrs),
|
||||
%FromJID1 = jlib:string_to_jid(From),
|
||||
%FromJID = case FromJID1 of
|
||||
% {Node, Server, Resource} ->
|
||||
% if Server == StateData#state.server -> FromJID1;
|
||||
% true -> error
|
||||
% end;
|
||||
% _ -> error
|
||||
% end,
|
||||
%To = xml:get_attr_s("to", Attrs),
|
||||
%ToJID = case To of
|
||||
% "" -> error;
|
||||
% _ -> jlib:string_to_jid(To)
|
||||
% end,
|
||||
%if ((Name == "iq") or (Name == "message") or (Name == "presence")) and
|
||||
% (ToJID /= error) and (FromJID /= error) ->
|
||||
% ejabberd_router:route(FromJID, ToJID, El);
|
||||
% true ->
|
||||
% error
|
||||
%end,
|
||||
{next_state, stream_established, StateData, ?S2STIMEOUT};
|
||||
|
||||
stream_established({xmlstreamend, Name}, StateData) ->
|
||||
% TODO
|
||||
{stop, normal, StateData};
|
||||
|
||||
stream_established(timeout, StateData) ->
|
||||
{stop, normal, StateData};
|
||||
|
||||
stream_established(closed, StateData) ->
|
||||
% TODO
|
||||
{stop, normal, StateData}.
|
||||
|
||||
|
||||
|
31
src/jlib.erl
31
src/jlib.erl
@ -211,13 +211,32 @@ is_nodename1([]) ->
|
||||
|
||||
|
||||
% TODO: UNICODE support
|
||||
tolower_c(C) when C >= $A, C =< $Z ->
|
||||
C + 32;
|
||||
tolower_c(C) ->
|
||||
C.
|
||||
%tolower_c(C) when C >= $A, C =< $Z ->
|
||||
% C + 32;
|
||||
%tolower_c(C) ->
|
||||
% C.
|
||||
|
||||
tolower(S) ->
|
||||
lists:map(fun tolower_c/1, S).
|
||||
-define(LOWER(Char),
|
||||
if
|
||||
Char >= $A, Char =< $Z ->
|
||||
Char + 32;
|
||||
true ->
|
||||
Char
|
||||
end).
|
||||
|
||||
%tolower(S) ->
|
||||
% lists:map(fun tolower_c/1, S).
|
||||
|
||||
%tolower(S) ->
|
||||
% [?LOWER(Char) || Char <- S].
|
||||
|
||||
% Not tail-recursive but it seems works faster than variants above
|
||||
tolower([C | Cs]) when C >= $A, C =< $Z ->
|
||||
[C + 32 | tolower(Cs)];
|
||||
tolower([C | Cs]) ->
|
||||
[C | tolower(Cs)];
|
||||
tolower([]) ->
|
||||
[].
|
||||
|
||||
|
||||
jid_tolower({U, S, R}) ->
|
||||
|
@ -202,6 +202,25 @@ get_form(["config", "acls"], Lang) ->
|
||||
}
|
||||
]};
|
||||
|
||||
get_form(["config", "remusers"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Remove Users")}]},
|
||||
{xmlelement, "instructions", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Choose users to remove")}]}] ++
|
||||
case catch ejabberd_auth:dirty_get_registered_users() of
|
||||
{'EXIT', Reason} ->
|
||||
[];
|
||||
Users ->
|
||||
lists:map(fun(U) ->
|
||||
?XFIELD("boolean", U, U, "0")
|
||||
end, lists:sort(Users))
|
||||
end
|
||||
};
|
||||
|
||||
get_form(_, Lang) ->
|
||||
{error, "503", "Service Unavailable"}.
|
||||
|
||||
@ -254,6 +273,21 @@ set_form(["config", "hostname"], Lang, XData) ->
|
||||
{error, "406", "Not Acceptable"}
|
||||
end;
|
||||
|
||||
set_form(["config", "remusers"], Lang, XData) ->
|
||||
lists:foreach(
|
||||
fun({Var, Vals}) ->
|
||||
case Vals of
|
||||
["1"] ->
|
||||
catch ejabberd_auth:remove_user(Var),
|
||||
catch mod_roster:remove_user(Var),
|
||||
catch mod_offline:remove_user(Var),
|
||||
catch mod_vcard:remove_user(Var);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end, XData),
|
||||
{result, []};
|
||||
|
||||
set_form(_, Lang, XData) ->
|
||||
{error, "503", "Service Unavailable"}.
|
||||
|
||||
|
@ -160,7 +160,8 @@ get_local_items(["config"], Server, Lang) ->
|
||||
[?NODE("Host Name", "config/hostname"),
|
||||
?NODE("ACLs", "config/acls"),
|
||||
?NODE("Access Rules", "config/access"),
|
||||
?NODE("Loaded Modules", "config/modules")
|
||||
?NODE("Loaded Modules", "config/modules"),
|
||||
?NODE("Remove Users", "config/remusers")
|
||||
]};
|
||||
|
||||
get_local_items(["config", _], Server, Lang) ->
|
||||
|
@ -13,7 +13,8 @@
|
||||
|
||||
-export([start/1,
|
||||
store_packet/3,
|
||||
resend_offline_messages/1]).
|
||||
resend_offline_messages/1,
|
||||
remove_user/1]).
|
||||
|
||||
-include("namespaces.hrl").
|
||||
|
||||
@ -115,3 +116,10 @@ resend_offline_messages(User) ->
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
remove_user(User) ->
|
||||
LUser = jlib:tolower(User),
|
||||
F = fun() ->
|
||||
mnesia:delete({offline_msg, LUser})
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
@ -17,7 +17,8 @@
|
||||
process_local_iq/3,
|
||||
get_subscription_lists/1,
|
||||
in_subscription/3,
|
||||
out_subscription/3]).
|
||||
out_subscription/3,
|
||||
remove_user/1]).
|
||||
|
||||
-include_lib("mnemosyne/include/mnemosyne.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
@ -459,3 +460,13 @@ out_subscription(User, JID, Type) ->
|
||||
false
|
||||
end.
|
||||
|
||||
remove_user(User) ->
|
||||
LUser = jlib:tolower(User),
|
||||
F = fun() ->
|
||||
lists:foreach(fun(R) ->
|
||||
mnesia:delete_object(R)
|
||||
end,
|
||||
mnesia:index_read(roster, LUser, #roster.user))
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
-export([start/1, init/1,
|
||||
process_local_iq/3,
|
||||
process_sm_iq/3,
|
||||
reindex_vcards/0]).
|
||||
reindex_vcards/0,
|
||||
remove_user/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("namespaces.hrl").
|
||||
@ -478,3 +479,16 @@ reindex_vcards() ->
|
||||
mnesia:transaction(F).
|
||||
|
||||
|
||||
remove_user(User) ->
|
||||
LUser = jlib:tolower(User),
|
||||
F = fun() ->
|
||||
mnesia:delete({vcard, LUser}),
|
||||
lists:foreach(fun(R) ->
|
||||
mnesia:delete_object(R)
|
||||
end,
|
||||
mnesia:index_read(vcard_search,
|
||||
LUser,
|
||||
#vcard_search.luser))
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
|
65
src/xml.erl
65
src/xml.erl
@ -10,7 +10,9 @@
|
||||
-author('alexey@sevcom.net').
|
||||
-vsn('$Revision$ ').
|
||||
|
||||
-export([element_to_string/1, crypt/1, remove_cdata/1,
|
||||
-export([element_to_string/1,
|
||||
crypt/1,
|
||||
remove_cdata/1,
|
||||
get_cdata/1, get_tag_cdata/1,
|
||||
get_attr/2, get_attr_s/2,
|
||||
get_tag_attr/2, get_tag_attr_s/2,
|
||||
@ -38,24 +40,51 @@ attrs_to_string(Attrs) ->
|
||||
attr_to_string({Name, Value}) ->
|
||||
" " ++ crypt(Name) ++ "='" ++ crypt(Value) ++ "'".
|
||||
|
||||
crypt(S) ->
|
||||
lists:reverse(crypt(S, "")).
|
||||
%crypt(S) ->
|
||||
% lists:reverse(crypt(S, "")).
|
||||
%
|
||||
%crypt([$& | S], R) ->
|
||||
% crypt(S, [$;, $p, $m, $a, $& | R]);
|
||||
%crypt([$< | S], R) ->
|
||||
% crypt(S, [$;, $t, $l, $& | R]);
|
||||
%crypt([$> | S], R) ->
|
||||
% crypt(S, [$;, $t, $g, $& | R]);
|
||||
%crypt([$" | S], R) ->
|
||||
% crypt(S, [$;, $t, $o, $u, $q, $& | R]);
|
||||
%crypt([$' | S], R) ->
|
||||
% crypt(S, [$;, $s, $o, $p, $a, $& | R]);
|
||||
%crypt([C | S], R) ->
|
||||
% crypt(S, [C | R]);
|
||||
%crypt([], R) ->
|
||||
% R.
|
||||
|
||||
crypt([$& | S], R) ->
|
||||
crypt(S, [$;, $p, $m, $a, $& | R]);
|
||||
crypt([$< | S], R) ->
|
||||
crypt(S, [$;, $t, $l, $& | R]);
|
||||
crypt([$> | S], R) ->
|
||||
crypt(S, [$;, $t, $g, $& | R]);
|
||||
crypt([$" | S], R) ->
|
||||
crypt(S, [$;, $t, $o, $u, $q, $& | R]);
|
||||
crypt([$' | S], R) ->
|
||||
crypt(S, [$;, $s, $o, $p, $a, $& | R]);
|
||||
crypt([C | S], R) ->
|
||||
crypt(S, [C | R]);
|
||||
crypt([], R) ->
|
||||
R.
|
||||
|
||||
%crypt1(S) ->
|
||||
% lists:flatten([case C of
|
||||
% $& -> "&";
|
||||
% $< -> "<";
|
||||
% $> -> ">";
|
||||
% $" -> """;
|
||||
% $' -> "'";
|
||||
% _ -> C
|
||||
% end || C <- S]).
|
||||
|
||||
% Not tail-recursive but it seems works faster than variants above
|
||||
crypt([$& | S]) ->
|
||||
[$&, $a, $m, $p, $; | crypt(S)];
|
||||
crypt([$< | S]) ->
|
||||
[$&, $l, $t, $; | crypt(S)];
|
||||
crypt([$> | S]) ->
|
||||
[$&, $g, $t, $; | crypt(S)];
|
||||
crypt([$" | S]) ->
|
||||
[$&, $q, $u, $o, $t, $; | crypt(S)];
|
||||
crypt([$' | S]) ->
|
||||
[$&, $a, $p, $o, $s, $; | crypt(S)];
|
||||
crypt([C | S]) ->
|
||||
[C | crypt(S)];
|
||||
crypt([]) ->
|
||||
[].
|
||||
|
||||
|
||||
|
||||
remove_cdata_p({xmlelement, Name, Attrs, Els}) -> true;
|
||||
remove_cdata_p(_) -> false.
|
||||
|
Loading…
Reference in New Issue
Block a user