You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xmppipe/src/xmppipe_util.c

280 lines
7.3 KiB
C

/* Copyright (c) 2015-2023, Michael Santos <michael.santos@gmail.com>
*
* 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 <fcntl.h>
#define XMPPIPE_NULL(a_) \
if ((a_) == NULL) { \
errx(3, "invalid argument: %s/%s (%s:%d)", __FUNCTION__, #a_, __FILE__, \
__LINE__); \
}
const char *const xmppipe_states[] = {"XMPPIPE_S_DISCONNECTED",
"XMPPIPE_S_CONNECTING",
"XMPPIPE_S_CONNECTED",
"XMPPIPE_S_MUC_SERVICE_LOOKUP",
"XMPPIPE_S_MUC_FEATURE_LOOKUP",
"XMPPIPE_S_MUC_WAITJOIN",
"XMPPIPE_S_MUC_JOIN",
"XMPPIPE_S_MUC_UNLOCK",
"XMPPIPE_S_READY",
"XMPPIPE_S_READY_AVAIL",
"XMPPIPE_S_READY_EMPTY"};
static char *xmppipe_join(const char *prefix, const char *delimiter, const char *suffix);
char *xmppipe_getenv(const char *s) {
char *p = getenv(s);
if (p == NULL)
return NULL;
return xmppipe_strdup(p);
}
char *xmppipe_strdup(const char *s) {
char *buf;
if (s == NULL)
errx(2, "invalid string");
buf = strdup(s);
if (buf == NULL)
err(3, "xmppipe_strdup");
return buf;
}
void *xmppipe_malloc(size_t size) {
char *buf;
if (size == 0 || size > 0xffff)
errx(2, "invalid size: %zd", size);
buf = malloc(size);
if (buf == NULL)
err(3, "xmppipe_malloc: %zu", size);
return buf;
}
void *xmppipe_calloc(size_t nmemb, size_t size) {
char *buf;
buf = calloc(nmemb, size);
if (buf == NULL)
err(3, "xmppipe_calloc: %zu/%zu", nmemb, size);
return buf;
}
xmpp_stanza_t *xmppipe_message_new(xmpp_ctx_t *ctx, const char *const type,
const char *const to, const char *const id) {
xmpp_stanza_t *m = xmpp_message_new(ctx, type, to, id);
if (m == NULL)
err(3, "xmppipe_message_new");
return m;
}
void xmppipe_message_set_body(xmpp_stanza_t *msg, const char *const text) {
int rv;
rv = xmpp_message_set_body(msg, text);
if (rv != XMPP_EOK)
errx(EXIT_FAILURE, "xmpp_message_set_body: %u", rv);
}
xmpp_stanza_t *xmppipe_stanza_reply(xmpp_stanza_t *const stanza) {
xmpp_stanza_t *s = xmpp_stanza_reply(stanza);
if (s == NULL)
err(3, "xmppipe_stanza_reply");
return s;
}
xmpp_stanza_t *xmppipe_stanza_new(xmpp_ctx_t *ctx) {
xmpp_stanza_t *s = xmpp_stanza_new(ctx);
if (s == NULL)
err(3, "xmppipe_stanza_new");
return s;
}
void xmppipe_stanza_set_attribute(xmpp_stanza_t *const stanza,
const char *const key,
const char *const value) {
XMPPIPE_NULL(stanza);
XMPPIPE_NULL(key);
XMPPIPE_NULL(value);
if (xmpp_stanza_set_attribute(stanza, key, value) < 0)
err(3, "xmppipe_stanza_set_attribute");
}
void xmppipe_stanza_set_id(xmpp_stanza_t *const stanza, const char *const id) {
XMPPIPE_NULL(stanza);
XMPPIPE_NULL(id);
if (xmpp_stanza_set_id(stanza, id) < 0)
err(3, "xmppipe_stanza_set_id");
}
void xmppipe_stanza_set_name(xmpp_stanza_t *stanza, const char *const name) {
XMPPIPE_NULL(stanza);
XMPPIPE_NULL(name);
switch (xmpp_stanza_set_name(stanza, name)) {
case 0:
return;
case XMPP_EMEM:
err(3, "xmppipe_stanza_set_name");
case XMPP_EINVOP:
err(4, "invalid operation");
default:
err(5, "unknown error");
}
}
void xmppipe_stanza_set_ns(xmpp_stanza_t *const stanza, const char *const ns) {
XMPPIPE_NULL(stanza);
XMPPIPE_NULL(ns);
if (xmpp_stanza_set_ns(stanza, ns) < 0)
err(3, "xmppipe_stanza_set_ns");
}
void xmppipe_stanza_set_text(xmpp_stanza_t *stanza, const char *const text) {
XMPPIPE_NULL(stanza);
XMPPIPE_NULL(text);
if (xmpp_stanza_set_text(stanza, text) < 0)
err(3, "xmppipe_stanza_set_text");
}
void xmppipe_stanza_set_type(xmpp_stanza_t *const stanza,
const char *const type) {
XMPPIPE_NULL(stanza);
XMPPIPE_NULL(type);
if (xmpp_stanza_set_type(stanza, type) < 0)
err(3, "xmppipe_stanza_set_type");
}
void xmppipe_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child) {
XMPPIPE_NULL(stanza);
XMPPIPE_NULL(child);
if (xmpp_stanza_add_child(stanza, child) < 0)
err(3, "xmppipe_stanza_add_child");
}
char *xmppipe_servername(const char *jid) {
char *buf = xmppipe_strdup(jid);
char *p = strchr(buf, '@');
char *q;
if (p == NULL) {
free(buf);
return NULL;
}
*p++ = '\0';
q = xmppipe_strdup(p);
free(buf);
return q;
}
char *xmppipe_resource(void) {
char buf[11];
(void)snprintf(buf, sizeof(buf), "%d", getpid());
return xmppipe_join(XMPPIPE_RESOURCE, ".", buf);
}
char *xmppipe_conference(const char *room, const char *mucservice) {
return xmppipe_join(room, "@", mucservice);
}
char *xmppipe_mucjid(const char *muc, const char *resource) {
return xmppipe_join(muc, "/", resource);
}
char *xmppipe_chatjid(const char *jid, const char *servername) {
return xmppipe_join(jid, "@", servername);
}
static char *xmppipe_join(const char *prefix, const char *delimiter, const char *suffix) {
size_t len = strlen(prefix) + strlen(delimiter) + strlen(suffix) + 1;
char *buf = xmppipe_malloc(len);
int rv;
rv = snprintf(buf, len, "%s%s%s", prefix, delimiter, suffix);
if (rv < 0 || (unsigned)rv > len)
errx(2, "invalid size: %d", rv);
return buf;
}
char *xmppipe_roomname(const char *label) {
char *buf;
size_t len = 64;
char name[16] = {0};
if (gethostname(name, sizeof(name) - 1) < 0) {
(void)snprintf(name, sizeof(name) - 1, "%s", XMPPIPE_RESOURCE);
}
buf = xmppipe_malloc(len);
(void)snprintf(buf, len, "%s-%s-%d", label, name, getuid());
return buf;
}
char *xmppipe_uuid_gen(xmpp_ctx_t *ctx) {
char *uuid;
uuid = xmpp_uuid_gen(ctx);
if (uuid == NULL)
errx(EXIT_FAILURE, "unable to allocate message id");
return uuid;
}
void xmppipe_next_state(xmppipe_state_t *state, int status) {
if (state->verbose)
(void)fprintf(stderr, "next state: %s (%d) -> %s (%d)\n",
(state->status < 0 || state->status > XMPPIPE_S_READY_EMPTY)
? "unknown"
: xmppipe_states[state->status],
state->status,
(state->status < 0 || state->status > XMPPIPE_S_READY_EMPTY)
? "unknown"
: xmppipe_states[status],
status);
state->status = status;
}