Unable to include both xmpp.hrl and jlib.hrl

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.
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: https://github.com/processone/xmpp/blob/master/README.md

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 &lt;query/&gt; qualified by namespace &apos;urn:xmpp:helloworld&apos;</text></error></iq>">>

See

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.

Syndicate content