Transparently base64 encode data to MUC

Optionally base64 encode data sent to and from a conference, allowing
transfer of binary data.

This could also be accomplished by piping in base64 encoded data:

    base64 /bin/ls | xmppipe

However the base64 command does not work with streams of data.
pull/1/head
Michael Santos 9 years ago
parent bcf7c1b2e8
commit 3ae0a9f88f

@ -14,6 +14,7 @@
*/
#include "xmppipe.h"
#include <resolv.h>
#include <sys/select.h>
#include <sys/types.h>
@ -48,7 +49,7 @@ void xmppipe_stream_close(xmppipe_state_t *);
void xmppipe_muc_join(xmppipe_state_t *);
void xmppipe_muc_unlock(xmppipe_state_t *);
void xmppipe_muc_subject(xmppipe_state_t *, char *);
void xmppipe_send_message(xmppipe_state_t *, char *, char *, char *);
void xmppipe_send_message(xmppipe_state_t *, char *, char *, char *, size_t);
void xmppipe_send(xmppipe_state_t *, xmpp_stanza_t *const);
void xmppipe_ping(xmppipe_state_t *);
@ -76,7 +77,7 @@ main(int argc, char **argv)
jid = xmppipe_getenv("XMPPIPE_USERNAME");
pass = xmppipe_getenv("XMPPIPE_PASSWORD");
while ( (ch = getopt(argc, argv, "a:dDehI:k:K:m:o:P:p:r:sS:u:v")) != -1) {
while ( (ch = getopt(argc, argv, "a:dDehI:k:K:m:o:P:p:r:sS:u:vx")) != -1) {
switch (ch) {
case 'u':
/* username/jid */
@ -109,6 +110,9 @@ main(int argc, char **argv)
case 'v':
state->verbose++;
break;
case 'x':
state->encode = 1;
break;
case 'I':
/* XEP-0198: stream management request interval */
@ -154,7 +158,8 @@ main(int argc, char **argv)
if (!jid)
usage(state);
if (state->bufsz < 3 || state->bufsz >= 0xffff)
if (state->bufsz < 3 || state->bufsz >= 0xffff
|| (state->encode && BASE64_LENGTH(state->bufsz) + 1 > 0xffff))
usage(state);
if (state->keepalive_limit < 1)
@ -173,8 +178,8 @@ main(int argc, char **argv)
state->mucjid = xmppipe_mucjid(state->out, state->resource);
}
if (xmppipe_encode_init() < 0)
errx(EXIT_FAILURE, "xmppipe_encode_init");
if (xmppipe_fmt_init() < 0)
errx(EXIT_FAILURE, "xmppipe_fmt_init");
xmpp_initialize();
@ -350,7 +355,7 @@ event_loop(xmppipe_state_t *state)
if (xmppipe_set_nonblock(fd) < 0)
return;
buf = xmppipe_calloc(1, state->bufsz);
buf = xmppipe_calloc(state->bufsz, 1);
for ( ; ; ) {
if (state->status == XMPPIPE_S_DISCONNECTED)
@ -444,21 +449,21 @@ handle_stdin(xmppipe_state_t *state, int fd, char *buf, size_t len)
if (n == 0)
return 0;
if (state->verbose)
if (state->verbose > 2)
(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;
enc = xmppipe_encode(buf);
enc = xmppipe_fmt(buf);
(void)printf("!:%s\n", enc);
free(enc);
}
return 2;
}
xmppipe_send_message(state, state->out, "groupchat", buf);
xmppipe_send_message(state, state->out, "groupchat", buf, n);
state->interval = 0;
return 3;
}
@ -798,9 +803,9 @@ handle_presence(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
if (state->status == XMPPIPE_S_READY_AVAIL && state->occupants == 0)
state->status = XMPPIPE_S_READY_EMPTY;
etype = xmppipe_encode(type);
efrom = xmppipe_encode(from);
eto = xmppipe_encode(to);
etype = xmppipe_fmt(type);
efrom = xmppipe_fmt(from);
eto = xmppipe_fmt(to);
(void)printf("p:%s:%s:%s\n", etype, efrom, eto);
state->interval = 0;
@ -892,9 +897,22 @@ handle_message(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
if (!message)
return 1;
etype = xmppipe_encode(type);
efrom = xmppipe_encode(from);
emessage = xmppipe_encode(message);
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);
size_t n = b64_pton(message, (u_char *)buf, len);
if (n < 0)
errx(EXIT_FAILURE, "invalid base64 message");
emessage = xmppipe_nfmt(buf,n);
free(buf);
}
else {
emessage = xmppipe_fmt(message);
}
etype = xmppipe_fmt(type);
efrom = xmppipe_fmt(from);
(void)printf("m:%s:%s:%s\n", etype, efrom, emessage);
state->interval = 0;
@ -991,7 +1009,8 @@ xmppipe_muc_subject(xmppipe_state_t *state, char *buf)
}
void
xmppipe_send_message(xmppipe_state_t *state, char *to, char *type, char *buf)
xmppipe_send_message(xmppipe_state_t *state, char *to, char *type, char *buf,
size_t len)
{
xmpp_stanza_t *message = NULL;
xmpp_stanza_t *body = NULL;
@ -1010,7 +1029,18 @@ xmppipe_send_message(xmppipe_state_t *state, char *to, char *type, char *buf)
xmppipe_stanza_set_name(body, "body");
text = xmppipe_stanza_new(state->ctx);
xmppipe_stanza_set_text(text, buf);
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)
errx(EXIT_FAILURE, "encode: invalid input: %u/%u", len, b64len);
xmppipe_stanza_set_text(text, b64);
free(b64);
}
else {
xmppipe_stanza_set_text(text, buf);
}
xmppipe_stanza_add_child(body, text);
xmppipe_stanza_add_child(message, body);
@ -1093,6 +1123,7 @@ usage(xmppipe_state_t *state)
" -D discard stdin and print to local stdout\n"
" -e ignore stdin EOF\n"
" -s exit when MUC is empty\n"
" -x base64 encode/decode data\n"
" -I <interval> request stream management status ever interval messages\n"
" -k <ms> periodically send a keepalive\n"

@ -21,11 +21,13 @@
#include <strophe.h>
#define XMPPIPE_VERSION "0.5.0"
#define XMPPIPE_VERSION "0.6.0"
#define XMPPIPE_STREQ(a,b) !strcmp((a),(b))
#define XMPPIPE_STRNEQ(a,b) strcmp((a),(b))
#define BASE64_LENGTH(n) ((((n) + 2) / 3) * 4)
enum {
XMPPIPE_S_DISCONNECTED,
XMPPIPE_S_CONNECTING,
@ -81,11 +83,13 @@ typedef struct {
int opt;
int verbose;
int encode; /* base64 encode/decode data to MUC */
} xmppipe_state_t;
int xmppipe_encode_init();
char *xmppipe_encode(const char *);
int xmppipe_fmt_init();
char *xmppipe_fmt(const char *);
char *xmppipe_nfmt(const char *, size_t);
char *xmppipe_id_alloc();
int xmppipe_set_nonblock(int fd);
@ -108,3 +112,7 @@ void xmppipe_stanza_set_ns(xmpp_stanza_t * const, const char * const);
void xmppipe_stanza_set_text(xmpp_stanza_t *, const char * const);
void xmppipe_stanza_set_type(xmpp_stanza_t * const, const char * const);
void xmppipe_stanza_add_child(xmpp_stanza_t *, xmpp_stanza_t *);
int b64_ntop(u_char const *src, size_t srclength, char *target,
size_t targsize);
int b64_pton(char const *src, u_char *target, size_t targsize);

@ -17,7 +17,7 @@
static unsigned char rfc3986[256];
int
xmppipe_encode_init()
xmppipe_fmt_init()
{
int i = 0;
@ -27,18 +27,17 @@ xmppipe_encode_init()
return 0;
}
char *
xmppipe_encode(const char *s)
xmppipe_nfmt(const char *s, size_t len)
{
// XXX overflow
size_t len = strlen(s);
char *buf = xmppipe_calloc(1, len * 3 + 1);
char *buf = xmppipe_calloc(len * 3 + 1, 1);
char *p = buf;
int n = 0;
int i = 0;
for (; *s; s++) {
// XXX signed
unsigned char c = *s;
for (i = 0; i < len; i++) {
unsigned char c = s[i];
n = rfc3986[c]
? sprintf(p, "%c", rfc3986[c])
: sprintf(p, "%%%02X", c);
@ -47,3 +46,9 @@ xmppipe_encode(const char *s)
return buf;
}
char *
xmppipe_fmt(const char *s)
{
return xmppipe_nfmt(s, strlen(s));
}

@ -22,7 +22,7 @@ xmppipe_id_alloc()
uuid_t uu = {0};
char *out = NULL;
out = xmppipe_calloc(1,37);
out = xmppipe_calloc(37,1);
uuid_generate(uu);
uuid_unparse(uu, out);

Loading…
Cancel
Save