I'm trying to write a module that requires both xmpp.hrl (for type presence() definition) and jlib.hrl (for 'ERR_NOT_AUTHORIZED' definition), but this appears to cause some form of include loop/redefinitions that I am unable to figure out.
I have created an almost-minimal test case based on hello world module (below).
Example error:
$ ejabberdctl module_install mod_hello_world
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:47: field sub_el undefined in record iq
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:47: field xmlns undefined in record iq
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:49: field sub_el undefined in record iq
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:50: field xmlns undefined in record iq
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:52: field sub_el undefined in record iq
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:53: field sub_el undefined in record iq
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:55: field sub_el undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:415: record jid already defined
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:422: type jid() already defined
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:424: type ljid() already defined
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:426: record iq already defined
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:436: field xmlns undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:438: field sub_el undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:446: field xmlns undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:448: field sub_el undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:458: field xmlns undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:460: field sub_el undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:468: field xmlns undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:470: field sub_el undefined in record iq
/Users/stu/my-ejabberd/lib/ejabberd-17.07.18/include/jlib.hrl:476: type iq() already defined
Error: {compilation_failed,"/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl"}
I've tried adding include header guards in jlib.hrl but somehow these are not working:
-ifndef(JLIB_HRL).
-define(JLIB_HRL, true).
... existing jlib.hrl content ...
-endif.
Full source of my example, failing, module is:
-module(mod_hello_world).
-behaviour(gen_mod).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-include("jlib.hrl").
-define(NS_HELLO_WORLD, <<"urn:xmpp:helloworld">>).
%% gen_mod API callbacks
-export([start/2,
c2s_self_presence/1,
depends/2,
mod_opt_type/1,
process_local_iq/3,
stop/1]).
start(Host, Opts) ->
?INFO_MSG("Hello, ejabberd world!", []),
ejabberd_hooks:add(c2s_self_presence, Host, ?MODULE, c2s_self_presence, 50),
IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(Host)),
gen_iq_handler:add_iq_handler(ejabberd_local, Host,
?NS_HELLO_WORLD, ?MODULE, process_local_iq, IQDisc),
ok.
stop(Host) ->
?INFO_MSG("Bye bye, ejabberd world!", []),
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_HELLO_WORLD),
ejabberd_hooks:delete(c2s_self_presence, Host, ?MODULE, c2s_self_presence, 50),
ok.
-spec c2s_self_presence({presence(), ejabberd_c2s:state()})
-> {presence(), ejabberd_c2s:state()}.
c2s_self_presence({_, #{pres_last := _}} = Acc) ->
%% This is just a presence update, nothing to do
Acc;
c2s_self_presence({#presence{type = available}, #{jid := New}} = Acc) ->
LUser = New#jid.luser,
LServer = New#jid.lserver,
?DEBUG("user_available: do stuff ~p @ ~p ", [LUser, LServer]),
Acc;
c2s_self_presence(Acc) ->
Acc.
process_local_iq(_From, _To, #iq{type = set, sub_el = SubEl, xmlns = ?NS_HELLO_WORLD} = IQ) ->
?INFO_MSG("Processing SET query:~n ~p", [IQ]),
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_AUTHORIZED]};
process_local_iq(_From, _To, #iq{type = get, xmlns = ?NS_HELLO_WORLD} = IQ) ->
?INFO_MSG("Processing GET query:~n ~p", [IQ]),
IQ#iq{type = result, sub_el = {xmlel, "result", [{"xmlns", ?NS_HELLO_WORLD}], [{xmlel, "hello", [], [{xmlcdata, <<"human">>}]}]}};
process_local_iq(_From, _To, #iq{sub_el = SubEl} = IQ) ->
?INFO_MSG("Processing IQ other type:~n ~p", [IQ]),
IQ#iq{type = error, sub_el = [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]}.
depends(_Host, _Opts) ->
[].
mod_opt_type(_) -> [].
Any help will be greatly appreciated!
Regards, Stu.
Don't use ?ERR_... Search in
Don't use ?ERR_...
Search in ejabberd source code examples of how to use xmpp:err_not_authorized(ErrText, Lang),
using xmpp:make_error(IQ,
using xmpp:make_error(IQ, xmpp:err_not_authorized()) allows me to avoid that error and get one step towards not including jlib.hrl (I presume that is the goal here?), but now I have these when I don't include jlib.hrl:
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:47: field sub_el undefined in record iq
/Users/stu/.ejabberd-modules/sources/mod_hello_world/src/mod_hello_world.erl:47: field xmlns undefined in record iq
You cannot use both xmpp.hrl
You cannot use both xmpp.hrl and jlib.hrl.https://github.com/processone/xmpp/blob/master/README.md
Also, jlib.hrl is deprecated and actually is forbidden to use. Use xmpp.hrl only. Adapt your code using new xmpp library, you can find the library's description here:
Do I need to modify XMPP
Do I need to modify XMPP library to add support for a new namespace for IQ queries?
I did have this part working before, when I was using jlib.hrl ...
2017-07-20 11:10:38.475 [debug] <0.1612.0>@ejabberd_receiver:process_data:284 Received XML on stream = <<"<iq to='localhost' type='get' id='123'>\n<query xmlns='urn:xmpp:helloworld'/>\n</iq>">>
...
2017-07-20 11:10:38.480 [debug] <0.1613.0>@ejabberd_socket:send:216 (tcp|<0.1612.0>) Send XML on stream = <<"<iq xml:lang='en' to='stu@localhost/resource' from='localhost' type='error' id='123'><query xmlns='urn:xmpp:helloworld'/><error code='400' type='modify'><bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Unknown tag <query/> qualified by namespace 'urn:xmpp:helloworld'</text></error></iq>">>
See
Seehttps://github.com/processone/xmpp/issues/9
Thank you for your assistance
Thank you for your assistance so far, I think I am nearly where I want to be, but it appears that my custom IQ handler is causing problems for others.
For example, with my module loaded and having answered one query, mod_ping is no longer processing client pings, and clients are being returned 503 / "No module is handling this query" errors.
I believe the problems I'm
I believe the problems I'm seeing with adding an IQ handler are specific to when my module is loaded only for a specific virtual host. If I load it globally, mod_ping is not affected. I suspect this may be an ejabberd bug.