#include "jabberd.h"
result xdb_results(instance id, dpacket p, void *arg)
{
xdbcache xc = (xdbcache)arg;
xdbcache curx;
int idnum;
char *idstr;
if(p->type != p_NORM || *(xmlnode_get_name(p->x)) != 'x') return r_PASS;
log_debug(ZONE,"xdb_results checking xdb packet %s",xmlnode2str(p->x));
if((idstr = xmlnode_get_attrib(p->x,"id")) == NULL) return r_ERR;
idnum = atoi(idstr);
pth_mutex_acquire(&(xc->mutex), FALSE, NULL);
for(curx = xc->next; curx->id != idnum && curx != xc; curx = curx->next);
if(curx->id != idnum)
{
pool_free(p->p);
pth_mutex_release(&(xc->mutex));
return r_DONE;
}
if(j_strcmp(xmlnode_get_attrib(p->x,"type"),"error") == 0)
curx->data = NULL;
else
curx->data = p->x;
curx->prev->next = curx->next;
curx->next->prev = curx->prev;
curx->preblock = 0;
pth_cond_notify(&(curx->cond), FALSE);
pth_mutex_release(&(xc->mutex));
return r_DONE;
}
void xdb_deliver(instance i, xdbcache xc)
{
xmlnode x;
char ids[9];
x = xmlnode_new_tag("xdb");
xmlnode_put_attrib(x,"type","get");
if(xc->set)
{
xmlnode_put_attrib(x,"type","set");
xmlnode_insert_tag_node(x,xc->data);
if(xc->act != NULL)
xmlnode_put_attrib(x,"action",xc->act);
if(xc->match != NULL)
xmlnode_put_attrib(x,"match",xc->match);
}
xmlnode_put_attrib(x,"to",jid_full(xc->owner));
xmlnode_put_attrib(x,"from",i->id);
xmlnode_put_attrib(x,"ns",xc->ns);
sprintf(ids,"%d",xc->id);
xmlnode_put_attrib(x,"id",ids);
deliver(dpacket_new(x), i);
}
result xdb_thump(void *arg)
{
xdbcache xc = (xdbcache)arg;
xdbcache cur, next;
int now = time(NULL);
pth_mutex_acquire(&(xc->mutex), FALSE, NULL);
cur = xc->next;
while(cur != xc)
{
next = cur->next;
if((now - cur->sent) > 30)
{
cur->prev->next = cur->next;
cur->next->prev = cur->prev;
cur->data = NULL;
if (cur->preblock)
{
cur->preblock = 0;
pth_cond_notify(&(cur->cond), FALSE);
}
cur = next;
continue;
}
if((now - cur->sent) > 10)
xdb_deliver(xc->i, cur);
cur = next;
}
pth_mutex_release(&(xc->mutex));
return r_DONE;
}
xdbcache xdb_cache(instance id)
{
xdbcache newx;
if(id == NULL)
{
fprintf(stderr, "Programming Error: xdb_cache() called with NULL\n");
return NULL;
}
newx = pmalloco(id->p, sizeof(_xdbcache));
newx->i = id;
newx->next = newx->prev = newx;
pth_mutex_init(&(newx->mutex));
register_phandler(id, o_PRECOND, xdb_results, (void *)newx);
register_beat(10,xdb_thump,(void *)newx);
return newx;
}
xmlnode xdb_get(xdbcache xc, jid owner, char *ns)
{
_xdbcache newx;
xmlnode x;
if(xc == NULL || owner == NULL || ns == NULL)
{
fprintf(stderr,"Programming Error: xdb_get() called with NULL\n");
return NULL;
}
newx.i = NULL;
newx.set = 0;
newx.data = NULL;
newx.ns = ns;
newx.owner = owner;
newx.sent = time(NULL);
newx.preblock = 1;
pth_cond_init(&(newx.cond));
pth_mutex_acquire(&(xc->mutex), FALSE, NULL);
newx.id = xc->id++;
newx.next = xc->next;
newx.prev = xc;
newx.next->prev = &newx;
xc->next = &newx;
xdb_deliver(xc->i, &newx);
log_debug(ZONE,"xdb_get() waiting for %s %s",jid_full(owner),ns);
if (newx.preblock)
pth_cond_await(&(newx.cond), &(xc->mutex), NULL);
pth_mutex_release(&(xc->mutex));
log_debug(ZONE,"xdb_get() done waiting for %s %s",jid_full(owner),ns);
for(x = xmlnode_get_firstchild(newx.data); x != NULL && xmlnode_get_type(x) != NTYPE_TAG; x = xmlnode_get_nextsibling(x));
if(x == NULL)
xmlnode_free(newx.data);
return x;
}
int xdb_act(xdbcache xc, jid owner, char *ns, char *act, char *match, xmlnode data)
{
_xdbcache newx;
if(xc == NULL || owner == NULL || ns == NULL)
{
fprintf(stderr,"Programming Error: xdb_set() called with NULL\n");
return 1;
}
newx.i = NULL;
newx.set = 1;
newx.data = data;
newx.ns = ns;
newx.act = act;
newx.match = match;
newx.owner = owner;
newx.sent = time(NULL);
newx.preblock = 1;
pth_cond_init(&(newx.cond));
pth_mutex_acquire(&(xc->mutex), FALSE, NULL);
newx.id = xc->id++;
newx.next = xc->next;
newx.prev = xc;
newx.next->prev = &newx;
xc->next = &newx;
xdb_deliver(xc->i, &newx);
log_debug(ZONE,"xdb_set() waiting for %s %s",jid_full(owner),ns);
if (newx.preblock)
pth_cond_await(&(newx.cond), &(xc->mutex), NULL);
pth_mutex_release(&(xc->mutex));
log_debug(ZONE,"xdb_set() done waiting for %s %s",jid_full(owner),ns);
if(newx.data == NULL)
return 1;
xmlnode_free(newx.data);
return 0;
}
int xdb_set(xdbcache xc, jid owner, char *ns, xmlnode data)
{
return xdb_act(xc, owner, ns, NULL, NULL, data);
}