diff --git a/ChangeLog b/ChangeLog index 802c3d3c9..69326c261 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2003-07-20 Alexey Shchepin + + * (all): Reorganized supervision tree + +2003-07-19 Alexey Shchepin + + * src/mod_register.erl: Bugfix + 2003-07-14 Alexey Shchepin * src/ejabberd_s2s_out.erl: Close connection after key diff --git a/src/ejabberd.app b/src/ejabberd.app index 231af035d..02b111181 100644 --- a/src/ejabberd.app +++ b/src/ejabberd.app @@ -4,7 +4,12 @@ [{description, "ejabberd"}, {vsn, "0.1-alpha"}, {modules, [acl, + configure, + cyrsasl, + cyrsasl_digest, + cyrsasl_plain, ejabberd, + ejabberd_app, ejabberd_auth, ejabberd_c2s, ejabberd_config, @@ -16,6 +21,11 @@ ejabberd_s2s_out, ejabberd_service, ejabberd_sm, + ejabberd_sup, + ejabberd_tmp_sup, + gen_iq_handler, + gen_mod, + jd2ejd, jlib, mod_configure, mod_disco, @@ -30,18 +40,31 @@ mod_version, randoms, sha, + shaper, translate, xml, xml_stream ]}, {registered, [ejabberd, + ejabberd_sup, ejabberd_auth, ejabberd_router, ejabberd_sm, ejabberd_s2s, ejabberd_local, + ejabberd_listeners, + ejabberd_iq_sup, + ejabberd_service_sup, + ejabberd_s2s_out_sup, + ejabberd_s2s_in_sup, + ejabberd_c2s_sup, ejabberd_mod_roster, - ejabberd_listeners + ejabberd_mod_echo, + ejabberd_mod_pubsub, + ejabberd_mod_irc, + ejabberd_mod_muc, + ejabberd_offline, + random_generator ]}, {applications, [kernel, stdlib]}, {env, []}, diff --git a/src/ejabberd.erl b/src/ejabberd.erl index b3de91eb2..3deda9a57 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -13,7 +13,6 @@ -export([start/0, stop/0]). start() -> - %application:start(mnesia), application:start(ejabberd). stop() -> diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 87cfb486f..c9ae60e49 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -19,6 +19,7 @@ -include("ejabberd.hrl"). start(normal, Args) -> + application:start(sasl), randoms:start(), db_init(), sha:start(), @@ -29,6 +30,9 @@ start(normal, Args) -> ejabberd_config:start(), ejabberd_auth:start(), cyrsasl:start(), + % Profiling + %eprof:start(), + %eprof:profile([self()]), Sup = ejabberd_sup:start_link(), start(), load_modules(), @@ -40,13 +44,10 @@ stop(StartArgs) -> ok. start() -> - spawn(?MODULE, init, []). + spawn_link(?MODULE, init, []). init() -> register(ejabberd, self()), - % Profiling - %eprof:start(), - %eprof:profile([self()]), %erlang:system_flag(fullsweep_after, 0), error_logger:logfile({open, ?LOG_PATH}), timer:apply_interval(3600000, ?MODULE, dump_ports, []), diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index b8ccc1efb..103fc1d3d 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -13,7 +13,11 @@ -behaviour(gen_fsm). %% External exports --export([start_link/2, receiver/4, send_text/2, send_element/2]). +-export([start/2, + start_link/2, + receiver/4, + send_text/2, + send_element/2]). %% gen_fsm callbacks -export([init/1, @@ -77,6 +81,9 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- +start(SockData, Opts) -> + supervisor:start_child(ejabberd_c2s_sup, [SockData, Opts]). + start_link(SockData, Opts) -> gen_fsm:start_link(ejabberd_c2s, [SockData, Opts], ?FSMOPTS). @@ -430,14 +437,15 @@ wait_for_session(closed, StateData) -> session_established({xmlstreamelement, El}, StateData) -> {xmlelement, Name, Attrs, Els} = El, + User = StateData#state.user, Server = StateData#state.server, - FromJID = {StateData#state.user, + FromJID = {User, Server, StateData#state.resource}, To = xml:get_attr_s("to", Attrs), ToJID = case To of "" -> - {"", Server, ""}; + {User, Server, ""}; _ -> jlib:string_to_jid(To) end, @@ -450,7 +458,7 @@ session_established({xmlstreamelement, El}, StateData) -> case Name of "presence" -> case ToJID of - {"", Server, ""} -> + {User, Server, ""} -> ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", [FromJID, El, StateData]), presence_update(FromJID, El, StateData); diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 049850600..916cb224e 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -32,7 +32,7 @@ init(_) -> permanent, brutal_kill, worker, - [Module]} + [?MODULE]} end, Ls)}} end. @@ -56,7 +56,16 @@ init(Port, Module, Opts) -> accept(ListenSocket, Module, Opts) -> case gen_tcp:accept(ListenSocket) of {ok, Socket} -> - {ok, Pid} = apply(Module, start_link, [{gen_tcp, Socket}, Opts]), + {ok, Pid} = Module:start({gen_tcp, Socket}, Opts), + %{ok, Pid} = + % supervisor:start_child( + % ejabberd_tmp_sup, + % {{Module, Socket}, + % {Module, start_link, [{gen_tcp, Socket}, Opts]}, + % transient, + % brutal_kill, + % worker, + % [Module]}), gen_tcp:controlling_process(Socket, Pid), accept(ListenSocket, Module, Opts) end. diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 5f2a388ec..b5b893b19 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -168,7 +168,7 @@ do_route(From, To, Packet) -> ok; {atomic, new} -> ?DEBUG("starting new s2s connection~n", []), - Pid = ejabberd_s2s_out:start_link(MyServer, Server, {new, Key}), + {ok, Pid} = ejabberd_s2s_out:start(MyServer, Server, {new, Key}), mnesia:transaction(fun() -> mnesia:write(#local_s2s{fromto = FromTo, pid = Pid}) diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 0cc200f58..a7e18540c 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -13,7 +13,7 @@ -behaviour(gen_fsm). %% External exports --export([start_link/2, receiver/2, send_text/2, send_element/2]). +-export([start/2, start_link/2, receiver/2, send_text/2, send_element/2]). %% gen_fsm callbacks -export([init/1, @@ -63,6 +63,9 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- +start(SockData, Opts) -> + supervisor:start_child(ejabberd_s2s_in_sup, [SockData, Opts]). + start_link(SockData, Opts) -> gen_fsm:start_link(ejabberd_s2s_in, [SockData], ?FSMOPTS). @@ -134,8 +137,8 @@ wait_for_key({xmlstreamelement, El}, StateData) -> ?INFO_MSG("GET KEY: ~p", [{To, From, Id, Key}]), case lists:member(To, ejabberd_router:dirty_get_all_domains()) of true -> - ejabberd_s2s_out:start_link(To, From, - {verify, self(), Key}), + ejabberd_s2s_out:start(To, From, + {verify, self(), Key}), {next_state, wait_for_verification, StateData#state{myname = To, diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 6efa7782f..e49a00e6e 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -13,7 +13,7 @@ -behaviour(gen_fsm). %% External exports --export([start_link/3, send_text/2, send_element/2]). +-export([start/3, start_link/3, send_text/2, send_element/2]). %% gen_fsm callbacks -export([init/1, @@ -65,10 +65,11 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- +start(From, Host, Type) -> + supervisor:start_child(ejabberd_s2s_out_sup, [From, Host, Type]). + start_link(From, Host, Type) -> - {ok, Pid} = gen_fsm:start_link(ejabberd_s2s_out, [From, Host, Type], - ?FSMOPTS), - Pid. + gen_fsm:start_link(ejabberd_s2s_out, [From, Host, Type], ?FSMOPTS). %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 87c4245be..cc73bf221 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -13,7 +13,7 @@ -behaviour(gen_fsm). %% External exports --export([start_link/2, receiver/2, send_text/2, send_element/2]). +-export([start/2, start_link/2, receiver/2, send_text/2, send_element/2]). %% gen_fsm callbacks -export([init/1, @@ -69,6 +69,9 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- +start(SockData, Opts) -> + supervisor:start_child(ejabberd_service_sup, [SockData, Opts]). + start_link(SockData, Opts) -> gen_fsm:start_link(ejabberd_service, [SockData, Opts], ?FSMOPTS). diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 584cb0b61..865ed89dc 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -46,9 +46,55 @@ init([]) -> Listener = {ejabberd_listener, {ejabberd_listener, start_link, []}, permanent, - brutal_kill, + infinity, supervisor, [ejabberd_listener]}, - {ok, {{one_for_one, 10, 1}, [Router, SM, S2S, Local, Listener]}}. + C2SSupervisor = + {ejabberd_c2s_sup, + {ejabberd_tmp_sup, start_link, [ejabberd_c2s_sup, ejabberd_c2s]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, + S2SInSupervisor = + {ejabberd_s2s_in_sup, + {ejabberd_tmp_sup, start_link, + [ejabberd_s2s_in_sup, ejabberd_s2s_in]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, + S2SOutSupervisor = + {ejabberd_s2s_out_sup, + {ejabberd_tmp_sup, start_link, + [ejabberd_s2s_out_sup, ejabberd_s2s_out]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, + ServiceSupervisor = + {ejabberd_service_sup, + {ejabberd_tmp_sup, start_link, + [ejabberd_service_sup, ejabberd_service]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, + IQSupervisor = + {ejabberd_iq_sup, + {ejabberd_tmp_sup, start_link, + [ejabberd_iq_sup, gen_iq_handler]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, + {ok, {{one_for_one, 10, 1}, + [Router, SM, S2S, Local, + C2SSupervisor, + S2SInSupervisor, + S2SOutSupervisor, + ServiceSupervisor, + IQSupervisor, + Listener]}}. diff --git a/src/ejabberd_tmp_sup.erl b/src/ejabberd_tmp_sup.erl new file mode 100644 index 000000000..357bdd67a --- /dev/null +++ b/src/ejabberd_tmp_sup.erl @@ -0,0 +1,22 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_tmp_sup.erl +%%% Author : Alexey Shchepin +%%% Purpose : Supervisor for temporary processess +%%% Created : 18 Jul 2003 by Alexey Shchepin +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(ejabberd_tmp_sup). +-author('alexey@sevcom.net'). +-vsn('$Revision$ '). + +-export([start_link/2, init/1]). + +start_link(Name, Module) -> + supervisor:start_link({local, Name}, ?MODULE, Module). + + +init(Module) -> + {ok, {{simple_one_for_one, 10, 1}, + [{undefined, {Module, start_link, []}, + temporary, brutal_kill, worker, [Module]}]}}. diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 3bdeeee4c..c9559628c 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -11,6 +11,7 @@ -vsn('$Revision$ '). -export([start/0, + start_link/2, add_iq_handler/5, remove_iq_handler/2, stop_iq_handler/3, @@ -28,7 +29,8 @@ add_iq_handler(Component, NS, Module, Function, Type) -> no_queue -> Component:register_iq_handler(NS, Module, Function, no_queue); one_queue -> - Pid = spawn(?MODULE, queue_init, [Module, Function]), + {ok, Pid} = supervisor:start_child(ejabberd_iq_sup, + [Module, Function]), Component:register_iq_handler(NS, Module, Function, {one_queue, Pid}); parallel -> @@ -73,6 +75,9 @@ process_iq(Module, Function, From, To, IQ) -> end end. +start_link(Module, Function) -> + {ok, proc_lib:spawn_link(?MODULE, queue_init, [Module, Function])}. + queue_init(Module, Function) -> queue_loop(Module, Function). diff --git a/src/jlib.erl b/src/jlib.erl index 91fd5f076..4992bb516 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -238,13 +238,24 @@ is_nodename1([]) -> % [?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)]; + if + C >= $A, C =< $Z -> + [C + 32 | tolower(Cs)]; + true -> + [C | tolower(Cs)] + end; tolower([]) -> []. +%tolower([C | Cs]) when C >= $A, C =< $Z -> +% [C + 32 | tolower(Cs)]; +%tolower([C | Cs]) -> +% [C | tolower(Cs)]; +%tolower([]) -> +% []. + + jid_tolower({U, S, R}) -> {tolower(U), tolower(S), R}. diff --git a/src/mod_private.erl b/src/mod_private.erl index ca320a7a7..fa043122b 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -26,7 +26,7 @@ start(Opts) -> mnesia:create_table(private_storage, [{disc_only_copies, [node()]}, {attributes, record_info(fields, private_storage)}]), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_PRIVATE, + gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_PRIVATE, ?MODULE, process_local_iq, IQDisc). stop() -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 6fe5a9bf2..ce0fb81f0 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -13,12 +13,12 @@ -behaviour(gen_mod). -export([start/1, - init/2, + init/3, + loop/2, stop/0, - % TODO: remove - create_new_node/3, - publish_item/5, - delete_item/4]). + system_continue/3, + system_terminate/4, + system_code_change/4]). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -43,11 +43,12 @@ start(Opts) -> mnesia:add_table_index(pubsub_node, parent), Host = gen_mod:get_opt(host, Opts, "pubsub." ++ ?MYNAME), ServedHosts = gen_mod:get_opt(served_hosts, Opts, [?MYNAME]), - register(ejabberd_mod_pubsub, spawn(?MODULE, init, [Host, ServedHosts])). + register(ejabberd_mod_pubsub, + proc_lib:spawn_link(?MODULE, init, [Host, ServedHosts, self()])). -init(Host, ServedHosts) -> +init(Host, ServedHosts, Parent) -> ejabberd_router:register_route(Host), create_new_node(Host, ["pubsub"], {"", Host, ""}), create_new_node(Host, ["pubsub", "nodes"], {"", Host, ""}), @@ -55,9 +56,9 @@ init(Host, ServedHosts) -> lists:foreach(fun(H) -> create_new_node(Host, ["home", H], {"", Host, ""}) end, ServedHosts), - loop(Host). + loop(Host, Parent). -loop(Host) -> +loop(Host, Parent) -> receive {route, From, To, Packet} -> case catch do_route(Host, From, To, Packet) of @@ -66,17 +67,19 @@ loop(Host) -> _ -> ok end, - loop(Host); + loop(Host, Parent); {room_destroyed, Room} -> ets:delete(muc_online_room, Room), - loop(Host); + loop(Host, Parent); stop -> ejabberd_router:unregister_global_route(Host), ok; reload -> - ?MODULE:loop(Host); + ?MODULE:loop(Host, Parent); + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, ?MODULE, [], Host); _ -> - loop(Host) + loop(Host, Parent) end. @@ -450,7 +453,9 @@ iq_pubsub(Host, From, Type, SubEl) -> create_new_node(Host, Node, Owner) -> case Node of [] -> - {error, ?ERR_CONFLICT}; + {LOU, LOS, _} = jlib:jid_tolower(Owner), + NewNode = ["home", LOS, LOU, randoms:get_string()], + create_new_node(Host, NewNode, Owner); _ -> LOwner = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), Parent = lists:sublist(Node, length(Node) - 1), @@ -491,16 +496,20 @@ create_new_node(Host, Node, Owner) -> {atomic, ok} -> Lang = "", broadcast_publish_item( - Host, ["pubsub", "nodes"], "", + Host, ["pubsub", "nodes"], node_to_string(Node), [{xmlelement, "x", - [{"xmlns", ?NS_PUBSUB_EVENT}, + [{"xmlns", ?NS_XDATA}, {"type", "result"}], [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NMI), ?XFIELD("jid-single", "Node Creator", "creator", jlib:jid_to_string(LOwner))]}]), - {result, []}; + {result, + [{xmlelement, "pubsub", + [{"xmlns", ?NS_PUBSUB}], + [{xmlelement, "create", + [{"node", node_to_string(Node)}], []}]}]}; {atomic, {error, _} = Error} -> Error; _ -> @@ -742,6 +751,9 @@ delete_node(Host, JID, Node) -> Error; {atomic, {removed, Removed}} -> broadcast_removed_node(Host, Removed), + Lang = "", + broadcast_retract_item( + Host, ["pubsub", "nodes"], node_to_string(Node)), {result, []}; _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} @@ -1100,9 +1112,10 @@ broadcast_retract_item(Host, Node, ItemID) -> {xmlelement, "message", [], [{xmlelement, "x", [{"xmlns", ?NS_PUBSUB_EVENT}], - [{xmlelement, "retract", + [{xmlelement, "items", [{"node", node_to_string(Node)}], - []}]}]}, + [{xmlelement, "retract", + ItemAttrs, []}]}]}]}, ejabberd_router:route({"", Host, ""}, JID, Stanza); true -> @@ -1137,3 +1150,13 @@ broadcast_removed_node(Host, Removed) -> end, ok, Entities) end, Removed). + + +system_continue(Parent, _, State) -> + loop(State, Parent). + +system_terminate(Reason, Parent, _, State) -> + exit(Reason). + +system_code_change(State, _Mod, Ver, _Extra) -> + {ok, State}. diff --git a/src/mod_register.erl b/src/mod_register.erl index 2b6b03fbd..b833cc6b1 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -68,8 +68,6 @@ process_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> [SubEl, ?ERR_BAD_REQUEST]} end end; - {iq, ID, error, XMLNS, - [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]}; (UTag /= false) and (PTag /= false) -> User = xml:get_tag_cdata(UTag), Password = xml:get_tag_cdata(PTag), @@ -85,7 +83,10 @@ process_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> {iq, ID, error, XMLNS, [SubEl, Error]} end - end + end; + true -> + {iq, ID, error, XMLNS, + [SubEl, ?ERR_BAD_REQUEST]} end; get -> {iq, ID, result, XMLNS, [{xmlelement, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index e8b9357c9..9acebe5f4 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -40,7 +40,7 @@ start(Opts) -> mnesia:create_table(roster,[{disc_copies, [node()]}, {attributes, record_info(fields, roster)}]), mnesia:add_table_index(roster, user), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_ROSTER, + gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_ROSTER, ?MODULE, process_local_iq, IQDisc). process_local_iq(From, To, {iq, _, Type, _, _} = IQ) -> diff --git a/src/translate.erl b/src/translate.erl index 062ed846b..78994934e 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -22,23 +22,27 @@ start() -> ok. load_dir(Dir) -> - {ok, Files} = file:list_dir(Dir), - MsgFiles = lists:filter( - fun(FN) -> - case string:len(FN) > 4 of - true -> - string:substr(FN, - string:len(FN) - 3) == ".msg"; - _ -> - false - end - end, Files), - lists:foreach( - fun(FN) -> - load_file(string:substr(FN, 1, string:len(FN) - 4), - Dir ++ "/" ++ FN) - end, MsgFiles), - ok. + case file:list_dir(Dir) of + {ok, Files} -> + MsgFiles = lists:filter( + fun(FN) -> + case string:len(FN) > 4 of + true -> + string:substr(FN, + string:len(FN) - 3) == ".msg"; + _ -> + false + end + end, Files), + lists:foreach( + fun(FN) -> + load_file(string:substr(FN, 1, string:len(FN) - 4), + Dir ++ "/" ++ FN) + end, MsgFiles), + ok; + {error, Reason} -> + ?ERROR_MSG("~p", [Reason]) + end. load_file(Lang, File) -> case file:consult(File) of diff --git a/src/xml.erl b/src/xml.erl index 88b00e7b1..9f047c825 100644 --- a/src/xml.erl +++ b/src/xml.erl @@ -65,23 +65,23 @@ attr_to_string({Name, Value}) -> -%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) -> + 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. %crypt1(S) -> % lists:flatten([case C of @@ -93,21 +93,20 @@ attr_to_string({Name, Value}) -> % _ -> 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([]) -> - []. +%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([]) -> +% [].