Files
libstrophe-gh/src/jid.c
Steffen Jaeckel 37555868f6 improve JID parsing according to RFC7622
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-03-10 11:11:44 +01:00

199 lines
4.9 KiB
C

/* jid.c
** strophe XMPP client library -- helper functions for parsing JIDs
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* JID creation and parsing.
*/
#include <string.h>
#include "strophe.h"
#include "common.h"
/** Create a JID string from component parts node, domain, and resource.
*
* @param ctx the Strophe context object
* @param node a string representing the node
* @param domain a string representing the domain. Required.
* @param resource a string representing the resource
*
* @return an allocated string with the full JID or NULL if no domain
* is specified
*/
char *xmpp_jid_new(xmpp_ctx_t *ctx,
const char *node,
const char *domain,
const char *resource)
{
char *result;
size_t len, nlen, dlen, rlen;
/* jid must at least have a domain */
if (domain == NULL) {
strophe_error(ctx, "jid", "domainpart missing.");
return NULL;
}
/* accumulate lengths */
dlen = strlen(domain);
nlen = (node) ? strlen(node) + 1 : 0;
rlen = (resource) ? strlen(resource) + 1 : 0;
len = nlen + dlen + rlen;
if (dlen > 1023) {
strophe_error(ctx, "jid", "domainpart too long.");
return NULL;
}
if (nlen > 1024) {
strophe_error(ctx, "jid", "localpart too long.");
return NULL;
}
if (rlen > 1024) {
strophe_error(ctx, "jid", "resourcepart too long.");
return NULL;
}
if (node) {
if (strcspn(node, "\"&'/:<>@") != nlen - 1) {
strophe_error(ctx, "jid", "localpart contained invalid character.");
return NULL;
}
}
/* concat components */
result = strophe_alloc(ctx, len + 1);
if (result != NULL) {
if (node != NULL) {
memcpy(result, node, nlen - 1);
result[nlen - 1] = '@';
}
memcpy(result + nlen, domain, dlen);
if (resource != NULL) {
result[nlen + dlen] = '/';
memcpy(result + nlen + dlen + 1, resource, rlen - 1);
}
result[len] = '\0';
}
return result;
}
/** Create a bare JID from a JID.
*
* @param ctx the Strophe context object
* @param jid the JID
*
* @return an allocated string with the bare JID or NULL on an error
*/
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
{
char *result;
size_t len;
len = strcspn(jid, "/");
result = strophe_alloc(ctx, len + 1);
if (result != NULL) {
memcpy(result, jid, len);
result[len] = '\0';
}
return result;
}
/** Create a node string from a JID.
*
* @param ctx a Strophe context object
* @param jid the JID
*
* @return an allocated string with the node or NULL if no node is found
* or an error occurs
*/
char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
{
char *dup_jid = strophe_strdup(ctx, jid);
char *result = NULL;
const char *c;
/* Apply the same parsing rules from rfc7622 Section 3.2
* 1. Strip resource
* 2. take part before the '@'
*/
char *resource = strchr(dup_jid, '/');
if (resource != NULL) {
*resource = '\0';
}
c = strchr(dup_jid, '@');
if (c != NULL) {
result = strophe_alloc(ctx, (c - dup_jid) + 1);
if (result != NULL) {
memcpy(result, dup_jid, (c - dup_jid));
result[c - dup_jid] = '\0';
}
}
strophe_free(ctx, dup_jid);
return result;
}
/** Create a domain string from a JID.
*
* @param ctx the Strophe context object
* @param jid the JID
*
* @return an allocated string with the domain or NULL on an error
*/
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
{
char *dup_jid = strophe_strdup(ctx, jid);
/* rfc7622 Section 3.2
* 1. Remove any portion from the first '/' character to the end of the
* string (if there is a '/' character present).
*/
char *resource = strchr(dup_jid, '/');
if (resource != NULL) {
*resource = '\0';
}
/* 2. Remove any portion from the beginning of the string to the first
* '@' character (if there is an '@' character present).
*/
char *at_sign = strchr(dup_jid, '@');
char *result = NULL;
if (at_sign != NULL) {
result = strophe_strdup(ctx, (at_sign + 1));
} else {
result = strophe_strdup(ctx, dup_jid);
}
strophe_free(ctx, dup_jid);
return result;
}
/** Create a resource string from a JID.
*
* @param ctx a Strophe context object
* @param jid the JID
*
* @return an allocated string with the resource or NULL if no resource
* is found or an error occurs
*/
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
{
const char *c;
c = strchr(jid, '/');
return c != NULL ? strophe_strdup(ctx, c + 1) : NULL;
}