#include "util.h"
#ifdef HAVE_IDN
#include <stringprep.h>
#endif
prep_cache_t prep_cache_new(void) {
#ifdef HAVE_IDN
prep_cache_t pc;
pc = (prep_cache_t) malloc(sizeof(struct prep_cache_st));
memset(pc, 0, sizeof(struct prep_cache_st));
pc->node = xhash_new(301);
pc->domain = xhash_new(301);
pc->resource = xhash_new(301);
return pc;
#else
return NULL;
#endif
}
void prep_cache_free(prep_cache_t pc) {
#ifdef HAVE_IDN
xhash_free(pc->node);
xhash_free(pc->domain);
xhash_free(pc->resource);
free(pc);
#endif
}
char *prep_cache_node_get(prep_cache_t pc, char *from) {
return (char *) xhash_get(pc->node, from);
}
void prep_cache_node_set(prep_cache_t pc, char *from, char *to) {
xhash_put(pc->node, pstrdup(xhash_pool(pc->node), from), (void *) pstrdup(xhash_pool(pc->node), to));
}
char *prep_cache_domain_get(prep_cache_t pc, char *from) {
return (char *) xhash_get(pc->domain, from);
}
void prep_cache_domain_set(prep_cache_t pc, char *from, char *to) {
xhash_put(pc->domain, pstrdup(xhash_pool(pc->domain), from), (void *) pstrdup(xhash_pool(pc->domain), to));
}
char *prep_cache_resource_get(prep_cache_t pc, char *from) {
return (char *) xhash_get(pc->resource, from);
}
void prep_cache_resource_set(prep_cache_t pc, char *from, char *to) {
xhash_put(pc->resource, pstrdup(xhash_pool(pc->resource), from), (void *) pstrdup(xhash_pool(pc->resource), to));
}
int jid_prep(jid_t jid) {
#ifdef HAVE_IDN
char str[1024], *prep;
jid->dirty = 1;
if(jid->pc == NULL) {
if(jid->node[0] != '\0')
if(stringprep_xmpp_nodeprep(jid->node, 1024) != 0)
return 1;
if(stringprep_nameprep(jid->domain, 1024) != 0)
return 1;
if(jid->resource[0] != '\0')
if(stringprep_xmpp_resourceprep(jid->node, 1024) != 0)
return 1;
return 0;
}
if(jid->node[0] != '\0') {
strcpy(str, jid->node);
prep = prep_cache_node_get(jid->pc, str);
if(prep != NULL)
strcpy(jid->node, prep);
else {
if(stringprep_xmpp_nodeprep(str, 1024) != 0)
return 1;
prep_cache_node_set(jid->pc, jid->node, str);
strcpy(jid->node, str);
}
}
strcpy(str, jid->domain);
prep = prep_cache_domain_get(jid->pc, str);
if(prep != NULL)
strcpy(jid->domain, prep);
else {
if(stringprep_nameprep(str, 1024) != 0)
return 1;
prep_cache_domain_set(jid->pc, jid->domain, str);
strcpy(jid->domain, str);
}
if(jid->resource[0] != '\0') {
strcpy(str, jid->resource);
prep = prep_cache_resource_get(jid->pc, str);
if(prep != NULL)
strcpy(jid->resource, prep);
else {
if(stringprep_xmpp_resourceprep(str, 1024) != 0)
return 1;
prep_cache_resource_set(jid->pc, jid->resource, str);
strcpy(jid->resource, str);
}
}
#endif
return 0;
}
jid_t jid_new(prep_cache_t pc, const unsigned char *id, int len) {
jid_t jid, ret;
jid = malloc(sizeof(struct jid_st));
jid->pc = pc;
ret = jid_reset(jid, id, len);
if(ret == NULL)
free(jid);
return ret;
}
jid_t jid_reset(jid_t jid, const unsigned char *id, int len) {
prep_cache_t pc;
unsigned char *myid, *cur;
assert((int) jid);
pc = jid->pc;
memset(jid, 0, sizeof(struct jid_st));
jid->pc = pc;
if(id == NULL)
return jid;
if(len < 0)
len = strlen(id);
if(len == 0)
return NULL;
myid = (char *) malloc(sizeof(char) * (len + 1));
sprintf(myid, "%.*s", len, id);
if (myid[0] == '/' || myid[0] == '@')
return NULL;
cur = strstr(myid, "/");
if(cur != NULL)
{
*cur = '\0';
cur++;
if(strlen(cur) > 0) {
strncpy(jid->resource, cur, 1023);
jid->resource[1023]='\0';
}
}
cur = strstr(myid, "@");
if(cur != NULL)
{
*cur = '\0';
cur++;
if(strlen(cur) == 0)
{
free(myid);
return NULL;
}
strncpy(jid->domain, cur, 1023);
jid->domain[1023]='\0';
strncpy(jid->node, myid, 1023);
jid->node[1023]='\0';
}
else {
strncpy(jid->domain, myid, 1023);
jid->domain[1023]='\0';
}
free(myid);
if(jid_prep(jid) != 0)
return NULL;
jid->dirty = 1;
return jid;
}
void jid_free(jid_t jid)
{
free(jid->_user);
free(jid->_full);
free(jid);
}
void jid_expand(jid_t jid)
{
int nlen, dlen, rlen, ulen;
if(!jid->dirty || *jid->domain == '\0')
return;
nlen = strlen(jid->node);
dlen = strlen(jid->domain);
rlen = strlen(jid->resource);
if(nlen == 0) {
ulen = dlen+1;
jid->_user = (unsigned char*) realloc(jid->_user, ulen);
strcpy(jid->_user, jid->domain);
} else {
ulen = nlen+1+dlen+1;
jid->_user = (unsigned char*) realloc(jid->_user, ulen);
snprintf(jid->_user, ulen, "%s@%s", jid->node, jid->domain);
}
if(rlen == 0) {
jid->_full = (unsigned char*) realloc(jid->_full, ulen);
strcpy(jid->_full, jid->_user);
} else {
jid->_full = (unsigned char*) realloc(jid->_full, ulen+1+rlen);
snprintf(jid->_full, ulen+1+rlen, "%s/%s", jid->_user, jid->resource);
}
jid->dirty = 0;
}
const unsigned char *jid_user(jid_t jid)
{
jid_expand(jid);
return jid->_user;
}
const unsigned char *jid_full(jid_t jid)
{
jid_expand(jid);
return jid->_full;
}
int jid_compare_user(jid_t a, jid_t b)
{
jid_expand(a);
jid_expand(b);
return strcmp(a->_user, b->_user);
}
int jid_compare_full(jid_t a, jid_t b)
{
jid_expand(a);
jid_expand(b);
return strcmp(a->_full, b->_full);
}
jid_t jid_dup(jid_t jid)
{
jid_t new;
new = (jid_t) malloc(sizeof(struct jid_st));
memcpy(new, jid, sizeof(struct jid_st));
if(jid->_user)
new->_user = strdup(jid->_user);
if(jid->_full)
new->_full = strdup(jid->_full);
return new;
}
int jid_search(jid_t list, jid_t jid)
{
jid_t cur;
for(cur = list; cur != NULL; cur = cur->next)
if(jid_compare_full(cur,jid) == 0)
return 1;
return 0;
}
jid_t jid_zap(jid_t list, jid_t jid)
{
jid_t cur, dead;
if(jid == NULL || list == NULL) return NULL;
if(jid_compare_full(jid,list) == 0)
{
cur = list->next;
jid_free(list);
return cur;
}
cur = list;
while(cur != NULL)
{
if(cur->next == NULL)
return list;
if(jid_compare_full(cur->next, jid) == 0)
{
dead = cur->next;
cur->next = cur->next->next;
jid_free(dead);
return list;
}
cur = cur->next;
}
return list;
}
jid_t jid_append(jid_t list, jid_t jid)
{
jid_t scan;
if(list == NULL)
return jid_dup(jid);
scan = list;
while(scan != NULL)
{
if(jid_compare_full(scan, jid) == 0)
return list;
if(scan->next == NULL)
{
scan->next = jid_dup(jid);
return list;
}
scan = scan->next;
}
return list;
}