Implementing mod_blocking on MongooseIM - erlang
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
Related
{aborted, {bad_type, {...} } on mnesia:write/3
Supressing irrelevant code, i've the following: % somefile.erl -record(task, {description, date, completed = false}). init() -> {atomic, _} = mnesia:create_table(task, [{attributes, record_info(fields, task)}]). In other file, where the {aborted, {bad_type, {}}} is ocurring: -record(task, {id, description, date, completed = false}). create_task(Req, State) -> Task = create_task_record(), Transaction = fun() -> mnesia:write(task, Task, write) end, {atomic, _} = mnesia:transaction(Transaction), % ... When i'm running the code, in the line {atomic, _} = mnesia:transaction(Transaction), i'm receiving the error {aborted, {bad_type, {task, ...}}}.
After hours trying to find, the problem here is in the record task definition. I wasn't using the hrl to share definitions, so i have the definition where i was using it, because of this, in one file the definition was missing the id attribute, so i was having different types.
Erlang syntax error before: 'end' in line 55
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.
Riak Commit Hook CRDT Increment Counter
I have a commit hook that I want to update a counter. Currently I have: -module(bucket_counter). -export([precommit/1]). -record(crdt_op, {mod, op, ctx}). -define(CRDT_OP, #crdt_op). -define(V1_COUNTER_TYPE, riak_kv_pncounter). precommit(RObj) -> {ok, Client} = riak:local_client(), Bucket = {<<"counters">>, <<"update_counts">>}, Id = <<"all">>, Counter = case Client:get(Bucket, Id) of {error, notfound} -> riak_object:new(Bucket, Id, 0); {ok, Obj} -> Obj end, io:format("Counter ~p~n", [Counter]), {{Context,_},_} = riak_kv_crdt:value(Counter, ?V1_COUNTER_TYPE), Op = ?CRDT_OP{mod=?V1_COUNTER_TYPE, op={increment, 1}, ctx=Context}, Counter2 = riak_kv_crdt:update(Counter, <<"1234">>, Op), io:format("Gen ~p~n", [Counter2]), %Counter3 = riak_kv_crdt:merge(Counter2), Client:put(Counter2), RObj. This produces the error: #riak_kv_put_fsm:decode_precommit:887 Problem invoking pre-commit hook bucket_counter:precommit -> error:function_clause [{riak_kv_crdt,update_crdt,[[{riak_dt_pncounter,{{dict,5,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[[<<"dot">>|{<<252,97,47,244,1,104,136,26>>,{1,63622971158}}]],[],[],[],[],[],[[<<"content-type">>,97,112,112,108,105,99,97,116,105,111,110,47,114,105,97,107,95,99,111,117,110,116,101,114],[<<"X-Riak-VTag">>,53,87,81,75,79,113,110,77,80,111,117,49,71,101,120,122,52,67,89,115,66,122]],[[<<"index">>]],[],[[<<"X-Riak-Last-Modified">>|{1455,751958,325156}]],[],[]}}},{crdt,riak_dt_pncounter,"application/riak_counter",[{<<252,97,47,244,1,104,136,26>>,1,0}]}}}],<<"1234">>,{crdt_op,riak_kv_pncounter,{increment,1},<<>>}],[{file,"src/riak_kv_crdt.erl"},{line,234}]},{riak_kv_crdt,update,3,[{file,"src/riak_kv_crdt.erl"},{line,61}]},{bucket_counter,precommit,1,[{file,"bucket_counter.erl"},{line,24}]},{riak_kv_put_fsm,invoke_hook,4,[{file,"src/riak_kv_put_fsm.erl"},{line,853}]},{riak_kv_put_fsm,precommit,2,[{file,"src/riak_kv_put_fsm.erl"},{line,503}]},{gen_fsm,handle_msg,7,[{file,"gen_fsm.erl"},{line,505}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}] Looking into riak_kv source, It looks like merge only works with Maps and Sets when you have a context: https://github.com/basho/riak_kv/blob/master/src/riak_kv_crdt.erl#L246 I have tried removing the context but it then crashes because of siblings: riak_index:parse_object_hook:116 Siblings not allowed: {r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,67,49,85,69,121,66,118,111,84,56,85,118,81,104,104,106,74,101,98,49,71]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,750950,430934}]],[],[]}}},<<69,2,0,0,0,17,114,105,97,107,95,100,116,95,112,110,99,111,117,110,116,101,114,71,2,131,108,0,0,0,1,104,3,109,0,0,0,8,252,97,47,244,156,20,105,128,97,1,97,0,106>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,67,49,85,69,121,66,118,111,84,56,85,118,81,104,104,106,74,101,98,49,71]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,750950,430934}]],[],[]}}},<<69,1,71,1,0,0,0,22,70,1,131,108,0,0,0,1,104,2,109,0,0,0,4,49,50,51,52,97,1,106,0,0,0,4,70,1,131,106>>}],[{<<252,97,47,244,156,20,105,128>>,{1,63622970068}}],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined} Updating to map gives me a sibling error: -module(bucket_counter). -export([precommit/1]). -record(crdt_op, {mod, op, ctx}). -define(CRDT_OP, #crdt_op). -define(V1_COUNTER_TYPE, riak_kv_pncounter). precommit(RObj) -> {ok, Client} = riak:local_client(), Bucket = {<<"counters">>, <<"update_counts">>}, Id = <<"all">>, {Counter, Context} = case Client:get(Bucket, Id) of {error, notfound} -> Obj = riak_object:new(Bucket, Id, 0), {Obj, undefined}; {ok, Obj} -> {{CountContext,_},_} = riak_kv_crdt:value(Obj, riak_dt_map), {Obj, CountContext} end, io:format("Counter ~p~n", [Counter]), Op = ?CRDT_OP{mod=riak_dt_map, op={update,[{update,{<<"count">>,riak_dt_emcntr},increment}]}, ctx=Context}, Counter2 = riak_kv_crdt:update(Counter, <<"1234">>, Op), io:format("Gen ~p~n", [Counter2]), %Counter3 = riak_kv_crdt:merge(Counter2), Client:put(Counter2), RObj. riak_index:parse_object_hook:116 Siblings not allowed: {r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},<<69,2,0,0,0,11,114,105,97,107,95,100,116,95,109,97,112,77,1,131,80,0,0,0,132,120,1,203,96,206,97,96,96,96,204,96,202,5,82,44,134,70,198,38,137,140,89,80,33,136,32,107,114,126,105,94,73,10,3,95,81,102,98,118,124,74,73,124,106,110,114,94,73,81,6,19,138,42,168,86,184,40,22,227,224,66,25,204,137,140,64,200,144,149,149,193,148,5,4,0,198,254,26,118>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},0}],[],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined} 2016-02-18 00:48:25.966 [debug] <0.2105.0>#riak_kv_put_fsm:decode_precommit:880 Pre-commit hook riak_index:parse_object_hook failed with reason {siblings_not_allowed,{r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},<<69,2,0,0,0,11,114,105,97,107,95,100,116,95,109,97,112,77,1,131,80,0,0,0,132,120,1,203,96,206,97,96,96,96,204,96,202,5,82,44,134,70,198,38,137,140,89,80,33,136,32,107,114,126,105,94,73,10,3,95,81,102,98,118,124,74,73,124,106,110,114,94,73,81,6,19,138,42,168,86,184,40,22,227,224,66,25,204,137,140,64,200,144,149,149,193,148,5,4,0,198,254,26,118>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},0}],[],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}}
I have figured it out, I was going off of 1.4 documentation and instead I needed to do riak_kv_crdt:new(Bucket, Id, riak_dt_map)
User send packet hook returning `badmatch` error
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}}),
Erl file not compiling due to syntax errors
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.