Can someone please give me some hints how to develop a custom registration module?
I have tried two approaches:
ejabberd_hooks:add(c2s_unauthenticated_iq, Host, ?MODULE, handler, 50)
This handler function gets called very reliably, but I can't for the life of me figure out how to make it respond with an iq packet. When sending something like:
<iq type='get' id='reg1' to='shakespeare.lit'>
<query xmlns='jabber:iq:register'/>
</iq>
I'd like to respond with something like:
<iq type='result' id='reg1'>
<query xmlns='jabber:iq:register'>
<instructions>Foo</instructions>
<phone />
</query>
</iq>
I am able to respond just with a <query ...>
sub element, but whenever I try to wrap it in an iq packet as return value for the function, ejabberd refuses to put it on the wire because of "badxml".
The other approach I tried was with:
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_REGISTER, ?MODULE, handler, IQDisc)
This is either not called at all, or whatever response I return from my handler triggers a termination of the process.
Please give me a hint how I can intercept jabber:iq:register
packets and respond with custom responses? Thanks!
OK, I figured out that the
OK, I figured out that the component was not registering itself correctly. In order for it to be invoked, it needs to hook into the right events and it needs to announce its ability in the protocol, otherwise clients will not even try to call it. This is the current setup:
start(Host, Ops) ->
ejabberd_hooks:add(c2s_stream_features, Host, ?MODULE, stream_feature_register, 50),
ejabberd_hooks:add(c2s_unauthenticated_iq, Host, ?MODULE, on_c2s_unauthenticated_iq, 50),
...
%% Without this, clients won't know about the availability of the registration feature
stream_feature_register(Acc, _Host) -> [{ xmlelement, "register", [{ "xmlns", ?NS_FEATURE_IQREGISTER }], [] } | Acc].
on_c2s_unauthenticated_iq(_Acc, Server, #iq{ type = get, xmlns = ?NS_REGISTER } = IQ, IP) -> registration_format_iq(Server, IQ, IP);
on_c2s_unauthenticated_iq(_Acc, Server, #iq{ type = set, xmlns = ?NS_REGISTER } = IQ, IP) -> registration_iq(Server, IQ, IP).
%% Announce the required registration form fields
registration_format_iq(Server, IQ, IP) ->
jlib:iq_to_xml(IQ#iq{ type = result, sub_el = [
{ xmlelement, "query", [{ "xmlns", ?NS_REGISTER }], [
{ xmlelement, "instructions", [], [{ xmlcdata, "These are my custom registration fields." }] },
{ xmlelement, "email", [], [] },
{ xmlelement, "phone", [], [] }
] }
] }).
registration_iq(Server, #iq{ sub_el = SubEl } = IQ, IP) ->
%% Handle actual registration...
When the original mod_registration is disabled, this works fine.