#!/usr/bin/env swipl
/* echobot.pl
Author: Gimenez, Christian.
Copyright (C) 2026 Gimenez, Christian
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
2026-05-03
*/
:- module(echobot, []).
/** echobot: Echo bot example.
To run this script, set BOTJID and BOTPASS with the JID and password to connect
to the server.
@author Christian Gimenez
@license GPLv3
*/
:- license(gplv3).
:- use_module(library(xmpp/xmpp)).
:- use_module(library(xmpp/xmpp_core)).
:- use_module(library(xmpp/xmpp_simple)).
:- initialization(main, main).
opt_type(d, debug, boolean).
opt_help(debug, 'Enable debug mode').
% ----------
% Handlers
%! after_connect_handler(+Args: list)
%
% Handler for after_connect hook.
%
% This handler sends the chatty presence of the bot.
%
% @param Args Ignored (no processing to this data).
after_connect_handler(_Args) :-
send_presence('Echo Bot ready!', [show('chat')]),
debug(echobot, 'Echobot connected!', []).
% handle_presence(+Args: list)
%
% The logic used when a presence is received.
handle_presence(Args) :-
member(from(From), Args),
member(to(To), Args),
member(status(Text), Args),
format(show(Show), args),
format('Presence from ~q to ~q: (~q) ~q', [From, To, Show, Text]), !,
nl, flush.
%! received_presence_handler(+Args: list)
%
% Handler for received_presence hook.
%
% Executed when a new presence update stanza is received. This handler only
% prints to standard output the update presence.
%
% # Argument
% This is a different from the echobot.pl example. In this case, elements are
% already parsed and stored in Args. See xmpp_simple:presence_handler/1 for
% more information.
%
% # Catcihng errors and exceptions
% To avoid stoping the program, a catch/3 should be use to process the exception
% and avoid propagating it.
%
% @param Args a list with `[data(XMLParsed), current_state(ClientState)]`. The
% order of data and currest_state is not garanteed.
received_presence_handler(Args) :-
debug(echobot,'Handling presence: ~q', [Args]),
catch(handle_presence(Args), Error,
debug(chatbot, '!!! Error at handle_presence/1: ~q', [Error])).
received_presence_handler(Args) :- !,
debug(echobot, 'Failed to handle presence: ~q', [Args]).
% receive_message(+Args: list)
%
% The logic used when recieved the message.
receive_message(Args) :-
member(from(From), Args),
member(body(Text), Args),
format(atom(NewText), 'Echo: ~q', [Text]),
debug(echobot, 'Sending ~q...', [NewText]),
send_message(From, NewText),
format('Echo to ~q: ~q', [From, NewText]), nl, flush.
%! received_message_handler(+Args: list)
%
% Handler for the `received_message` hook.
%
% This handlers is executed when the bot receives a message stanza. It extracts
% the from JID and the text message, and sends it back.
%
% # Argument
% This is a different from the echobot.pl example. In this case, elements are
% already parsed and stored in Args. See xmpp_simple:message_handler/1 for
% more information.
%
% # Catcihng errors and exceptions
% To avoid stoping the program, a catch/3 should be use to process the exception
% and avoid propagating it.
%
% @param Args a list with `[data(XMLParsed), current_state(ClientState)]`. The
% order of data and currest_state is not garanteed.
received_message_handler(Args) :-
debug(echobot, 'Received: ~q', [Args]),
catch(receive_message(Args),
Error,
debug(echobot, '!!! Error at receive_message/1: ~q', [Error])).
received_message_handler(Args) :- !,
debug(echobot, 'Message handler failed with ~q', [Args]).
% -----
enable_debug(Options) :-
option(debug(true), Options, false),
debug(xmpp), debug(xmpp_auth), debug(xmpp_ping),
debug(echobot).
get_envdata(JID, Password) :-
getenv('BOTJID', JID),
getenv('BOTPASS', Password).
get_envdata(_, _) :-
throw(error(no_envvar_set,
context(get_envdata/2, 'Please, set BOTJID and BOTPASS environment variables'))).
main(ArgV) :-
argv_options(ArgV, _Pos, Options),
ignore(enable_debug(Options)),
get_envdata(JID, Password),
add_hook(after_connect, echobot:after_connect_handler),
% The xmpp_simple hooks are set here.
add_hook(received_message_simple, echobot:received_message_handler),
add_hook(received_presence_simple, echobot:received_presence_handler),
connect(JID, Password),
write('Press ENTER to quit.'), nl,
get_char(_),
disconnect.