sandbox: basic rlimit sandbox
The rlimit sandbox disables forking processes and opening files.
The rlimit sandbox is not used by default yet. To compile it:
XMPPIPE_SANDBOX=XMPPIPE_SANDBOX_RLIMIT make
The rlimit sandbox should work on any platform. However the interaction
of RLIMIT_NOFILE with poll(2) (and select(2)?) on some platforms (FreeBSD
but really any OS besides Linux) is problematic:
* opening a number of fd's, setting RLIMIT_NOFILE to 0, calling
poll(2) on the fdset
Linux: works
FreeBSD: fails
* opening a number of fd's, setting RLIMIT_NOFILE to maxfd+1, calling
poll(2) on the fdset
Linux: works
FreeBSD: works
The issue with the second option is that a library may have opened a
sequence of file descriptors then closed the lower numbered fd's:
open() => 3
open() => 4
open() => 5
close(3)
close(4)
maxfd = 5
RLIMIT_NOFILE would be set to 6 (stdin, stdout, stderr, 3, 4, 5) and the
sandbox would allow re-opening fd's 3 and 4.
One possible fix would be to run through the sequence of fd's before
entering the rlimit sandbox:
* test if the fd is closed
* if the fd is closed, dup2(STDIN_FILENO, fd)
Since the closed fd's are not part of the pollset, they will not be
polled and should be ignored.
Note we can't simply move maxfd to the lowest unused fd because
libstrophe maintains the fd number as internal, opaque state.
Empirically, the xmpp fd is always 3. Another option would be to abort
the process if the fd does not equal 3.
2017-01-31 13:17:02 +00:00
|
|
|
/* Copyright (c) 2015-2017, Michael Santos <michael.santos@gmail.com>
|
2015-05-11 19:19:35 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
#include "xmppipe.h"
|
|
|
|
|
|
|
|
#include <sys/select.h>
|
|
|
|
#include <sys/types.h>
|
2015-07-01 13:12:16 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <resolv.h>
|
2017-06-27 12:47:01 +00:00
|
|
|
#include <getopt.h>
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
extern char *__progname;
|
|
|
|
|
|
|
|
static void usage(xmppipe_state_t *xp);
|
|
|
|
|
2017-03-18 12:00:59 +00:00
|
|
|
static long long xmppipe_strtonum(xmppipe_state_t *state, const char *nptr,
|
|
|
|
long long minval, long long maxval);
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
void handle_connection(xmpp_conn_t * const, const xmpp_conn_event_t, const int,
|
|
|
|
xmpp_stream_error_t * const, void * const userdata);
|
|
|
|
int handle_disco_items(xmpp_conn_t * const, xmpp_stanza_t * const,
|
|
|
|
void * const);
|
|
|
|
int handle_disco_info(xmpp_conn_t * const, xmpp_stanza_t * const,
|
|
|
|
void * const);
|
|
|
|
int handle_version(xmpp_conn_t * const, xmpp_stanza_t * const, void * const);
|
|
|
|
int handle_message(xmpp_conn_t * const, xmpp_stanza_t * const, void * const);
|
|
|
|
int handle_presence(xmpp_conn_t * const, xmpp_stanza_t * const, void * const);
|
2015-05-13 11:37:34 +00:00
|
|
|
int handle_presence_error(xmpp_conn_t * const, xmpp_stanza_t * const,
|
|
|
|
void * const);
|
2015-06-10 11:49:21 +00:00
|
|
|
int handle_ping_reply(xmpp_conn_t * const, xmpp_stanza_t * const, void * const);
|
2015-05-16 18:45:22 +00:00
|
|
|
int handle_sm_request(xmpp_conn_t * const, xmpp_stanza_t * const, void * const);
|
|
|
|
int handle_sm_enabled(xmpp_conn_t * const, xmpp_stanza_t * const, void * const);
|
|
|
|
int handle_sm_ack(xmpp_conn_t * const, xmpp_stanza_t * const, void * const);
|
|
|
|
int handle_null(xmpp_conn_t * const, xmpp_stanza_t * const, void * const);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
int xmppipe_connect_init(xmppipe_state_t *);
|
2015-05-16 18:45:22 +00:00
|
|
|
int xmppipe_stream_init(xmppipe_state_t *);
|
2015-05-11 19:19:35 +00:00
|
|
|
int xmppipe_muc_init(xmppipe_state_t *);
|
|
|
|
int xmppipe_presence_init(xmppipe_state_t *);
|
|
|
|
void event_loop(xmppipe_state_t *);
|
|
|
|
int handle_stdin(xmppipe_state_t *, int, char *, size_t);
|
2015-05-16 18:45:22 +00:00
|
|
|
void xmppipe_stream_close(xmppipe_state_t *);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-12 18:09:14 +00:00
|
|
|
void xmppipe_muc_join(xmppipe_state_t *);
|
|
|
|
void xmppipe_muc_unlock(xmppipe_state_t *);
|
|
|
|
void xmppipe_muc_subject(xmppipe_state_t *, char *);
|
2015-05-24 14:27:59 +00:00
|
|
|
void xmppipe_send_message(xmppipe_state_t *, char *, char *, char *, size_t);
|
2015-05-16 18:45:22 +00:00
|
|
|
void xmppipe_send(xmppipe_state_t *, xmpp_stanza_t *const);
|
2015-05-11 19:19:35 +00:00
|
|
|
void xmppipe_ping(xmppipe_state_t *);
|
|
|
|
|
2017-06-27 12:47:01 +00:00
|
|
|
static const struct option long_options[] =
|
|
|
|
{
|
|
|
|
{"address", required_argument, NULL, 'a'},
|
|
|
|
{"buffer-size", required_argument, NULL, 'b'},
|
|
|
|
{"flow-control", required_argument, NULL, 'c'},
|
|
|
|
{"discard", no_argument, NULL, 'd'},
|
|
|
|
{"discard-to-stdout", no_argument, NULL, 'D'},
|
|
|
|
{"ignore-eof", no_argument, NULL, 'e'},
|
|
|
|
{"interval", required_argument, NULL, 'I'},
|
|
|
|
{"keepalive", required_argument, NULL, 'k'},
|
|
|
|
{"keepalive-failures", required_argument, NULL, 'K'},
|
|
|
|
{"ouput", required_argument, NULL, 'o'},
|
|
|
|
{"password", required_argument, NULL, 'p'},
|
|
|
|
{"poll-delay", required_argument, NULL, 'P'},
|
|
|
|
{"resource", required_argument, NULL, 'r'},
|
|
|
|
{"exit-when-empty", no_argument, NULL, 's'},
|
|
|
|
{"subject", required_argument, NULL, 'S'},
|
|
|
|
{"username", required_argument, NULL, 'u'},
|
|
|
|
{"unacked-requests", required_argument, NULL, 'U'},
|
|
|
|
{"verbose", no_argument, NULL, 'v'},
|
|
|
|
{"base64", no_argument, NULL, 'x'},
|
|
|
|
{"help", no_argument, NULL, 'h'}
|
|
|
|
};
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = NULL;
|
|
|
|
xmpp_log_t *log = NULL;
|
|
|
|
char *jid = NULL;
|
|
|
|
char *pass = NULL;
|
2015-05-16 13:54:35 +00:00
|
|
|
char *addr = NULL;
|
|
|
|
u_int16_t port = 0;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
int ch = 0;
|
|
|
|
|
|
|
|
state = xmppipe_calloc(1, sizeof(xmppipe_state_t));
|
|
|
|
|
|
|
|
state->status = XMPPIPE_S_CONNECTING;
|
2015-06-03 14:08:37 +00:00
|
|
|
state->bufsz = 2049;
|
2015-05-11 19:19:35 +00:00
|
|
|
state->poll = 10;
|
|
|
|
state->keepalive = 60 * 1000;
|
2015-05-16 15:10:31 +00:00
|
|
|
state->keepalive_limit = 3;
|
2015-05-31 12:56:04 +00:00
|
|
|
state->sm_request_interval = 1;
|
2015-06-01 13:39:22 +00:00
|
|
|
state->sm_fc = 15;
|
|
|
|
state->sm_unacked = 5;
|
2017-02-26 19:51:44 +00:00
|
|
|
state->room = xmppipe_roomname("stdout");
|
|
|
|
state->resource = xmppipe_strdup(XMPPIPE_RESOURCE);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
jid = xmppipe_getenv("XMPPIPE_USERNAME");
|
|
|
|
pass = xmppipe_getenv("XMPPIPE_PASSWORD");
|
|
|
|
|
2017-04-10 15:25:01 +00:00
|
|
|
if (state->verbose)
|
|
|
|
(void)fprintf(stderr, "sandbox: init: %s\n", XMPPIPE_SANDBOX);
|
|
|
|
|
|
|
|
if (xmppipe_sandbox_init(state) < 0)
|
|
|
|
err(EXIT_FAILURE, "sandbox failed");
|
|
|
|
|
2017-06-27 12:47:01 +00:00
|
|
|
while ( (ch = getopt_long(argc, argv, "a:b:c:dDehI:k:K:o:P:p:r:sS:u:U:vx",
|
|
|
|
long_options, NULL)) != -1) {
|
2015-05-11 19:19:35 +00:00
|
|
|
switch (ch) {
|
|
|
|
case 'u':
|
|
|
|
/* username/jid */
|
2016-10-08 15:10:15 +00:00
|
|
|
free(jid);
|
2015-05-11 19:19:35 +00:00
|
|
|
jid = xmppipe_strdup(optarg);
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
/* password */
|
2016-10-08 15:10:15 +00:00
|
|
|
free(pass);
|
2015-05-11 19:19:35 +00:00
|
|
|
pass = xmppipe_strdup(optarg);
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
/* output/muc */
|
2016-10-08 15:10:15 +00:00
|
|
|
free(state->room);
|
2015-05-11 19:19:35 +00:00
|
|
|
state->room = xmppipe_strdup(optarg);
|
|
|
|
break;
|
2015-05-16 13:54:35 +00:00
|
|
|
case 'a': {
|
2015-06-02 12:17:28 +00:00
|
|
|
/* address:port */
|
|
|
|
char *p = NULL;
|
2016-10-08 15:10:15 +00:00
|
|
|
free(addr);
|
2015-06-02 12:17:28 +00:00
|
|
|
addr = xmppipe_strdup(optarg);
|
|
|
|
p = strchr(addr, ':');
|
|
|
|
if (p) {
|
|
|
|
*p++ = '\0';
|
2017-03-18 12:00:59 +00:00
|
|
|
port = xmppipe_strtonum(state, p, 0, 0xfffe);
|
2015-06-02 12:17:28 +00:00
|
|
|
}
|
2015-05-16 13:54:35 +00:00
|
|
|
}
|
2015-06-02 12:17:28 +00:00
|
|
|
break;
|
2015-05-11 19:19:35 +00:00
|
|
|
case 'r':
|
2016-10-08 15:10:15 +00:00
|
|
|
free(state->resource);
|
2015-05-11 19:19:35 +00:00
|
|
|
state->resource = xmppipe_strdup(optarg);
|
|
|
|
break;
|
|
|
|
case 'S':
|
2016-10-08 15:10:15 +00:00
|
|
|
free(state->subject);
|
2015-05-11 19:19:35 +00:00
|
|
|
state->subject = xmppipe_strdup(optarg);
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
state->verbose++;
|
|
|
|
break;
|
2015-05-24 14:27:59 +00:00
|
|
|
case 'x':
|
|
|
|
state->encode = 1;
|
|
|
|
break;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-06-02 12:17:28 +00:00
|
|
|
case 'b':
|
|
|
|
/* read buffer size */
|
2017-03-18 12:00:59 +00:00
|
|
|
state->bufsz = xmppipe_strtonum(state, optarg, 3, 0xfffe);
|
2015-06-02 12:17:28 +00:00
|
|
|
break;
|
2015-06-01 13:39:22 +00:00
|
|
|
case 'c':
|
|
|
|
/* XEP-0198: stream management flow control */
|
2017-03-18 12:00:59 +00:00
|
|
|
state->sm_fc = xmppipe_strtonum(state, optarg, 0, 0xfffe);
|
2015-06-01 13:39:22 +00:00
|
|
|
break;
|
2015-05-16 18:45:22 +00:00
|
|
|
case 'I':
|
|
|
|
/* XEP-0198: stream management request interval */
|
2017-03-18 12:00:59 +00:00
|
|
|
state->sm_request_interval = xmppipe_strtonum(state, optarg, 0,
|
|
|
|
0xfffe);
|
2015-05-16 18:45:22 +00:00
|
|
|
break;
|
2015-05-11 19:19:35 +00:00
|
|
|
case 'k':
|
2015-05-16 18:45:22 +00:00
|
|
|
/* XEP-0199: XMPP ping keepalives */
|
2017-03-18 12:00:59 +00:00
|
|
|
state->sm_request_interval = xmppipe_strtonum(state, optarg, 0,
|
|
|
|
0xfffe) * 1000;
|
2015-05-11 19:19:35 +00:00
|
|
|
break;
|
2015-05-16 14:55:26 +00:00
|
|
|
case 'K':
|
2015-05-16 18:45:22 +00:00
|
|
|
/* XEP-0199: number of keepalive without a reply */
|
2017-03-18 12:00:59 +00:00
|
|
|
state->keepalive_limit = xmppipe_strtonum(state, optarg, 0,
|
|
|
|
0xfffe);
|
2015-05-16 14:55:26 +00:00
|
|
|
break;
|
2015-05-11 19:19:35 +00:00
|
|
|
case 'P':
|
|
|
|
/* poll delay */
|
2017-03-18 12:00:59 +00:00
|
|
|
state->poll = xmppipe_strtonum(state, optarg, 0, 0xfffe);
|
2015-05-11 19:19:35 +00:00
|
|
|
break;
|
2015-06-01 13:39:22 +00:00
|
|
|
case 'U':
|
|
|
|
/* XEP-0198: stream management unacked requests */
|
2017-03-18 12:00:59 +00:00
|
|
|
state->sm_unacked = xmppipe_strtonum(state, optarg, 0, 0xfffe);
|
2015-06-01 13:39:22 +00:00
|
|
|
break;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
case 'd':
|
|
|
|
state->opt |= XMPPIPE_OPT_DISCARD;
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
state->opt |= XMPPIPE_OPT_DISCARD;
|
|
|
|
state->opt |= XMPPIPE_OPT_DISCARD_TO_STDOUT;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
state->opt |= XMPPIPE_OPT_EOF;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
state->opt |= XMPPIPE_OPT_SIGPIPE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
usage(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-27 12:47:01 +00:00
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (jid == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
usage(state);
|
|
|
|
|
2017-03-17 12:13:23 +00:00
|
|
|
if (state->encode && BASE64_LENGTH(state->bufsz) + 1 > 0xffff)
|
2015-05-11 19:19:35 +00:00
|
|
|
usage(state);
|
|
|
|
|
2015-05-19 12:03:02 +00:00
|
|
|
if (state->keepalive_limit < 1)
|
2015-05-11 19:19:35 +00:00
|
|
|
usage(state);
|
|
|
|
|
|
|
|
state->server = xmppipe_servername(jid);
|
|
|
|
|
|
|
|
if (strchr(state->room, '@')) {
|
|
|
|
state->out = xmppipe_strdup(state->room);
|
|
|
|
state->mucjid = xmppipe_mucjid(state->out, state->resource);
|
|
|
|
}
|
|
|
|
|
2015-05-24 14:27:59 +00:00
|
|
|
if (xmppipe_fmt_init() < 0)
|
|
|
|
errx(EXIT_FAILURE, "xmppipe_fmt_init");
|
2015-05-14 10:55:48 +00:00
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
xmpp_initialize();
|
|
|
|
|
|
|
|
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
|
2015-05-22 13:48:15 +00:00
|
|
|
|
2015-05-12 18:09:14 +00:00
|
|
|
state->ctx = xmpp_ctx_new(NULL, (state->verbose > 1 ? log : NULL));
|
2015-07-21 13:44:08 +00:00
|
|
|
if (state->ctx == NULL)
|
2015-05-22 13:48:15 +00:00
|
|
|
errx(EXIT_FAILURE, "could not allocate context");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
state->conn = xmpp_conn_new(state->ctx);
|
2015-07-21 13:44:08 +00:00
|
|
|
if (state->conn == NULL)
|
2015-05-22 13:48:15 +00:00
|
|
|
errx(EXIT_FAILURE, "could not allocate connection");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmpp_conn_set_jid(state->conn, jid);
|
|
|
|
xmpp_conn_set_pass(state->conn, pass);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
if (xmpp_connect_client(state->conn, addr, port, handle_connection, state) < 0)
|
2015-05-21 14:11:22 +00:00
|
|
|
errx(EXIT_FAILURE, "connection failed");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
if (xmppipe_connect_init(state) < 0)
|
2015-06-02 12:17:28 +00:00
|
|
|
errx(EXIT_FAILURE, "XMPP handshake failed");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2017-02-03 14:47:12 +00:00
|
|
|
if (state->verbose)
|
2017-04-10 15:25:01 +00:00
|
|
|
(void)fprintf(stderr, "sandbox: stdin: %s\n", XMPPIPE_SANDBOX);
|
2017-02-03 14:47:12 +00:00
|
|
|
|
2017-04-10 15:25:01 +00:00
|
|
|
if (xmppipe_sandbox_stdin(state) < 0)
|
2017-01-29 14:13:18 +00:00
|
|
|
err(EXIT_FAILURE, "sandbox failed");
|
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
if (xmppipe_stream_init(state) < 0)
|
|
|
|
errx(EXIT_FAILURE, "enabling stream management failed");
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
if (xmppipe_muc_init(state) < 0)
|
2015-05-15 14:00:38 +00:00
|
|
|
errx(EXIT_FAILURE, "failed to join MUC");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
if (xmppipe_presence_init(state) < 0)
|
2015-05-15 14:00:38 +00:00
|
|
|
errx(EXIT_FAILURE, "publishing presence failed");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
if (state->subject)
|
2015-05-12 18:09:14 +00:00
|
|
|
xmppipe_muc_subject(state, state->subject);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
event_loop(state);
|
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_stream_close(state);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_conn_release(state->conn);
|
2015-05-11 19:19:35 +00:00
|
|
|
xmpp_ctx_free(state->ctx);
|
|
|
|
xmpp_shutdown();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
xmppipe_connect_init(xmppipe_state_t *state)
|
|
|
|
{
|
|
|
|
for ( ; ; ) {
|
|
|
|
xmpp_run_once(state->ctx, state->poll);
|
|
|
|
switch (state->status) {
|
|
|
|
case XMPPIPE_S_CONNECTED:
|
|
|
|
return 0;
|
|
|
|
case XMPPIPE_S_CONNECTING:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
int
|
|
|
|
xmppipe_stream_init(xmppipe_state_t *state)
|
|
|
|
{
|
|
|
|
xmpp_stanza_t *enable = NULL;
|
|
|
|
|
|
|
|
if (state->sm_request_interval == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* <enable xmlns='urn:xmpp:sm:3'/> */
|
2015-05-22 13:48:15 +00:00
|
|
|
enable = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(enable, "enable");
|
|
|
|
xmppipe_stanza_set_ns(enable, "urn:xmpp:sm:3");
|
2015-05-16 18:45:22 +00:00
|
|
|
xmpp_send(state->conn, enable);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(enable);
|
2015-05-16 18:45:22 +00:00
|
|
|
|
|
|
|
xmpp_handler_add(state->conn, handle_sm_enabled,
|
|
|
|
"urn:xmpp:sm:3", "enabled", NULL, state);
|
|
|
|
xmpp_handler_add(state->conn, handle_sm_request,
|
|
|
|
"urn:xmpp:sm:3", "r", NULL, state);
|
|
|
|
xmpp_handler_add(state->conn, handle_sm_ack,
|
|
|
|
"urn:xmpp:sm:3", "a", NULL, state);
|
|
|
|
|
|
|
|
/* XXX multiple handlers can be called for each event
|
|
|
|
* XXX
|
|
|
|
* XXX * is the order handlers are called determinisitc?
|
|
|
|
* XXX * the NULL handler needs to installed as soon as stream management is enabled
|
|
|
|
* XXX * a handler has to exist for unsupported events
|
|
|
|
*/
|
|
|
|
xmpp_handler_add(state->conn, handle_null, NULL, NULL, NULL, state);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
int
|
|
|
|
xmppipe_muc_init(xmppipe_state_t *state)
|
|
|
|
{
|
|
|
|
xmpp_stanza_t *presence = NULL;
|
|
|
|
xmpp_stanza_t *iq = NULL;
|
|
|
|
xmpp_stanza_t *query = NULL;
|
|
|
|
|
2015-05-13 11:37:34 +00:00
|
|
|
xmpp_handler_add(state->conn, handle_presence_error,
|
|
|
|
"http://jabber.org/protocol/muc", "presence", "error", state);
|
2015-05-11 19:19:35 +00:00
|
|
|
xmpp_handler_add(state->conn, handle_presence,
|
|
|
|
"http://jabber.org/protocol/muc#user", "presence", NULL, state);
|
|
|
|
xmpp_handler_add(state->conn, handle_version,
|
|
|
|
"jabber:iq:version", "iq", NULL, state);
|
|
|
|
xmpp_handler_add(state->conn, handle_message, NULL, "message", NULL, state);
|
2015-06-10 11:49:21 +00:00
|
|
|
xmpp_id_handler_add(state->conn, handle_ping_reply, "c2s1", state);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
/* Discover the MUC service */
|
2015-07-21 13:44:08 +00:00
|
|
|
if (state->out == NULL) {
|
2015-05-11 19:19:35 +00:00
|
|
|
xmpp_handler_add(state->conn, handle_disco_items,
|
|
|
|
"http://jabber.org/protocol/disco#items", "iq", "result",
|
|
|
|
state);
|
|
|
|
xmpp_handler_add(state->conn, handle_disco_info,
|
|
|
|
"http://jabber.org/protocol/disco#info", "iq", "result",
|
|
|
|
state);
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
iq = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(iq, "iq");
|
|
|
|
xmppipe_stanza_set_type(iq, "get");
|
|
|
|
xmppipe_stanza_set_attribute(iq, "to", state->server);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
query = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(query, "query");
|
|
|
|
xmppipe_stanza_set_ns(query, "http://jabber.org/protocol/disco#items");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmppipe_stanza_add_child(iq, query);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, iq);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(iq);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
state->status = XMPPIPE_S_MUC_SERVICE_LOOKUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send initial <presence/> so that we appear online to contacts */
|
2015-05-22 13:48:15 +00:00
|
|
|
presence = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(presence, "presence");
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, presence);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(presence);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
if (state->out) {
|
2015-05-12 18:09:14 +00:00
|
|
|
xmppipe_muc_join(state);
|
|
|
|
xmppipe_muc_unlock(state);
|
2015-05-11 19:19:35 +00:00
|
|
|
state->status = XMPPIPE_S_MUC_WAITJOIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
xmppipe_presence_init(xmppipe_state_t *state)
|
|
|
|
{
|
|
|
|
for ( ; ; ) {
|
|
|
|
xmpp_run_once(state->ctx, state->poll);
|
|
|
|
switch (state->status) {
|
|
|
|
case XMPPIPE_S_READY:
|
|
|
|
case XMPPIPE_S_READY_AVAIL:
|
|
|
|
case XMPPIPE_S_READY_EMPTY:
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
event_loop(xmppipe_state_t *state)
|
|
|
|
{
|
|
|
|
int fd = STDIN_FILENO;
|
|
|
|
int eof = 0;
|
|
|
|
char *buf = NULL;
|
|
|
|
|
|
|
|
if (xmppipe_set_nonblock(fd) < 0)
|
|
|
|
return;
|
|
|
|
|
2015-05-24 14:27:59 +00:00
|
|
|
buf = xmppipe_calloc(state->bufsz, 1);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
for ( ; ; ) {
|
|
|
|
if (state->status == XMPPIPE_S_DISCONNECTED)
|
|
|
|
goto XMPPIPE_EXIT;
|
|
|
|
|
2017-03-19 13:44:59 +00:00
|
|
|
if (state->sm_enabled) {
|
|
|
|
if (state->sm_ack_sent > state->sm_request)
|
|
|
|
errx(EXIT_FAILURE, "h too large: sent=%u, server responded=%u",
|
|
|
|
state->sm_request, state->sm_ack_sent);
|
|
|
|
|
|
|
|
if ( (state->sm_request_unack > state->sm_unacked)
|
|
|
|
|| (state->sm_request - state->sm_ack_sent > state->sm_fc)) {
|
|
|
|
if (state->verbose)
|
|
|
|
(void)fprintf(stderr,
|
|
|
|
"WAIT: request=%u ack_sent=%u unack=%u\n",
|
|
|
|
state->sm_request, state->sm_ack_sent,
|
|
|
|
state->sm_request_unack);
|
|
|
|
goto XMPPIPE_POLL;
|
|
|
|
}
|
2015-06-01 13:39:22 +00:00
|
|
|
}
|
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
if (eof) {
|
|
|
|
if (state->opt & XMPPIPE_OPT_EOF)
|
|
|
|
goto XMPPIPE_POLL;
|
|
|
|
|
|
|
|
if (state->sm_enabled && (state->sm_ack_sent < state->sm_request)) {
|
|
|
|
if (state->verbose)
|
|
|
|
(void)fprintf(stderr, "POLLING: request: %d ack: %d\n",
|
|
|
|
state->sm_request, state->sm_ack_sent);
|
|
|
|
goto XMPPIPE_POLL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
goto XMPPIPE_EXIT;
|
|
|
|
}
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
switch (handle_stdin(state, fd, buf, state->bufsz-1)) {
|
|
|
|
case -1:
|
|
|
|
goto XMPPIPE_EXIT;
|
|
|
|
case 0:
|
2015-05-16 18:45:22 +00:00
|
|
|
if (!(state->opt & XMPPIPE_OPT_EOF) && !state->sm_enabled)
|
2015-05-11 19:19:35 +00:00
|
|
|
goto XMPPIPE_EXIT;
|
|
|
|
|
|
|
|
eof = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
(void)memset(buf, '\0', state->bufsz);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->interval += state->poll;
|
|
|
|
|
2015-05-12 18:09:14 +00:00
|
|
|
XMPPIPE_POLL:
|
2015-05-19 12:03:02 +00:00
|
|
|
if (state->keepalive > 0 && state->interval > state->keepalive) {
|
2015-05-11 19:19:35 +00:00
|
|
|
xmppipe_ping(state);
|
|
|
|
state->interval = 0;
|
|
|
|
}
|
|
|
|
|
2015-05-16 14:55:26 +00:00
|
|
|
if (state->keepalive_fail > state->keepalive_limit)
|
|
|
|
errx(EXIT_FAILURE, "no response to keepalives");
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
xmpp_run_once(state->ctx, state->poll);
|
|
|
|
|
|
|
|
state->interval += state->poll;
|
|
|
|
|
|
|
|
if ((state->opt & XMPPIPE_OPT_SIGPIPE)
|
|
|
|
&& state->status == XMPPIPE_S_READY_EMPTY)
|
|
|
|
goto XMPPIPE_EXIT;
|
|
|
|
|
|
|
|
(void)fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
XMPPIPE_EXIT:
|
|
|
|
free(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
handle_stdin(xmppipe_state_t *state, int fd, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
fd_set rfds;
|
|
|
|
struct timeval tv = {0};
|
|
|
|
ssize_t n = 0;
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_usec = state->poll * 1000;
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(fd, &rfds);
|
|
|
|
|
2017-02-10 15:18:01 +00:00
|
|
|
rv = select(fd+1, &rfds, NULL, NULL, &tv);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
if (rv < 0) {
|
|
|
|
warn("select");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD_ISSET(fd, &rfds)) {
|
|
|
|
n = read(fd, buf, len);
|
|
|
|
|
2016-09-09 10:57:49 +00:00
|
|
|
if (n <= 0)
|
|
|
|
return n;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-24 14:27:59 +00:00
|
|
|
if (state->verbose > 2)
|
2015-05-11 19:19:35 +00:00
|
|
|
(void)fprintf(stderr, "STDIN:%s\n", buf);
|
|
|
|
|
|
|
|
/* read and discard the data */
|
|
|
|
if ((state->opt & XMPPIPE_OPT_DISCARD) && state->occupants == 0) {
|
|
|
|
if (state->opt & XMPPIPE_OPT_DISCARD_TO_STDOUT) {
|
|
|
|
char *enc = NULL;
|
2015-05-24 14:27:59 +00:00
|
|
|
enc = xmppipe_fmt(buf);
|
2015-05-11 19:19:35 +00:00
|
|
|
(void)printf("!:%s\n", enc);
|
2016-09-06 12:15:25 +00:00
|
|
|
(void)fflush(stdout);
|
2015-05-11 19:19:35 +00:00
|
|
|
free(enc);
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2015-05-24 14:27:59 +00:00
|
|
|
xmppipe_send_message(state, state->out, "groupchat", buf, n);
|
2015-05-11 19:19:35 +00:00
|
|
|
state->interval = 0;
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-05-16 18:45:22 +00:00
|
|
|
handle_connection(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
2015-05-11 19:19:35 +00:00
|
|
|
const int error, xmpp_stream_error_t * const stream_error,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
case XMPP_CONN_CONNECT:
|
|
|
|
if (state->verbose)
|
|
|
|
fprintf(stderr, "DEBUG: connected\n");
|
|
|
|
state->status = XMPPIPE_S_CONNECTED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
state->status = XMPPIPE_S_DISCONNECTED;
|
|
|
|
if (state->verbose)
|
|
|
|
fprintf(stderr, "DEBUG: disconnected\n");
|
2015-06-28 14:34:41 +00:00
|
|
|
errx(EXIT_FAILURE, "handle_connection: disconnected");
|
2015-05-11 19:19:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
int
|
|
|
|
handle_null(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = userdata;
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *name = NULL;
|
2015-05-16 18:45:22 +00:00
|
|
|
|
|
|
|
name = xmpp_stanza_get_name(stanza);
|
2015-07-21 13:44:08 +00:00
|
|
|
if (name == NULL)
|
2015-05-16 18:45:22 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (XMPPIPE_STREQ(name, "iq")
|
|
|
|
|| XMPPIPE_STREQ(name, "message")
|
|
|
|
|| XMPPIPE_STREQ(name, "presence"))
|
|
|
|
state->sm_ack_recv++;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
handle_sm_enabled(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
state->sm_enabled = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
handle_sm_request(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
|
|
|
|
xmpp_stanza_t *a = NULL;
|
|
|
|
char h[11] = {0};
|
|
|
|
|
|
|
|
if (state->sm_request % state->sm_request_interval != 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
(void)snprintf(h, sizeof(h), "%u", state->sm_ack_recv);
|
|
|
|
|
|
|
|
/* <a xmlns='urn:xmpp:sm:3' h='1'/> */
|
2015-05-22 13:48:15 +00:00
|
|
|
a = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(a, "a");
|
|
|
|
xmppipe_stanza_set_ns(a, "urn:xmpp:sm:3");
|
|
|
|
xmppipe_stanza_set_attribute(a, "h", h);
|
2015-05-16 18:45:22 +00:00
|
|
|
|
|
|
|
xmpp_send(state->conn, a);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(a);
|
2015-05-16 18:45:22 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
handle_sm_ack(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = userdata;
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *h = NULL;
|
2015-05-16 18:45:22 +00:00
|
|
|
u_int32_t ack = 0;
|
2017-03-05 14:15:22 +00:00
|
|
|
const char *errstr = NULL;
|
2015-05-16 18:45:22 +00:00
|
|
|
|
|
|
|
h = xmpp_stanza_get_attribute(stanza, "h");
|
2015-05-30 14:41:36 +00:00
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (h == NULL)
|
2015-05-30 14:41:36 +00:00
|
|
|
return 1;
|
|
|
|
|
2017-03-05 14:15:22 +00:00
|
|
|
ack = strtonum(h, 0, UINT_MAX-1, &errstr);
|
|
|
|
if (errstr)
|
|
|
|
goto XMPPIPE_STREAMERR;
|
2015-05-16 18:45:22 +00:00
|
|
|
|
|
|
|
if (state->verbose)
|
|
|
|
(void)fprintf(stderr, "SM: request=%u ack=%u last=%u\n",
|
|
|
|
state->sm_request, ack, state->sm_ack_sent);
|
|
|
|
|
2015-06-01 13:39:22 +00:00
|
|
|
state->sm_request_unack = 0;
|
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
/* Number of stanzas received by server exceeds the number sent by
|
|
|
|
* the client.
|
|
|
|
*/
|
|
|
|
if (ack > state->sm_request)
|
|
|
|
goto XMPPIPE_STREAMERR;
|
|
|
|
|
|
|
|
/* Server count not incremented since last request (stanzas may have
|
|
|
|
* been dropped).
|
|
|
|
*
|
|
|
|
* Could resend dropped stanzas.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
if (ack == state->sm_ack_sent)
|
|
|
|
goto XMPPIPE_STREAMERR;
|
|
|
|
|
|
|
|
state->sm_ack_sent = ack;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
XMPPIPE_STREAMERR:
|
|
|
|
xmppipe_stream_close(state);
|
|
|
|
errx(EXIT_FAILURE, "ack sequence mismatch: request=%u, ack=%u\n",
|
|
|
|
state->sm_request, state->sm_ack_sent);
|
|
|
|
}
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
int
|
|
|
|
handle_disco_items(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmpp_stanza_t *query, *item;
|
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
xmpp_ctx_t *ctx = state->ctx;
|
|
|
|
|
|
|
|
query = xmpp_stanza_get_child_by_name(stanza, "query");
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (query == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (item = xmpp_stanza_get_children(query); item != NULL;
|
|
|
|
item = xmpp_stanza_get_next(item)) {
|
|
|
|
xmpp_stanza_t *iq, *reply;
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *jid = NULL;
|
|
|
|
const char *name = NULL;
|
2015-05-30 14:41:36 +00:00
|
|
|
|
|
|
|
name = xmpp_stanza_get_name(item);
|
2015-07-21 13:44:08 +00:00
|
|
|
if (name == NULL)
|
2015-05-30 14:41:36 +00:00
|
|
|
continue;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-30 14:41:36 +00:00
|
|
|
if (XMPPIPE_STRNEQ(name, "item"))
|
2015-05-11 19:19:35 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
jid = xmpp_stanza_get_attribute(item, "jid");
|
2015-07-21 13:44:08 +00:00
|
|
|
if (jid == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
continue;
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
iq = xmppipe_stanza_new(ctx);
|
|
|
|
xmppipe_stanza_set_name(iq, "iq");
|
|
|
|
xmppipe_stanza_set_type(iq, "get");
|
|
|
|
xmppipe_stanza_set_attribute(iq, "to", jid);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
reply = xmppipe_stanza_new(ctx);
|
|
|
|
xmppipe_stanza_set_name(reply, "query");
|
|
|
|
xmppipe_stanza_set_ns(reply, "http://jabber.org/protocol/disco#info");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmppipe_stanza_add_child(iq, reply);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, iq);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(iq);
|
2015-05-11 19:19:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
handle_disco_info(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmpp_stanza_t *query, *child;
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *from = NULL;
|
2015-05-11 19:19:35 +00:00
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
|
|
|
|
from = xmpp_stanza_get_attribute(stanza, "from");
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (from == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
query = xmpp_stanza_get_child_by_name(stanza, "query");
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (query == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (child = xmpp_stanza_get_children(query); child != NULL;
|
|
|
|
child = xmpp_stanza_get_next(child)) {
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *feature = NULL;
|
|
|
|
const char *var = NULL;
|
2015-05-30 14:41:36 +00:00
|
|
|
|
|
|
|
feature = xmpp_stanza_get_name(child);
|
2015-07-21 13:44:08 +00:00
|
|
|
if (feature == NULL)
|
2015-05-30 14:41:36 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (XMPPIPE_STRNEQ(feature, "feature"))
|
2015-05-11 19:19:35 +00:00
|
|
|
continue;
|
|
|
|
|
2015-05-30 14:41:36 +00:00
|
|
|
var = xmpp_stanza_get_attribute(child, "var");
|
2015-07-21 13:44:08 +00:00
|
|
|
if (var == NULL)
|
2015-05-30 14:41:36 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (XMPPIPE_STRNEQ(var, "http://jabber.org/protocol/muc"))
|
2015-05-11 19:19:35 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
state->mucservice = xmppipe_strdup(from);
|
|
|
|
state->out = xmppipe_conference(state->room, state->mucservice);
|
|
|
|
state->mucjid = xmppipe_mucjid(state->out, state->resource);
|
|
|
|
|
2015-05-12 18:09:14 +00:00
|
|
|
xmppipe_muc_join(state);
|
|
|
|
xmppipe_muc_unlock(state);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
handle_version(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
2015-05-23 13:06:24 +00:00
|
|
|
xmpp_stanza_t *reply = NULL;
|
|
|
|
xmpp_stanza_t *query = NULL;
|
|
|
|
xmpp_stanza_t *name = NULL;
|
|
|
|
xmpp_stanza_t *version = NULL;
|
|
|
|
xmpp_stanza_t *text = NULL;
|
|
|
|
xmpp_stanza_t *child = NULL;
|
|
|
|
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *ns = NULL;
|
|
|
|
const char *id = NULL;
|
|
|
|
const char *from = NULL;
|
2015-05-23 13:06:24 +00:00
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
xmpp_ctx_t *ctx = state->ctx;
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
reply = xmppipe_stanza_new(ctx);
|
|
|
|
xmppipe_stanza_set_name(reply, "iq");
|
|
|
|
xmppipe_stanza_set_type(reply, "result");
|
2015-05-23 13:06:24 +00:00
|
|
|
|
|
|
|
id = xmpp_stanza_get_attribute(stanza, "from");
|
2015-07-21 13:44:08 +00:00
|
|
|
if (id == NULL)
|
2015-05-23 13:06:24 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
xmppipe_stanza_set_id(reply, id);
|
|
|
|
|
|
|
|
from = xmpp_stanza_get_attribute(stanza, "from");
|
2015-07-21 13:44:08 +00:00
|
|
|
if (from == NULL)
|
2015-05-30 14:41:36 +00:00
|
|
|
return 1;
|
|
|
|
|
2015-05-23 13:06:24 +00:00
|
|
|
xmppipe_stanza_set_attribute(reply, "to", from);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
query = xmppipe_stanza_new(ctx);
|
|
|
|
xmppipe_stanza_set_name(query, "query");
|
2015-05-23 13:06:24 +00:00
|
|
|
|
|
|
|
child = xmpp_stanza_get_children(stanza);
|
2015-07-21 13:44:08 +00:00
|
|
|
if (child == NULL) {
|
2015-05-23 13:06:24 +00:00
|
|
|
(void)xmpp_stanza_release(query);
|
|
|
|
return 1;
|
2015-05-11 19:19:35 +00:00
|
|
|
}
|
|
|
|
|
2015-05-23 13:06:24 +00:00
|
|
|
ns = xmpp_stanza_get_ns(child);
|
|
|
|
if (ns)
|
|
|
|
xmppipe_stanza_set_ns(query, ns);
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
name = xmppipe_stanza_new(ctx);
|
|
|
|
xmppipe_stanza_set_name(name, "name");
|
|
|
|
xmppipe_stanza_add_child(query, name);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
text = xmppipe_stanza_new(ctx);
|
|
|
|
xmppipe_stanza_set_text(text, "xmppipe");
|
|
|
|
xmppipe_stanza_add_child(name, text);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
version = xmppipe_stanza_new(ctx);
|
|
|
|
xmppipe_stanza_set_name(version, "version");
|
|
|
|
xmppipe_stanza_add_child(query, version);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
text = xmppipe_stanza_new(ctx);
|
|
|
|
xmppipe_stanza_set_text(text, XMPPIPE_VERSION);
|
|
|
|
xmppipe_stanza_add_child(version, text);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmppipe_stanza_add_child(reply, query);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, reply);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(reply);
|
2015-05-23 13:06:24 +00:00
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
handle_presence(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
xmpp_stanza_t *x = NULL;
|
|
|
|
xmpp_stanza_t *item = NULL;
|
|
|
|
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *from = NULL;
|
|
|
|
const char *to = NULL;
|
|
|
|
const char *type = NULL;
|
|
|
|
const char *code = NULL;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
char *efrom = NULL;
|
|
|
|
char *eto = NULL;
|
|
|
|
char *etype = NULL;
|
|
|
|
|
|
|
|
int me = 0;
|
|
|
|
|
|
|
|
from = xmpp_stanza_get_attribute(stanza, "from");
|
|
|
|
to = xmpp_stanza_get_attribute(stanza, "to");
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (from == NULL || to == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
x = xmpp_stanza_get_child_by_name(stanza, "x");
|
|
|
|
|
|
|
|
if (x) {
|
|
|
|
for (item = xmpp_stanza_get_children(x); item != NULL;
|
|
|
|
item = xmpp_stanza_get_next(item)) {
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *name = xmpp_stanza_get_name(item);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-06-11 13:55:54 +00:00
|
|
|
if (name && XMPPIPE_STREQ(name, "status")) {
|
2015-05-11 19:19:35 +00:00
|
|
|
code = xmpp_stanza_get_attribute(item, "code");
|
|
|
|
if (code && XMPPIPE_STREQ(code, "110")) {
|
|
|
|
/* Check for nick conflict */
|
|
|
|
if (XMPPIPE_STRNEQ(from, state->mucjid)) {
|
|
|
|
free(state->mucjid);
|
|
|
|
state->mucjid= xmppipe_strdup(from);
|
|
|
|
}
|
|
|
|
state->status = XMPPIPE_S_READY;
|
|
|
|
me = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* code ignored */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type = xmpp_stanza_get_attribute(stanza, "type");
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (type == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
type = "available";
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (me != 0 && XMPPIPE_STREQ(type, "available")) {
|
2015-05-11 19:19:35 +00:00
|
|
|
state->occupants++;
|
|
|
|
}
|
|
|
|
else if (XMPPIPE_STREQ(type, "unavailable") && (state->occupants > 0)) {
|
|
|
|
state->occupants--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->status == XMPPIPE_S_READY && state->occupants > 0)
|
|
|
|
state->status = XMPPIPE_S_READY_AVAIL;
|
|
|
|
|
|
|
|
if (state->status == XMPPIPE_S_READY_AVAIL && state->occupants == 0)
|
|
|
|
state->status = XMPPIPE_S_READY_EMPTY;
|
|
|
|
|
2015-05-24 14:27:59 +00:00
|
|
|
etype = xmppipe_fmt(type);
|
|
|
|
efrom = xmppipe_fmt(from);
|
|
|
|
eto = xmppipe_fmt(to);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
(void)printf("p:%s:%s:%s\n", etype, efrom, eto);
|
2016-09-06 12:15:25 +00:00
|
|
|
(void)fflush(stdout);
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
state->interval = 0;
|
|
|
|
|
|
|
|
free(etype);
|
|
|
|
free(efrom);
|
|
|
|
free(eto);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-05-13 11:37:34 +00:00
|
|
|
int
|
|
|
|
handle_presence_error(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
xmpp_stanza_t *error = NULL;
|
2015-05-23 13:06:24 +00:00
|
|
|
xmpp_stanza_t *child = NULL;
|
2015-05-13 11:37:34 +00:00
|
|
|
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *from = NULL;
|
|
|
|
const char *to = NULL;
|
|
|
|
const char *code = NULL;
|
|
|
|
const char *text = NULL;
|
2015-05-13 11:37:34 +00:00
|
|
|
|
|
|
|
from = xmpp_stanza_get_attribute(stanza, "from");
|
|
|
|
to = xmpp_stanza_get_attribute(stanza, "to");
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (from == NULL || to == NULL)
|
2015-05-13 11:37:34 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Check error is to our JID (user@example.org/binding) */
|
|
|
|
if (XMPPIPE_STRNEQ(to, xmpp_conn_get_bound_jid(conn)))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Check error is from our resource in the MUC (room@example.org/nick) */
|
|
|
|
if (XMPPIPE_STRNEQ(from, state->mucjid))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
error = xmpp_stanza_get_child_by_name(stanza, "error");
|
2015-07-21 13:44:08 +00:00
|
|
|
if (error == NULL)
|
2015-05-13 11:37:34 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
code = xmpp_stanza_get_attribute(error, "code");
|
2015-05-23 13:06:24 +00:00
|
|
|
child = xmpp_stanza_get_child_by_name(error, "text");
|
|
|
|
if (child)
|
|
|
|
text = xmpp_stanza_get_text(child);
|
2015-05-13 11:37:34 +00:00
|
|
|
|
|
|
|
errx(EXIT_FAILURE, "%s: %s", code ? code : "no error code specified",
|
|
|
|
text ? text : "no description");
|
|
|
|
}
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
handle_message(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
2015-05-23 13:06:24 +00:00
|
|
|
xmpp_stanza_t *child = NULL;
|
2015-05-11 19:19:35 +00:00
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
|
|
|
|
char *message = NULL;
|
2017-01-18 11:31:24 +00:00
|
|
|
const char *type = NULL;
|
|
|
|
const char *from = NULL;
|
|
|
|
const char *to = NULL;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
|
|
|
char *etype = NULL;
|
|
|
|
char *efrom = NULL;
|
2015-06-29 14:27:49 +00:00
|
|
|
char *eto = NULL;
|
2015-05-11 19:19:35 +00:00
|
|
|
char *emessage = NULL;
|
|
|
|
|
|
|
|
if (xmpp_stanza_get_child_by_name(stanza, "delay"))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
from = xmpp_stanza_get_attribute(stanza, "from");
|
2015-07-21 13:44:08 +00:00
|
|
|
if (from == NULL)
|
2015-05-30 14:41:36 +00:00
|
|
|
return 1;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-06-29 14:27:49 +00:00
|
|
|
to = xmpp_stanza_get_attribute(stanza, "to");
|
2015-07-21 13:44:08 +00:00
|
|
|
if (to == NULL)
|
2015-06-29 14:27:49 +00:00
|
|
|
return 1;
|
|
|
|
|
2015-05-30 14:41:36 +00:00
|
|
|
type = xmpp_stanza_get_type(stanza);
|
2015-07-21 13:44:08 +00:00
|
|
|
if (type == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Check if the message is from us */
|
|
|
|
if (XMPPIPE_STREQ(type, "groupchat") && XMPPIPE_STREQ(from, state->mucjid))
|
|
|
|
return 1;
|
|
|
|
|
2015-05-23 13:06:24 +00:00
|
|
|
child = xmpp_stanza_get_child_by_name(stanza, "body");
|
2015-07-21 13:44:08 +00:00
|
|
|
if (child == NULL)
|
2015-05-23 13:06:24 +00:00
|
|
|
return 1;
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-23 13:06:24 +00:00
|
|
|
message = xmpp_stanza_get_text(child);
|
2015-07-21 13:44:08 +00:00
|
|
|
if (message == NULL)
|
2015-05-11 19:19:35 +00:00
|
|
|
return 1;
|
|
|
|
|
2015-05-24 14:27:59 +00:00
|
|
|
if (state->encode) {
|
|
|
|
/* Does not need to be NULL terminated, buf is passed with length */
|
|
|
|
size_t len = strlen(message) * 3 / 4;
|
|
|
|
char *buf = xmppipe_calloc(len, 1);
|
2017-02-13 15:07:06 +00:00
|
|
|
int n = b64_pton(message, (u_char *)buf, len);
|
|
|
|
if (n <= 0 || n > len) {
|
|
|
|
/* Not a base64 message */
|
|
|
|
free(buf);
|
|
|
|
return 1;
|
|
|
|
}
|
2015-05-24 14:27:59 +00:00
|
|
|
emessage = xmppipe_nfmt(buf,n);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emessage = xmppipe_fmt(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
etype = xmppipe_fmt(type);
|
|
|
|
efrom = xmppipe_fmt(from);
|
2015-06-29 14:27:49 +00:00
|
|
|
eto = xmppipe_fmt(to);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-06-29 14:27:49 +00:00
|
|
|
(void)printf("m:%s:%s:%s:%s\n", etype, efrom, eto, emessage);
|
2016-09-06 12:15:25 +00:00
|
|
|
(void)fflush(stdout);
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
state->interval = 0;
|
|
|
|
|
|
|
|
free(message);
|
|
|
|
free(etype);
|
|
|
|
free(efrom);
|
2015-06-29 14:27:49 +00:00
|
|
|
free(eto);
|
2015-05-11 19:19:35 +00:00
|
|
|
free(emessage);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-05-16 14:55:26 +00:00
|
|
|
int
|
|
|
|
handle_ping_reply(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
|
|
|
|
void * const userdata)
|
|
|
|
{
|
|
|
|
xmppipe_state_t *state = userdata;
|
|
|
|
state->keepalive_fail = 0;
|
2015-06-10 11:49:21 +00:00
|
|
|
return 1;
|
2015-05-16 14:55:26 +00:00
|
|
|
}
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
void
|
2015-05-12 18:09:14 +00:00
|
|
|
xmppipe_muc_join(xmppipe_state_t *state)
|
2015-05-11 19:19:35 +00:00
|
|
|
{
|
|
|
|
xmpp_stanza_t *presence = NULL;
|
|
|
|
xmpp_stanza_t *x = NULL;
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
presence = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(presence, "presence");
|
|
|
|
xmppipe_stanza_set_attribute(presence, "to", state->mucjid);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
x = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(x, "x");
|
|
|
|
xmppipe_stanza_set_ns(x, "http://jabber.org/protocol/muc");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmppipe_stanza_add_child(presence, x);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, presence);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(presence);
|
2015-05-11 19:19:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-05-12 18:09:14 +00:00
|
|
|
xmppipe_muc_unlock(xmppipe_state_t *state)
|
2015-05-11 19:19:35 +00:00
|
|
|
{
|
|
|
|
xmpp_stanza_t *iq = NULL;
|
|
|
|
xmpp_stanza_t *q= NULL;
|
|
|
|
xmpp_stanza_t *x = NULL;
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
iq = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(iq, "iq");
|
|
|
|
xmppipe_stanza_set_attribute(iq, "to", state->out);
|
|
|
|
xmppipe_stanza_set_attribute(iq, "id", "create1");
|
|
|
|
xmppipe_stanza_set_attribute(iq, "type", "set");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
q = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(q, "query");
|
|
|
|
xmppipe_stanza_set_ns(q, "http://jabber.org/protocol/muc#owner");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
x = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(x, "x");
|
|
|
|
xmppipe_stanza_set_ns(x, "jabber:x:data");
|
|
|
|
xmppipe_stanza_set_attribute(x, "type", "submit");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmppipe_stanza_add_child(q, x);
|
|
|
|
xmppipe_stanza_add_child(iq, q);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, iq);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(iq);
|
2015-05-11 19:19:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-05-12 18:09:14 +00:00
|
|
|
xmppipe_muc_subject(xmppipe_state_t *state, char *buf)
|
2015-05-11 19:19:35 +00:00
|
|
|
{
|
|
|
|
xmpp_stanza_t *message = NULL;
|
|
|
|
xmpp_stanza_t *subject= NULL;
|
|
|
|
xmpp_stanza_t *text= NULL;
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
message = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(message, "message");
|
|
|
|
xmppipe_stanza_set_attribute(message, "to", state->out);
|
|
|
|
xmppipe_stanza_set_attribute(message, "type", "groupchat");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
subject = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(subject, "subject");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
text = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_text(text, buf);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmppipe_stanza_add_child(subject, text);
|
|
|
|
xmppipe_stanza_add_child(message, subject);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, message);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(message);
|
2015-05-11 19:19:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-05-24 14:27:59 +00:00
|
|
|
xmppipe_send_message(xmppipe_state_t *state, char *to, char *type, char *buf,
|
|
|
|
size_t len)
|
2015-05-11 19:19:35 +00:00
|
|
|
{
|
|
|
|
xmpp_stanza_t *message = NULL;
|
|
|
|
xmpp_stanza_t *body = NULL;
|
|
|
|
xmpp_stanza_t *text = NULL;
|
2015-05-14 10:55:48 +00:00
|
|
|
char *id = NULL;
|
|
|
|
|
|
|
|
id = xmppipe_id_alloc();
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2016-10-28 14:13:49 +00:00
|
|
|
if (id == NULL) {
|
|
|
|
errx(EXIT_FAILURE, "unable to allocate message id");
|
|
|
|
}
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
message = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(message, "message");
|
|
|
|
xmppipe_stanza_set_type(message, type);
|
|
|
|
xmppipe_stanza_set_attribute(message, "to", to);
|
|
|
|
xmppipe_stanza_set_id(message, id);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
body = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(body, "body");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
text = xmppipe_stanza_new(state->ctx);
|
2015-05-24 14:27:59 +00:00
|
|
|
|
|
|
|
if (state->encode) {
|
|
|
|
size_t b64len = BASE64_LENGTH(len) + 1; /* Include trailing NULL */
|
|
|
|
char *b64 = xmppipe_calloc(b64len, 1);
|
|
|
|
if (b64_ntop((u_char *)buf, len, b64, b64len) < 0)
|
2015-05-26 11:43:45 +00:00
|
|
|
errx(EXIT_FAILURE, "encode: invalid input: %zu/%zu", len, b64len);
|
2015-05-24 14:27:59 +00:00
|
|
|
xmppipe_stanza_set_text(text, b64);
|
|
|
|
free(b64);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
xmppipe_stanza_set_text(text, buf);
|
|
|
|
}
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmppipe_stanza_add_child(body, text);
|
|
|
|
xmppipe_stanza_add_child(message, body);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, message);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(message);
|
2015-05-14 10:55:48 +00:00
|
|
|
free(id);
|
2015-05-11 19:19:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xmppipe_ping(xmppipe_state_t *state)
|
|
|
|
{
|
|
|
|
xmpp_stanza_t *iq = NULL;
|
|
|
|
xmpp_stanza_t *ping = NULL;
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
iq = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(iq, "iq");
|
|
|
|
xmppipe_stanza_set_type(iq, "get");
|
|
|
|
xmppipe_stanza_set_id(iq, "c2s1");
|
|
|
|
xmppipe_stanza_set_attribute(iq, "from", xmpp_conn_get_bound_jid(state->conn));
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
ping = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(ping, "ping");
|
|
|
|
xmppipe_stanza_set_ns(ping, "urn:xmpp:ping");
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
xmppipe_stanza_add_child(iq, ping);
|
2015-05-11 19:19:35 +00:00
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
xmppipe_send(state, iq);
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(iq);
|
2015-05-16 14:55:26 +00:00
|
|
|
|
|
|
|
state->keepalive_fail++;
|
2015-05-11 19:19:35 +00:00
|
|
|
}
|
|
|
|
|
2015-05-16 18:45:22 +00:00
|
|
|
void
|
|
|
|
xmppipe_send(xmppipe_state_t *state, xmpp_stanza_t *const stanza)
|
|
|
|
{
|
|
|
|
xmpp_stanza_t *r = NULL;
|
|
|
|
|
|
|
|
state->sm_request++;
|
|
|
|
|
|
|
|
xmpp_send(state->conn, stanza);
|
|
|
|
|
2015-07-21 13:44:08 +00:00
|
|
|
if (state->sm_enabled == 0)
|
2015-05-16 18:45:22 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (state->sm_request % state->sm_request_interval != 0)
|
|
|
|
return;
|
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
r = xmppipe_stanza_new(state->ctx);
|
|
|
|
xmppipe_stanza_set_name(r, "r");
|
|
|
|
xmppipe_stanza_set_ns(r, "urn:xmpp:sm:3");
|
2015-05-16 18:45:22 +00:00
|
|
|
xmpp_send(state->conn, r);
|
2015-06-01 13:39:22 +00:00
|
|
|
state->sm_request_unack++;
|
2015-05-16 18:45:22 +00:00
|
|
|
|
2015-05-22 13:48:15 +00:00
|
|
|
(void)xmpp_stanza_release(r);
|
2015-05-16 18:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xmppipe_stream_close(xmppipe_state_t *state)
|
|
|
|
{
|
|
|
|
if (state->sm_enabled)
|
|
|
|
xmpp_send_raw_string(state->conn, "</stream:stream>");
|
|
|
|
}
|
|
|
|
|
2017-03-18 12:00:59 +00:00
|
|
|
static long long
|
|
|
|
xmppipe_strtonum(xmppipe_state_t *state, const char *nptr, long long minval,
|
|
|
|
long long maxval)
|
|
|
|
{
|
|
|
|
long long n = 0;
|
|
|
|
const char *errstr = NULL;
|
|
|
|
|
|
|
|
n = strtonum(nptr, minval, maxval, &errstr);
|
|
|
|
if (errstr)
|
|
|
|
errx(EXIT_FAILURE, "%s: %s", errstr, nptr);
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2015-05-11 19:19:35 +00:00
|
|
|
static void
|
|
|
|
usage(xmppipe_state_t *state)
|
|
|
|
{
|
2017-02-06 15:03:06 +00:00
|
|
|
(void)fprintf(stderr, "%s %s (%s)\n",
|
|
|
|
__progname, XMPPIPE_VERSION, XMPPIPE_SANDBOX);
|
2015-05-11 19:19:35 +00:00
|
|
|
(void)fprintf(stderr,
|
2017-06-27 12:47:01 +00:00
|
|
|
"usage: %s [OPTIONS]\n"
|
|
|
|
" -u, --user <jid> username (aka JID)\n"
|
|
|
|
" -p, --passord <password> password\n"
|
|
|
|
" -r, --resource <resource> resource (aka MUC nick)\n"
|
|
|
|
" -o, --output <output> MUC room to send stdout\n"
|
|
|
|
" -S, --subject <subject> set MUC subject\n"
|
|
|
|
" -a, --address <addr:port> set XMPP server address (port is optional)\n"
|
|
|
|
|
|
|
|
" -d, --discard discard stdin when MUC is empty\n"
|
|
|
|
" -D, --discard-to-stdout discard stdin and print to local stdout\n"
|
|
|
|
" -e, --ignore-eof ignore stdin EOF\n"
|
|
|
|
" -s, --exit-when-empty exit when MUC is empty\n"
|
|
|
|
" -x, --base64 base64 encode/decode data\n"
|
|
|
|
|
|
|
|
" -b, --buffer-size <size> size of read buffer\n"
|
|
|
|
" -I, --interval <interval> request stream management status every interval messages\n"
|
|
|
|
" -k, --keepalives <seconds> periodically send a keepalive\n"
|
|
|
|
" -K, --keepalive-failures <count> number of keepalive failures before exiting\n"
|
|
|
|
" -P, --poll-delay <ms> poll delay\n"
|
|
|
|
" -v, --verbose verbose\n",
|
2015-05-11 19:19:35 +00:00
|
|
|
__progname
|
|
|
|
);
|
|
|
|
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|