I am a beginner with Erlang/Nitrogen.
I am toying with a bidding system back by a mnesia db.
On my index page I have the following code and the various items and their properties get created dynamically from the database:
%% -*- mode: nitrogen -*-
-module (index).
-compile(export_all).
-include_lib("nitrogen/include/wf.hrl").
main() -> #template { file="./site/templates/bare.html" }.
title() -> "Meir Panim Gala Dinner silent auction".
body() ->
Header = [#panel{id=header, body=[#h1{text="Meir Panim Gala Dinner silent auction"}]}],
{atomic, Items} = item_database:get_all(),
Elements = lists:map(fun(X) ->
{item, Index, Title, _, Picture, _, _, Reserve, CurrentBid} = X,
#panel{id=items, body=[
#span{id=title, text=Title},
#image{id=image, image= "images/" ++ Picture},
#span{id=currentbid, text="Current bid: £" ++ integer_to_list(CurrentBid)},
#span{id=reserve, text="Reserve: £" ++ wf:to_list(Reserve)},
#link{id=showalert, text="More info / Place your bid", postback="showalert"++integer_to_list(Index)}
]
}
end, Items),
wf:f([Header, Elements]).
{atomic, Items} = item_database:get_all(),
Actions = lists:map(fun(X) ->
{item, Index, _, _, _, _, _, _, _} = X,
event("showalert"++integer_to_list(Index)) ->
wf:wire(#alert{text="action "++integer_to_list(Index)++" clicked"})
end, Items).
I tried to create my events in the same manner but it was not working.
In my code the alerts will be replaced with lightboxes containing a form to accept bids.
Please help and tell me what I am doing wrong.
As far as I know you catch events in page with "event".
so I would try something like :
postback={bid, Index}
and at down catch it with :
event({bid, Index})->
%% do stuff
ok;
event(_)->
ok.
update:
this is only an example of how you can fix it, its not the best way.
%% -*- mode: nitrogen -*-
-module (index).
-compile(export_all).
-include_lib("nitrogen/include/wf.hrl").
main() -> #template { file="./site/templates/bare.html" }.
title() -> "Meir Panim Gala Dinner silent auction".
body() ->
Header = [#panel{id=header, body=[#h1{text="Meir Panim Gala Dinner silent auction"}]}],
{atomic, Items} = item_database:get_all(),
Elements = lists:map(fun(X) ->
{item, Index, Title, _, Picture, _, _, Reserve, CurrentBid} = X,
#panel{id=items, body=[
#span{id=title, text=Title},
#image{id=image, image= "images/" ++ Picture},
#span{id=currentbid, text="Current bid: £" ++ integer_to_list(CurrentBid)},
#span{id=reserve, text="Reserve: £" ++ wf:to_list(Reserve)},
#link{id=showalert, text="More info / Place your bid", postback={bid,Index}}
]
}
end, Items),
wf:f([Header, Elements]).
event({bid, Idx})->
%% you would better have a function to get one item at a time in item_database
case item_database:get_by_index(Idx) of
{atomic, X} ->
%% This is not the right way, use records
{item, Index, Title, _, Picture, _, _, Reserve, CurrentBid} = X,
wf:wire(#alert{text="action "++ Title ++" clicked"});
_ ->
wf:wire(#alert{text="item not found"})
end;
event(_)->
ok.
%% -*- mode: nitrogen -*-
-module (index).
-compile(export_all).
-include_lib("nitrogen/include/wf.hrl").
main() -> #template { file="./site/templates/bare.html" }.
title() -> "Welcome to Nitrogen".
body() ->
{atomic, Records} = item_database:get_all(),
Elements = lists:map(fun(X) ->
{item, Index, Title, _, _, _, _, _, _} = X,
#panel{body=[
#span{text=Title, style="font-size: 20px; font-weight: bold;"},
#br{},
#link{text="more info / place your bid", postback="showinfo"++integer_to_list(Index)},
#br{},
#link{text="register your bid", postback="registerbid"++integer_to_list(Index)},
#br{},
#br{},
#lightbox{id="lightbox"++integer_to_list(Index), style="display: none;", body=[
#span{text=Title, style="font-size: 24px; font-weight: bold; color: #ffffff;"}
]}
]}
end, Records),
wf:f([Elements]).
event(Event) ->
case (re:run(Event, "showinfo")) of
{match, _} ->
[_, _, SI] = re:split(Event, "(showinfo)"),
ShowIndex = binary:bin_to_list(SI),
wf:wire(#show{target="lightbox"++ShowIndex});
_ -> ok
end,
case (re:run(Event, "registerbid")) of
{match, _} ->
[_, _, RI] = re:split(Event, "(registerbid)"),
RegisterIndex = binary:bin_to_list(RI),
wf:wire(#alert{text="registerbid"++RegisterIndex++" clicked"});
_ -> ok
end.
Related
Cant find the syntax error, i searched for misplaced/missing ";" , "," , "end" and also searched for missing parentheses but no luck.
Any ideas?
PD: Sorry for bad English and Spanglish code
partida(ID,Tablero,Turno,Name1,Psocket1,Name2,Psocket2,SpectList) ->
case (Psocket1 == " ") of
true -> F = fun() -> case mnesia:read(juegos,ID) of
[P1] ->
case mnesia:read(nombre,P1#juegos.jg1) of
[] -> exit(normal);
[A] -> P2 = A#nombre.psocket
end,
case mnesia:read(nombre,P1#juegos.jg2) of
[] -> exit(normal);
[B] -> P3 = B#nombre.psocket
end,
Res = {P1#juegos.jg1,P2,P1#juegos.jg2,P3,P1#juegos.spect};
_ -> Res = ok,exit(normal)
end,
Res end,
{atomic,Arg} = mnesia:transaction(F),
partida(ID,Tablero,Turno,element(1,Arg),element(2,Arg),element(3,Arg),element(4,Arg),element(5,Arg))
end,
receive
case Jugada of
[Pj,"bye"] -> ok;
[Pj,F] -> Posicion = element(1,string:to_integer(F)),
case (Name1 == Pj) and ((Turno rem 2) == 1) of
true -> case not(Posicion == error) and (Posicion < 10) of
true -> ok;%%jugada valida
_ -> ok %%Jugada ilegal
end;
false ->ok %%No es tu turno
end,
case (Name2 == Pj) and ((Turno rem 2) == 0) of
true -> case (not(Posicion == error) and (Posicion < 10)) of
true ->ok; %%jugada valida
_ -> ok %%Jugada ilegal
end;
false -> ok %%No es tu turno
end
end
end, %% Line 55
ASD = get_spects(ID),partida(ID,Tablero,Turno,Name1,Psocket1,Name2,Psocket2,ASD).
You have a syntax error in receive clause.
1> case oops of _ -> ok end. % correct
ok
2> receive (case oops of _ -> ok end) end.
* 1: syntax error before: 'end'
receive statement is used for reading Erlang messages of the process. Here you are not waiting for any message and you are doing something in body of receive clause! If you don't want to check the message but you want to do something after receiving first message, I recommend to use _ for pattern matching:
3> receive _ -> (case oops of _ -> ok end) end.
%% Waits for a message
Actually you can have no receive clause, but like this:
4> receive after 1000 -> done end. %% Sleeps 1000 ms and does not care about any incoming message
done
But you can't write code in receive clause without any pattern matching.
trying to upload files using curl
curl -v -F 'file1=#/home/user/test/aaa/validation_utils.erl' -F 'file2=#/home/user/test/aaa/README.md' http://localhost:8083/api/list
but receiving only one (as i can see from logs)
[warning] Form_Data:
[{<<"content-type">>,<<"application/octet-stream">>},{<<"content-disposition">>,<<"form-data; name=\"file1\"; filename=\"validation_utils.erl\"">>}]
this is my get_body function:
get_body(<<"POST">>, AllHeaders, Req, _MaxFileSize) ->
case maps:get(<<"content-type">>, AllHeaders) of
<<"application/json", _Rest/binary>> ->
case catch cowboy_req:read_body(Req) of
{ok, <<>>, Req2} ->
{ok, [], Req2};
{ok, JsonBody, Req2} when JsonBody =/= <<>> ->
try
{ok, ?JSON_DECODE(JsonBody), Req2}
catch
_:Err ->
Err
end
end;
<<"multipart/form-data", _Rest/binary>> ->
{ok, Headers, Req2} = cowboy_req:read_part(Req),
{ok, Data, _Req3} = cowboy_req:read_part_body(Req2),
{file, _, Filename, _ContentType, _BitSize} = cow_multipart:form_data(Headers),
Body = [{<<"filename">>, Filename}, {<<"base64_file">>, base64:encode(Data)} | cowboy_req:parse_qs(Req)],
{ok, Body, Req};
_ ->
cowboy_req:read_urlencoded_body(Req)
end;
Got it.
I need to iterate the cowboy_req:read_part(Req)
multipart(Req0) ->
case cowboy_req:read_part(Req0) of
{ok, Headers, Req1} ->
?LOG_WARNING("Headers: p~n", [Headers]),
{ok, _Body, Req} = cowboy_req:read_part_body(Req1),
multipart(Req);
{done, Req} ->
?LOG_WARNING("Req: p~n", [Req]),
Req
end.
as mentioned here : https://ninenines.eu/docs/en/cowboy/2.0/guide/multipart/
I am using user send packet hook in my custom module, I am not understanding why getting badmatch error for each of the packet received. i have added declaration part here too.
**Code**
-module(mod_post_log).
-behaviour(gen_mod).
-export([start/2,stop/1,log_user_send/4,post_result/1,send_message/3]).
**strong text**
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("logger.hrl").
start(Host, _Opts) ->
ok = case inets:start() of
{error, {already_started, inets}} ->
ok;
ok ->
ok
end,
ejabberd_hooks:add(user_send_packet, Host,
?MODULE, log_user_send, 50),
ok.
stop(Host) ->
ejabberd_hooks:delete(user_send_packet, Host,
?MODULE, log_user_send, 50),
ok.
log_user_send(Packet, _C2SState, From, To) ->
ok = log_packet(From, To, Packet),
Packet.
log_packet(From, To, #xmlel{name = <<"message">>} = Packet) ->
MessageId = xml:get_tag_attr_s(<<"id">>, Packet),
Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
send_message(From, To, MessageId, Type),
%% send_message(From, To, xml:get_tag_attr_s(list_to_binary("id"), Packet),xml:get_tag_attr_s(list_to_binary("type"), Packet)),
%% ?INFO_MSG("mod_ack_receipt - MsgID: ~p To: ~p From: ~p", [MessageId, To, From]),
ok = log_message(From, To, Packet);
log_packet(_From, _To, _Packet) ->
ok.
log_message(From, To, #xmlel{attrs = Attrs} = Packet) ->
Type = lists:keyfind(<<"type">>, 1, Attrs),
log_message_filter(Type, From, To, Packet).
log_message_filter({<<"type">>, Type}, From, To, Packet)
when Type =:= <<"chat">>;
Type =:= <<"groupchat">> ->
log_chat(From, To, Packet);
log_message_filter(_Other, _From, _To, _Packet) ->
ok.
log_chat(From, To, #xmlel{children = Els} = Packet) ->
case get_body(Els) of
no_body ->
ok;
{ok, _Body} ->
log_chat_with_body(From, To, Packet)
end.
log_chat_with_body(From, To, Packet) ->
case should_acknowledge(Packet) of
S when (S==true) ->
post_xml(From, To, Packet);
false ->
ok
end,
Packet.
should_acknowledge(#xmlel{name = <<"message">>} = Packet) ->
case {xml:get_attr_s(<<"type">>, Packet#xmlel.attrs),
xml:get_subtag_cdata(Packet, <<"body">>)} of
{<<"error">>, _} ->
false;
{_, <<>>} ->
%% Empty body
false;
_ ->
true
end;
should_acknowledge(#xmlel{}) ->
false.
post_xml(From, To, Packet) ->
Ts = to_iso_8601_date(os:timestamp()),
MessageId = xml:get_tag_attr_s(list_to_binary("id"), Packet),
Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
Chat_sent = xml:get_tag_attr_s(list_to_binary("chat_sent"), Packet),
Subject = xml:get_path_s(Packet, [{elem, list_to_binary("subject")},cdata]),
Body = xml:get_path_s(Packet,[{elem, list_to_binary("body")}, cdata]),
Sep = "&",
Post = [
"from=", From#jid.luser, Sep,
"to=", To#jid.luser, Sep,
"body=", binary_to_list(Body), Sep,
"type=", binary_to_list(Type),Sep,
"chat_sent=", binary_to_list(Chat_sent),Sep,
"subject=",binary_to_list(Subject),Sep,
"message_id=", binary_to_list(MessageId),Sep,
"xml=",xml:element_to_binary(Packet),Sep,
"done=11"
],
Url = get_opt(url),
TsHeader = get_opt(ts_header, "X-Message-Timestamp"),
FromHeader = get_opt(from_header, "X-Message-From"),
ToHeader = get_opt(to_header, "X-Message-To"),
HttpOptions = get_opt(http_options, []),
ReqOptions = get_opt(req_options, []),
{ok, _ReqId} = httpc:request(post,
{Url, [], "application/x-www-form-urlencoded", list_to_binary(Post)},
HttpOptions,
[ {sync, false},
{receiver, {?MODULE, post_result, []}}
| ReqOptions ]),
?INFO_MSG("post http - MsgID: xml: ~p", [post]),
ok.
post_result({_ReqId, {error, Reason}}) ->
report_error([ {error, Reason } ]);
post_result({_ReqId, Result}) ->
{StatusLine, Headers, Body} = Result,
{_HttpVersion, StatusCode, ReasonPhrase} = StatusLine,
if StatusCode < 200;
StatusCode > 299 ->
ok = report_error([ {status_code, StatusCode},
{reason_phrase, ReasonPhrase},
{headers, Headers},
{body, Body} ]),
ok;
true ->
ok
end.
send_message(From, To, MessageId,Type) ->
Packet = #xmlel{name = <<"iq">>,
attrs = [{<<"to">>, From},{<<"ack">>, MessageId}, {<<"type">>, <<"result">>},{<<"chattype">>, Type}],
children =
[#xmlel{name = <<"ack">>,
attrs = [{<<"xmlns">>,<<"xmpp:ack">> }],
children = []}]},
ejabberd_router:route(From, From, Packet).
get_body(Els) ->
XmlEls = [ El || El <- Els, is_record(El, xmlel) ],
case lists:keyfind(<<"body">>, #xmlel.name, XmlEls) of
false ->
no_body;
#xmlel{children = InnerEls} ->
case lists:keyfind(xmlcdata, 1, InnerEls) of
false ->
no_body;
{xmlcdata, Body} ->
{ok, Body}
end
end.
get_opt(Opt) ->
get_opt(Opt, undefined).
get_opt(Opt, Default) ->
F = fun(Val) when is_binary(Val) -> binary_to_list(Val);
(Val) -> Val
end,
gen_mod:get_module_opt(global, ?MODULE, Opt, F, Default).
report_error(ReportArgs) ->
ok = error_logger:error_report([ mod_post_log_cannot_post | ReportArgs ]).
**Error Log**
{{badmatch,{xmlel,<<"message">>,
[{<<"xml:lang">>,<<"en">>},
{<<"to">>,<<"123456789#xyz.myapp.com">>},
{<<"id">>,<<"AF1xJ-149">>},
{<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>},
{<<"type">>,<<"chat">>}],
[{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]},
{xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]},
{xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]},
{xmlel,<<"request">>,
[{<<"xmlns">>,<<"urn:xmpp:receipts">>}],
[]}]}},
[{mod_post_log,log_packet,3,
[{file,"src/mod_post_log.erl"},{line,44}]},
{mod_post_log,log_user_send,4,
[{file,"src/mod_post_log.erl"},{line,33}]},
{ejabberd_hooks,safe_apply,3,
[{file,"src/ejabberd_hooks.erl"},{line,382}]},
{ejabberd_hooks,run_fold1,4,
[{file,"src/ejabberd_hooks.erl"},{line,365}]},
{ejabberd_c2s,session_established2,2,
[{file,"src/ejabberd_c2s.erl"},{line,1296}]},
{p1_fsm,handle_msg,10,[{file,"src/p1_fsm.erl"},{line,582}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,237}]}]}
In file src/mod_post_log.erl at line 44 in function mod_post_log:log_packet/3 is some match operator which doesn't expect to get
{xmlel,<<"message">>,
[{<<"xml:lang">>,<<"en">>},
{<<"to">>,<<"123456789#xyz.myapp.com">>},
{<<"id">>,<<"AF1xJ-149">>},
{<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>},
{<<"type">>,<<"chat">>}],
[{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]},
{xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]},
{xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]},
{xmlel,<<"request">>,
[{<<"xmlns">>,<<"urn:xmpp:receipts">>}],
[]}]}
it would be much better to see full module "mod_post_log.erl" as is.
But i think that problem is here :
MessageId = xml:get_tag_attr_s(<<"id">>, Packet),
Packet is a record, and function wait for iolist, so it should be something like
MessageId = xml:get_tag_attr_s(<<"id">>, Packet#xmlel.{{see record declaration}}),
I'm trying to implement mod_blocking that will work only with mod_privacy in odbc module.
I keep getting the response:
<error code='500' type='wait'><internal-server-error0 xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>
Here is my code:
process_blocklist_block(LUser, LServer, JIDs) ->
Filter = fun (List) ->
AlreadyBlocked = list_to_blocklist_jids(List, []),
lists:foldr(fun (JID, List1) ->
case lists:member(JID, AlreadyBlocked)
of
true -> List1;
false ->
[#listitem{type = jid,
value = JID,
action = deny,
order = 0,
match_all = true}
| List1]
end
end,
List, JIDs)
end,
case process_blocklist_block(LUser, LServer, Filter,odbc)
of
{atomic, {ok, Default, List}} ->
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, Default,
UserList),
broadcast_blocklist_event(LUser, LServer,
{block, JIDs}),
{result, [], UserList};
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
end.
process_blocklist_block(LUser, LServer, Filter, odbc) ->
F = fun () ->
Default = case mod_privacy_odbc:sql_get_default_privacy_list_t(LUser)
of
{selected, [<<"name">>], []} ->
Name = <<"Blocked contacts">>,
mod_privacy_odbc:sql_add_privacy_list(LUser, Name),
mod_privacy_odbc:sql_set_default_privacy_list(LUser, Name),
Name;
{selected, [<<"name">>], [[Name]]} -> Name
end,
{selected, [<<"id">>], [[ID]]} = mod_privacy_odbc:sql_get_privacy_list_id_t(LUser, Default),
case mod_privacy_odbc:sql_get_privacy_list_data_by_id_t(ID)
of
{selected,
[<<"t">>, <<"value">>, <<"action">>, <<"ord">>,
<<"match_all">>, <<"match_iq">>, <<"match_message">>,
<<"match_presence_in">>, <<"match_presence_out">>],
RItems = [_ | _]} ->
List = lists:map(fun mod_privacy_odbc:raw_to_item/1, RItems);
_ -> List = []
end,
NewList = Filter(List),
NewRItems = lists:map(fun mod_privacy_odbc:item_to_raw/1, NewList),
mod_privacy_odbc:sql_set_privacy_list(ID, NewRItems),
{ok, Default, NewList}
end,
ejabberd_odbc:sql_transaction(LServer, F).
I've checked all the queries. They work fine. I struggling with understanding the logic of this piece of code. What is the best way to debug this code, so i can understand when my logic is failing? Could anyone point me in the right direction?
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, Default,
UserList),
broadcast_blocklist_event(LUser, LServer,
{block, JIDs}),
{result, [], UserList};
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
if you expect
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
is the point where server returns 'internal server error', you can just change this place to
_Otherwise ->
?WARNING_MSG("Got some unexpected result in mod_priv ~100000p",[_Otherwise]),
{error, ?ERR_INTERNAL_SERVER_ERROR)
and then look at log/ejabberd.log
Of course you need to start mongooseim with loglevel at least 3 in the ejabberd.cfg
I am trying to figure out what is wrong with this code, cause it is giving me errors preventing it from compiling properly into a beam file. I do not see what is wrong with the syntax. Is there an IDE which could help me out?
These are the errors:
parallels#parallels-Parallels-Virtual-Platform:/var/backend/ejabberd_modules# erlc -I /var/tmp/ejabberd/src/ mod_stanza_ack.erl
./mod_stanza_ack.erl:97: syntax error before: '.'
./mod_stanza_ack.erl:98: syntax error before: Body
./mod_stanza_ack.erl:16: function route/3 undefined
./mod_stanza_ack.erl:3: Warning: behaviour gen_mod undefined
./mod_stanza_ack.erl:111: Warning: function strip_bom/1 is unused
./mod_stanza_ack.erl:114: Warning: function send_presence/3 is unused
./mod_stanza_ack.erl:120: Warning: function echo/3 is unused
./mod_stanza_ack.erl:123: Warning: function send_message/4 is unused
This is the code:
-module(mod_stanza_ack).
-behavior(gen_server).
-behavior(gen_mod).
-export([start_link/2]).
-export([start/2,
stop/1,
init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).
-export([route/3]).
-include("ejabberd.hrl").
-define(PROCNAME, ejabberd_mod_stanza_ack).
-define(BOTNAME, stanza_ack).
start_link(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
start(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ChildSpec = {Proc,
{?MODULE, start_link, [Host, Opts]},
temporary,
1000,
worker,
[?MODULE]},
supervisor:start_child(ejabberd_sup, ChildSpec).
stop(Host) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:call(Proc, stop),
supervisor:terminate_child(ejabberd_sup, Proc),
supervisor:delete_child(ejabberd_sup, Proc).
init([Host, Opts]) ->
?DEBUG("ECHO_BOT: Starting echo_bot", []),
% add a new virtual host / subdomain "echo".example.com
MyHost = gen_mod:get_opt_host(Host, Opts, "echo.#HOST#"),
ejabberd_router:register_route(MyHost, {apply, ?MODULE, route}),
{ok, Host}.
handle_call(stop, _From, Host) ->
{stop, normal, ok, Host}.
handle_cast(_Msg, Host) ->
{noreply, Host}.
handle_info(_Msg, Host) ->
{noreply, Host}.
terminate(_Reason, Host) ->
ejabberd_router:unregister_route(Host),
ok.
code_change(_OldVsn, Host, _Extra) ->
{ok, Host}.
% Checks a presence /subscription/ is a part of this.
% we may want to impliment blacklisting / some kind of
% protection here to prevent malicious users
%route(From, #jid{luser = ?BOTNAME} = To, {xmlelement, "presence", _, _} = Packet) ->
route(From, To, {xmlelement, "presence", _, _} = Packet) ->
case xml:get_tag_attr_s("type", Packet) of
"subscribe" ->
send_presence(To, From, "subscribe");
"subscribed" ->
send_presence(To, From, "subscribed"),
send_presence(To, From, "");
"unsubscribe" ->
send_presence(To, From, "unsubscribed"),
send_presence(To, From, "unsubscribe");
"unsubscribed" ->
send_presence(To, From, "unsubscribed");
"" ->
send_presence(To, From, "");
"unavailable" ->
ok;
"probe" ->
send_presence(To, From, "");
_Other ->
?INFO_MSG("Other kind of presence~n~p", [Packet])
end,
ok;
%route(From, #jid{luser = ?BOTNAME} = To, {xmlelement, "message", _, _} = Packet) ->
route(From, To, {xmlelement, "message", _, _} = Packet) ->
case xml:get_subtag_cdata(Packet, "body") of
"" ->
ok.
Body ->
case xml:get_tag_attr_s("type", Packet) of
"error" ->
?ERROR_MSG("Received error message~n~p -> ~p~n~p", [From, To, Packet]);
_ ->
echo(To, From, strip_bom(Body))
end
end,
ok.
%% HELPER FUNCTIONS
strip_bom([239,187,191|C]) -> C;
strip_bom(C) -> C.
send_presence(From, To, "") ->
ejabberd_router:route(From, To, {xmlelement, "presence", [], []});
send_presence(From, To, TypeStr) ->
ejabberd_router:route(From, To, {xmlelement, "presence", [{"type", TypeStr}], []}).
echo(From, To, Body) ->
send_message(From, To, "chat", Body).
send_message(From, To, TypeStr, BodyStr) ->
XmlBody = {xmlelement, "message",
[{"type", TypeStr},
{"from", jlib:jid_to_string(From)},
{"to", jlib:jid_to_string(To)}],
[{xmlelement, "body", [],
[{xmlcdata, BodyStr}]}]},
ejabberd_router:route(From, To, XmlBody).
./mod_stanza_ack.erl:97: syntax error before: '.' is saying the error is in line 97.
At line 97 change ok. to ok;. This will fix the issue.
Erlide plugin for eclipse is a good IDE to try out.
On line 97 in the function route/3 the first clause of the case is
"" ->
ok.
The . here ends the function which is illegal in the middle of a case, it should be a ;. This also means that the parser assumes that the variable Body on the next line starts a new function which is also illegal as a function name cannot be a variable.
Seeing the function route/3 has not been defined it cannot be exported which is the cause of the undefined function error on line 16.
Sometimes the compiler error messages are a bit cryptic but the line numbers usually help.