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 "xmppipe.h"
#include <resolv.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/types.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_join(xmppipe_state_t *);
void xmppipe_muc_unlock(xmppipe_state_t *); void xmppipe_muc_unlock(xmppipe_state_t *);
void xmppipe_muc_subject(xmppipe_state_t *, char *); 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_send(xmppipe_state_t *, xmpp_stanza_t *const);
void xmppipe_ping(xmppipe_state_t *); void xmppipe_ping(xmppipe_state_t *);
@ -76,7 +77,7 @@ main(int argc, char **argv)
jid = xmppipe_getenv("XMPPIPE_USERNAME"); jid = xmppipe_getenv("XMPPIPE_USERNAME");
pass = xmppipe_getenv("XMPPIPE_PASSWORD"); 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) { switch (ch) {
case 'u': case 'u':
/* username/jid */ /* username/jid */
@ -109,6 +110,9 @@ main(int argc, char **argv)
case 'v': case 'v':
state->verbose++; state->verbose++;
break; break;
case 'x':
state->encode = 1;
break;
case 'I': case 'I':
/* XEP-0198: stream management request interval */ /* XEP-0198: stream management request interval */
@ -154,7 +158,8 @@ main(int argc, char **argv)
if (!jid) if (!jid)
usage(state); 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); usage(state);
if (state->keepalive_limit < 1) if (state->keepalive_limit < 1)
@ -173,8 +178,8 @@ main(int argc, char **argv)
state->mucjid = xmppipe_mucjid(state->out, state->resource); state->mucjid = xmppipe_mucjid(state->out, state->resource);
} }
if (xmppipe_encode_init() < 0) if (xmppipe_fmt_init() < 0)
errx(EXIT_FAILURE, "xmppipe_encode_init"); errx(EXIT_FAILURE, "xmppipe_fmt_init");
xmpp_initialize(); xmpp_initialize();
@ -350,7 +355,7 @@ event_loop(xmppipe_state_t *state)
if (xmppipe_set_nonblock(fd) < 0) if (xmppipe_set_nonblock(fd) < 0)
return; return;
buf = xmppipe_calloc(1, state->bufsz); buf = xmppipe_calloc(state->bufsz, 1);
for ( ; ; ) { for ( ; ; ) {
if (state->status == XMPPIPE_S_DISCONNECTED) 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) if (n == 0)
return 0; return 0;
if (state->verbose) if (state->verbose > 2)
(void)fprintf(stderr, "STDIN:%s\n", buf); (void)fprintf(stderr, "STDIN:%s\n", buf);
/* read and discard the data */ /* read and discard the data */
if ((state->opt & XMPPIPE_OPT_DISCARD) && state->occupants == 0) { if ((state->opt & XMPPIPE_OPT_DISCARD) && state->occupants == 0) {
if (state->opt & XMPPIPE_OPT_DISCARD_TO_STDOUT) { if (state->opt & XMPPIPE_OPT_DISCARD_TO_STDOUT) {
char *enc = NULL; char *enc = NULL;
enc = xmppipe_encode(buf); enc = xmppipe_fmt(buf);
(void)printf("!:%s\n", enc); (void)printf("!:%s\n", enc);
free(enc); free(enc);
} }
return 2; return 2;
} }
xmppipe_send_message(state, state->out, "groupchat", buf); xmppipe_send_message(state, state->out, "groupchat", buf, n);
state->interval = 0; state->interval = 0;
return 3; 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) if (state->status == XMPPIPE_S_READY_AVAIL && state->occupants == 0)
state->status = XMPPIPE_S_READY_EMPTY; state->status = XMPPIPE_S_READY_EMPTY;
etype = xmppipe_encode(type); etype = xmppipe_fmt(type);
efrom = xmppipe_encode(from); efrom = xmppipe_fmt(from);
eto = xmppipe_encode(to); eto = xmppipe_fmt(to);
(void)printf("p:%s:%s:%s\n", etype, efrom, eto); (void)printf("p:%s:%s:%s\n", etype, efrom, eto);
state->interval = 0; state->interval = 0;
@ -892,9 +897,22 @@ handle_message(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
if (!message) if (!message)
return 1; return 1;
etype = xmppipe_encode(type); if (state->encode) {
efrom = xmppipe_encode(from); /* Does not need to be NULL terminated, buf is passed with length */
emessage = xmppipe_encode(message); 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); (void)printf("m:%s:%s:%s\n", etype, efrom, emessage);
state->interval = 0; state->interval = 0;
@ -991,7 +1009,8 @@ xmppipe_muc_subject(xmppipe_state_t *state, char *buf)
} }
void 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 *message = NULL;
xmpp_stanza_t *body = 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"); xmppipe_stanza_set_name(body, "body");
text = xmppipe_stanza_new(state->ctx); 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(body, text);
xmppipe_stanza_add_child(message, body); xmppipe_stanza_add_child(message, body);
@ -1093,6 +1123,7 @@ usage(xmppipe_state_t *state)
" -D discard stdin and print to local stdout\n" " -D discard stdin and print to local stdout\n"
" -e ignore stdin EOF\n" " -e ignore stdin EOF\n"
" -s exit when MUC is empty\n" " -s exit when MUC is empty\n"
" -x base64 encode/decode data\n"
" -I <interval> request stream management status ever interval messages\n" " -I <interval> request stream management status ever interval messages\n"
" -k <ms> periodically send a keepalive\n" " -k <ms> periodically send a keepalive\n"

@ -21,11 +21,13 @@
#include <strophe.h> #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_STREQ(a,b) !strcmp((a),(b))
#define XMPPIPE_STRNEQ(a,b) strcmp((a),(b)) #define XMPPIPE_STRNEQ(a,b) strcmp((a),(b))
#define BASE64_LENGTH(n) ((((n) + 2) / 3) * 4)
enum { enum {
XMPPIPE_S_DISCONNECTED, XMPPIPE_S_DISCONNECTED,
XMPPIPE_S_CONNECTING, XMPPIPE_S_CONNECTING,
@ -81,11 +83,13 @@ typedef struct {
int opt; int opt;
int verbose; int verbose;
int encode; /* base64 encode/decode data to MUC */
} xmppipe_state_t; } xmppipe_state_t;
int xmppipe_encode_init(); int xmppipe_fmt_init();
char *xmppipe_encode(const char *); char *xmppipe_fmt(const char *);
char *xmppipe_nfmt(const char *, size_t);
char *xmppipe_id_alloc(); char *xmppipe_id_alloc();
int xmppipe_set_nonblock(int fd); 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_text(xmpp_stanza_t *, const char * const);
void xmppipe_stanza_set_type(xmpp_stanza_t * const, 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 *); 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]; static unsigned char rfc3986[256];
int int
xmppipe_encode_init() xmppipe_fmt_init()
{ {
int i = 0; int i = 0;
@ -27,18 +27,17 @@ xmppipe_encode_init()
return 0; return 0;
} }
char * char *
xmppipe_encode(const char *s) xmppipe_nfmt(const char *s, size_t len)
{ {
// XXX overflow char *buf = xmppipe_calloc(len * 3 + 1, 1);
size_t len = strlen(s);
char *buf = xmppipe_calloc(1, len * 3 + 1);
char *p = buf; char *p = buf;
int n = 0; int n = 0;
int i = 0;
for (; *s; s++) { for (i = 0; i < len; i++) {
// XXX signed unsigned char c = s[i];
unsigned char c = *s;
n = rfc3986[c] n = rfc3986[c]
? sprintf(p, "%c", rfc3986[c]) ? sprintf(p, "%c", rfc3986[c])
: sprintf(p, "%%%02X", c); : sprintf(p, "%%%02X", c);
@ -47,3 +46,9 @@ xmppipe_encode(const char *s)
return buf; 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}; uuid_t uu = {0};
char *out = NULL; char *out = NULL;
out = xmppipe_calloc(1,37); out = xmppipe_calloc(37,1);
uuid_generate(uu); uuid_generate(uu);
uuid_unparse(uu, out); uuid_unparse(uu, out);

Loading…
Cancel
Save