示例#1
0
mreturn mod_browse_reply(mapi m, void *arg)
{
	xmlnode browse, ns, cur;
	session s;

	if (m->packet->type != JPACKET_IQ)
		return M_IGNORE;
	if (!NSCHECK(m->packet->iq, NS_BROWSE))
		return M_PASS;

	/* first, is this a valid request? */
	switch (jpacket_subtype(m->packet)) {
	case JPACKET__RESULT:
	case JPACKET__ERROR:
		return M_PASS;
	case JPACKET__SET:
		js_bounce(m->si, m->packet->x, TERROR_NOTALLOWED);
		return M_HANDLED;
	}

	log_debug("handling query for user %s", m->user->user);

	/* get this dudes browse info */
	browse = mod_browse_get(m, m->packet->to);

	/* insert the namespaces */
	ns = xdb_get(m->si->xc, m->packet->to, NS_XDBNSLIST);
	for (cur = xmlnode_get_firstchild(ns); cur != NULL;
	     cur = xmlnode_get_nextsibling(cur))
		if (xmlnode_get_attrib(cur, "type") == NULL)
			xmlnode_insert_tag_node(browse, cur);	/* only include the generic <ns>foo</ns> */
	xmlnode_free(ns);

	/* include any connected resources if there's a s10n from them */
	if (js_trust(m->user, m->packet->from)) {
		SEM_LOCK(m->user->sem);
		for (s = m->user->sessions; s != NULL; s = s->next) {
			/* if(s->priority < 0) continue; *** include all resources I guess */
			if (xmlnode_get_tag
			    (browse,
			     spools(m->packet->p, "?jid=", jid_full(s->id),
				    m->packet->p)) != NULL)
				continue;	/* already in the browse result */
			cur = xmlnode_insert_tag(browse, "user");
			xmlnode_put_attrib(cur, "type", "client");
			xmlnode_put_attrib(cur, "jid", jid_full(s->id));
		}
		SEM_UNLOCK(m->user->sem);
	}

	/* XXX include iq:filter forwards */

	jutil_iqresult(m->packet->x);
	jpacket_reset(m->packet);
	xmlnode_insert_tag_node(m->packet->x, browse);
	js_deliver(m->si, m->packet);

	xmlnode_free(browse);
	return M_HANDLED;
}
示例#2
0
/* child that handles packets from the user */
void _js_session_from(void *arg)
{
	jpacket p = (jpacket) arg;
	session s = (session) (p->aux1);

	/* if this session is dead */
	if (s->exit_flag) {
		/* send the packet into oblivion */
		xmlnode_free(p->x);
		return;
	}

	/* at least we must have a valid packet */
	if (p->type == JPACKET_UNKNOWN) {
		/* send an error back */
		jutil_error(p->x, TERROR_BAD);
		jpacket_reset(p);
		js_session_to(s, p);
		return;
	}

	/* debug message */
	log_debug("THREAD:SESSION:FROM received a packet!");

	/* increment packet out count */
	s->si->stats->packets_out++;
	s->c_out++;

	/* make sure we have our from set correctly for outgoing packets */
	if (jid_cmpx(p->from, s->id, JID_USER | JID_SERVER) != 0) {
		/* nope, fix it */
		xmlnode_put_attrib(p->x, "from", jid_full(s->id));
		p->from = jid_new(p->p, jid_full(s->id));
	}

	/* if you use to="yourself@yourhost" it's the same as not having a to, the modules use the NULL as a self-flag */
	if (jid_cmp(p->to, s->uid) == 0) {
		/* xmlnode_hide_attrib(p->x,"to"); */
		p->to = NULL;
	}

	/* let the modules have their heyday */
	if (js_mapi_call(NULL, es_OUT, p, s->u, s))
		return;

	/* no module handled it, so restore the to attrib to us */
	if (p->to == NULL) {
		xmlnode_put_attrib(p->x, "to", jid_full(s->uid));
		p->to = jid_new(p->p, jid_full(s->uid));
	}

	js_post_out_main(s, p);

	/* pass these to the general delivery function */
	//    js_deliver(s->si, p);
}
示例#3
0
文件: jpacket.c 项目: bcy/muc
jpacket jpacket_new(xmlnode x)
{
    jpacket p;

    if(x == NULL)
        return NULL;

    p = pmalloc(xmlnode_pool(x),sizeof(_jpacket));
    p->x = x;

    return jpacket_reset(p);
}
示例#4
0
mreturn mod_agents_agent(mapi m)
{
	xmlnode ret, retq, info, agents, reg;

	/* get data from the config file */
	info = js_config(m->si, "vCard");
	agents = js_config(m->si, "agents");
	reg = js_config(m->si, "register");

	/* if we don't have anything to say, bounce */
	if (info == NULL && agents == NULL && reg == NULL)
		return M_PASS;

	log_debug("handling agent query");

	/* build the result IQ */
	ret = jutil_iqresult(m->packet->x);
	retq = xmlnode_insert_tag(ret, "query");
	xmlnode_put_attrib(retq, "xmlns", NS_AGENT);

	/* copy in the vCard info */
	xmlnode_insert_cdata(xmlnode_insert_tag(retq, "name"),
			     xmlnode_get_tag_data(info, "FN"), -1);
	xmlnode_insert_cdata(xmlnode_insert_tag(retq, "url"),
			     xmlnode_get_tag_data(info, "URL"), -1);
	xmlnode_insert_cdata(xmlnode_insert_tag(retq, "service"), "jabber",
			     6);

	/* set the flags */
	if (agents != NULL)
		xmlnode_insert_tag(retq, "agents");
	if (reg != NULL)
		xmlnode_insert_tag(retq, "register");

	jpacket_reset(m->packet);
	if (m->s != NULL) {	/* XXX null session hack! */
		xmlnode_put_attrib(m->packet->x, "from",
				   m->packet->from->server);
		js_session_to(m->s, m->packet);
	} else {
		js_deliver(m->si, m->packet);
	}

	return M_HANDLED;
}
示例#5
0
mreturn mod_browse_server(mapi m, void *arg)
{
	xmlnode browse, query, x;

	if (m->packet->type != JPACKET_IQ)
		return M_IGNORE;
	if (jpacket_subtype(m->packet) != JPACKET__GET
	    || !NSCHECK(m->packet->iq, NS_BROWSE)
	    || m->packet->to->resource != NULL)
		return M_PASS;

	/* get data from the config file */
	if ((browse = js_config(m->si, "browse")) == NULL)
		return M_PASS;

	log_debug("handling browse query");

	/* build the result IQ */
	query =
	    xmlnode_insert_tag(jutil_iqresult(m->packet->x), "service");
	xmlnode_put_attrib(query, "xmlns", NS_BROWSE);
	xmlnode_put_attrib(query, "type", "jabber");
	xmlnode_put_attrib(query, "jid", m->packet->to->server);
	xmlnode_put_attrib(query, "name", xmlnode_get_data(js_config(m->si, "vCard/FN")));	/* pull name from the server vCard */

	/* copy in the configured services */
	xmlnode_insert_node(query, xmlnode_get_firstchild(browse));

	/* list the admin stuff */
	if (js_admin_jid(m->si, jid_user(m->packet->from), ADMIN_READ)) {
		x = xmlnode_insert_tag(query, "item");
		xmlnode_put_attrib(x, "jid",
				   spools(xmlnode_pool(x),
					  m->packet->to->server, "/admin",
					  xmlnode_pool(x)));
		xmlnode_put_attrib(x, "name", "Online Users");
		xmlnode_insert_cdata(xmlnode_insert_tag(query, "ns"),
				     NS_ADMIN, -1);
	}

	jpacket_reset(m->packet);
	js_deliver(m->si, m->packet);

	return M_HANDLED;
}
示例#6
0
文件: conference_room.c 项目: bcy/muc
void _con_room_discoinfo(cnr room, jpacket jp)
{
  xmlnode result;
  xmlnode xdata, field;
  char *topic;
  char buf[32];

  if(room == NULL) 
  {
    log_warn(NAME, "[%s] Aborting - NULL room attribute found", FZONE);
    return;
  }

  jutil_iqresult(jp->x);
  xmlnode_put_attrib(xmlnode_insert_tag(jp->x,"query"), "xmlns", NS_DISCO_INFO);
  jpacket_reset(jp);

  result = xmlnode_insert_tag(jp->iq,"identity");
  xmlnode_put_attrib(result, "category", "conference");
  xmlnode_put_attrib(result, "type", "text");
  xmlnode_put_attrib(result, "name", room->name);

  xmlnode_put_attrib(xmlnode_insert_tag(jp->iq, "feature"), "var", NS_MUC);
  xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", NS_DISCO);
  xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", NS_BROWSE);
  xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", NS_VERSION);
  xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", NS_LAST);
  xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", NS_TIME);
  xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", NS_VCARD);

  if(room->secret != NULL && *room->secret != '\0')
    xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", "muc_passwordprotected");
  else
    xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", "muc_unsecure");

  if(room->public == 1)
    xmlnode_put_attrib(xmlnode_insert_tag(jp->iq,"feature"), "var", "muc_public");
  else
示例#7
0
文件: deliver.c 项目: smokku/wpjabber
/* any thread */
result js_packet(instance i, dpacket p, void *arg)
{
	jsmi si = (jsmi) arg;
	jpacket jp = NULL;
	session s = NULL;
	packet_thread_p pt;
	udata u;

	char *type, *authto;

	log_debug("incoming packet %s", xmlnode2str(p->x));

	/* if this is a routed packet */
	if (p->type == p_ROUTE) {
		type = xmlnode_get_attrib(p->x, "type");

		/* new session requests */
		if (j_strcmp(type, "session") == 0) {
			js_session_new_mtq(si, p);
			return r_DONE;
		}

		/* get the internal jpacket */
		if (xmlnode_get_firstchild(p->x) != NULL)	/* XXX old libjabber jpacket_new() wasn't null safe, this is just safety */
			jp = jpacket_new(xmlnode_get_firstchild(p->x));


		/* auth/reg requests */
		if (jp != NULL && j_strcmp(type, "auth") == 0) {
			/* check and see if we're configured to forward auth packets for processing elsewhere */
			if ((authto =
			     xmlnode_get_data(js_config(si, "auth"))) !=
			    NULL) {
				xmlnode_put_attrib(p->x, "oto", xmlnode_get_attrib(p->x, "to"));	/* preserve original to */
				xmlnode_put_attrib(p->x, "to", authto);
				deliver(dpacket_new(p->x), i);
				return r_DONE;
			}

			/* internally, hide the route to/from addresses on the authreg request */
			xmlnode_put_attrib(jp->x, "to",
					   xmlnode_get_attrib(p->x, "to"));
			xmlnode_put_attrib(jp->x, "from",
					   xmlnode_get_attrib(p->x,
							      "from"));
			xmlnode_put_attrib(jp->x, "route",
					   xmlnode_get_attrib(p->x,
							      "type"));
			jpacket_reset(jp);
			jp->aux1 = (void *) si;

			pt = pmalloco(jp->p, sizeof(packet_thread_t));
			pt->jp = jp;
			fast_mtq_send(si->mtq_authreg, pt);
			return r_DONE;
		}

		/* if it's an error */
		if (j_strcmp(type, "error") == 0) {

			/* look for users online */
			u = js_user(si, p->id, 1);
			if (u == NULL) {
				/* if this was a message,
				   it should have been delievered to that session, store offline */
				if (jp != NULL
				    && jp->type == JPACKET_MESSAGE) {
					pt = pmalloco(jp->p,
						      sizeof
						      (packet_thread_t));
					pt->jp = jp;
					fast_mtq_send(si->mtq_deliver, pt);
					return r_DONE;
				}

				xmlnode_free(p->x);
				return r_DONE;
				/*
				   log_notice(p->host,
				   "Bouncing packet intended for nonexistant user: %s",
				   xmlnode2str(p->x));
				   deliver_fail(dpacket_new(p->x), "Invalid User");
				   return r_DONE;
				 */
			}

			if (p->id->resource != NULL) {
				SEM_LOCK(u->sem);
				for (s = u->sessions; s != NULL;
				     s = s->next)
					if (j_strcmp
					    (p->id->resource,
					     s->route->resource) == 0)
						break;
				SEM_UNLOCK(u->sem);

				if (s != NULL) {
					s->sid = NULL;	/* they generated the error,
							   no use in sending there anymore! */
					js_session_end(s, "Disconnected");
				}
			} else {
				session temp;
				/* a way to boot an entire user off */
				SEM_LOCK(u->sem);
				for (s = u->sessions; s != NULL;) {
					temp = s;
					s = s->next;
					js_session_end_nosem(temp,
							     "Removed");
				}
				u->pass = NULL;	/* so they can't log back in */

				SEM_UNLOCK(u->sem);

				xmlnode_free(p->x);
				THREAD_DEC(u->ref);
				return r_DONE;
			}

			THREAD_DEC(u->ref);

			/* if this was a message,
			   it should have been delievered to that session, store offline */
			if (jp != NULL && jp->type == JPACKET_MESSAGE) {
				pt = pmalloco(jp->p,
					      sizeof(packet_thread_t));
				pt->jp = jp;
				fast_mtq_send(si->mtq_deliver, pt);
				return r_DONE;
			}

			/* drop and return */
			if (xmlnode_get_firstchild(p->x) != NULL)
				log_notice(p->host,
					   "Dropping a bounced session packet to %s",
					   jid_full(p->id));

			xmlnode_free(p->x);
			return r_DONE;
		}

		/* uhh, empty packet, *shrug* */
		if (jp == NULL) {
			log_notice(p->host,
				   "Dropping an invalid or empty route packet: %s",
				   xmlnode2str(p->x), jid_full(p->id));
			xmlnode_free(p->x);
			return r_DONE;
		}

		/* ============================================================== */


		/* attempt to locate the session by matching the special resource */
		u = js_user(si, p->id, 1);
		if (u == NULL) {
			/* only when route packet to users not online */
			pt = pmalloco(p->p, sizeof(packet_thread_t));
			pt->p = p;
			pt->jp = jp;
			fast_mtq_send(si->mtq_deliver, pt);
			return r_DONE;
		}

		/* user is online :) */
		SEM_LOCK(u->sem);
		for (s = u->sessions; s != NULL; s = s->next)
			if (j_strcmp(p->id->resource, s->route->resource)
			    == 0)
				break;
		SEM_UNLOCK(u->sem);

		THREAD_DEC(u->ref);

		if (s != NULL) {	/* just pass to the session normally */
			js_session_from(s, jp);
			return r_DONE;
		}

		log_notice(p->host,
			   "Bouncing %s packet intended for session %s",
			   xmlnode_get_name(jp->x), jid_full(p->id));
		deliver_fail(dpacket_new(p->x), "Invalid Session");
		return r_DONE;
	}

	/* normal server-server packet, should we make sure it's not spoofing us?  if so, if ghash_get(p->to->server) then bounce w/ security error */

	jp = jpacket_new(p->x);
	if (jp == NULL) {
		log_warn(p->host, "Dropping invalid incoming packet: %s",
			 xmlnode2str(p->x));
		xmlnode_free(p->x);
		return r_DONE;
	}

	pt = pmalloco(jp->p, sizeof(packet_thread_t));
	pt->jp = jp;
	fast_mtq_send(si->mtq_deliver, pt);
	return r_DONE;
}
示例#8
0
mreturn mod_agents_agents(mapi m)
{
	xmlnode ret, retq, agents, cur, a, cur2;

	/* get data from the config file */
	agents = js_config(m->si, "browse");

	/* if we don't have anything to say, bounce */
	if (agents == NULL)
		return M_PASS;

	log_debug("handling agents query");

	/* build the result IQ */
	ret = jutil_iqresult(m->packet->x);
	retq = xmlnode_insert_tag(ret, "query");
	xmlnode_put_attrib(retq, "xmlns", NS_AGENTS);

	/* parse the new browse data into old agents format */
	for (cur = xmlnode_get_firstchild(agents); cur != NULL;
	     cur = xmlnode_get_nextsibling(cur)) {
		if (xmlnode_get_type(cur) != NTYPE_TAG)
			continue;

		/* generic <agent> part */
		a = xmlnode_insert_tag(retq, "agent");
		xmlnode_put_attrib(a, "jid",
				   xmlnode_get_attrib(cur, "jid"));
		xmlnode_insert_cdata(xmlnode_insert_tag(a, "name"),
				     xmlnode_get_attrib(cur, "name"), -1);
		xmlnode_insert_cdata(xmlnode_insert_tag(a, "service"),
				     xmlnode_get_attrib(cur, "type"), -1);

		if (j_strcmp(xmlnode_get_name(cur), "conference") == 0)
			xmlnode_insert_tag(a, "groupchat");

		/* map the included <ns>'s in browse to the old agent flags */
		for (cur2 = xmlnode_get_firstchild(cur); cur2 != NULL;
		     cur2 = xmlnode_get_nextsibling(cur2)) {
			if (j_strcmp(xmlnode_get_name(cur2), "ns") != 0)
				continue;
			if (j_strcmp
			    (xmlnode_get_data(cur2),
			     "jabber:iq:register") == 0)
				xmlnode_insert_tag(a, "register");
			if (j_strcmp
			    (xmlnode_get_data(cur2),
			     "jabber:iq:search") == 0)
				xmlnode_insert_tag(a, "search");
			if (j_strcmp
			    (xmlnode_get_data(cur2),
			     "jabber:iq:gateway") == 0)
				xmlnode_insert_cdata(xmlnode_insert_tag
						     (a, "transport"),
						     "Enter ID", -1);
		}
	}

	jpacket_reset(m->packet);
	if (m->s != NULL) {	/* XXX null session hack! */
		xmlnode_put_attrib(m->packet->x, "from",
				   m->packet->from->server);
		js_session_to(m->s, m->packet);
	} else {
		js_deliver(m->si, m->packet);
	}

	return M_HANDLED;
}
示例#9
0
mreturn mod_stats_server(mapi m, void *arg)
{
	xmlnode cur;
	int i;

	if (m->packet->type != JPACKET_IQ)
		return M_IGNORE;
	if (jpacket_subtype(m->packet) != JPACKET__GET)
		return M_PASS;
	if (!NSCHECK(m->packet->iq, NS_STATS))
		return M_PASS;
	if (m->packet->to->resource)
		return M_PASS;

	/* get data from the config file */
	i = 0;
	if (xmlnode_get_tag(js_config(m->si, "stats"), "allow_all") !=
	    NULL)
		i = 1;

	log_debug("handling stats get %s", jid_full(m->packet->from));

	/* check if admin */
	if ((i == 0) &&
	    (!js_admin_jid(m->si, jid_user(m->packet->from), ADMIN_READ)))
	{
		jutil_error(m->packet->x, TERROR_AUTH);
		jpacket_reset(m->packet);
		js_deliver(m->si, m->packet);
		return M_HANDLED;
	}

	/* check if any stat have given iq query */
	cur = xmlnode_get_firstchild(m->packet->iq);
	for (; cur != NULL; cur = xmlnode_get_nextsibling(cur)) {
		if (xmlnode_get_type(cur) != NTYPE_TAG)
			continue;
		break;
	}
	if (cur != NULL)
		cur = xmlnode_get_firstchild(m->packet->iq);

	jutil_tofrom(m->packet->x);
	xmlnode_put_attrib(m->packet->x, "type", "result");

	/* return available stats */
	if (!cur) {
		for (i = 0; available_stats[i]; i++) {
			xmlnode_put_attrib(xmlnode_insert_tag
					   (m->packet->iq, "stat"), "name",
					   available_stats[i]);
		}
		jpacket_reset(m->packet);
		js_deliver(m->si, m->packet);
		return M_HANDLED;
	}

	/* return server stats */
	/* cur is already first stat */
	for (; cur != NULL; cur = xmlnode_get_nextsibling(cur)) {
		char *name;
		char buf[31];
		int found;

		if (xmlnode_get_type(cur) != NTYPE_TAG)
			continue;
		if (j_strcmp(xmlnode_get_name(cur), "stat") != 0)
			continue;

		name = xmlnode_get_attrib(cur, "name");

		if (!name)
			continue;

		log_debug("get stats for %s", name);

		found = 0;
		for (i = 0; available_stats[i]; i++) {

			if (j_strcmp(available_stats[i], name) != 0)
				continue;

			log_debug("stats for %s", name);
			/* give stats */

			found = 1;

			/* time/uptime */
			if (j_strcmp(name, "time/uptime") == 0) {
				snprintf(buf, 30, "%d",
					 time(NULL) -
					 m->si->stats->started);
				xmlnode_put_attrib(cur, "value", buf);
				xmlnode_put_attrib(cur, "units",
						   "seconds");
			}

			/* users/online */
			if (j_strcmp(name, "users/online") == 0) {
				snprintf(buf, 30, "%d",
					 m->si->stats->sessioncount);
				xmlnode_put_attrib(cur, "value", buf);
				xmlnode_put_attrib(cur, "units", "users");
			}

			if (j_strcmp(name, "users/max_online_today") == 0) {
				snprintf(buf, 30, "%d",
					 m->si->stats->session_max_today);
				xmlnode_put_attrib(cur, "value", buf);
				xmlnode_put_attrib(cur, "units", "users");
			}

			if (j_strcmp(name, "users/max_online_yesterday") ==
			    0) {
				snprintf(buf, 30, "%d",
					 m->si->stats->
					 session_max_yesterday);
				xmlnode_put_attrib(cur, "value", buf);
				xmlnode_put_attrib(cur, "units", "users");
			}

			if (j_strcmp(name, "users/registered_today") == 0) {
				snprintf(buf, 30, "%d",
					 m->si->stats->
					 users_registered_today);
				xmlnode_put_attrib(cur, "value", buf);
				xmlnode_put_attrib(cur, "units", "users");
			}

			if (j_strcmp(name, "users/registered_from_start")
			    == 0) {
				snprintf(buf, 30, "%d",
					 m->si->stats->
					 users_registered_from_start);
				xmlnode_put_attrib(cur, "value", buf);
				xmlnode_put_attrib(cur, "units", "users");
			}

			if (j_strcmp(name, "bandwidth/packets-in") == 0) {
				snprintf(buf, 30, "%lu",
					 m->si->stats->packets_in);
				xmlnode_put_attrib(cur, "value", buf);
				xmlnode_put_attrib(cur, "units",
						   "packets");
			}

			if (j_strcmp(name, "bandwidth/packets-out") == 0) {
				snprintf(buf, 30, "%lu",
					 m->si->stats->packets_out);
				xmlnode_put_attrib(cur, "value", buf);
				xmlnode_put_attrib(cur, "units",
						   "packets");
			}
#ifndef WIN32
			if (j_strcmp(name, "memory/usage") == 0) {
				long mem = get_memory_usage();
				if (mem > 0) {
					snprintf(buf, 30, "%lu", mem);
					xmlnode_put_attrib(cur, "value",
							   buf);
					xmlnode_put_attrib(cur, "units",
							   "bytes");
				} else
					found = 0;
			}
#endif
			break;
		}

		if (found <= 0) {
			xmlnode err;
			err = xmlnode_insert_tag(cur, "error");
			xmlnode_put_attrib(err, "code", "404");
			xmlnode_insert_cdata(err, "Not Found", -1);
		}
	}

	jpacket_reset(m->packet);
	js_deliver(m->si, m->packet);
	return M_HANDLED;
}
示例#10
0
mreturn mod_browse_set(mapi m, void *arg)
{
	xmlnode browse, cur;
	jid id, to;

	if (m->packet->type != JPACKET_IQ)
		return M_IGNORE;
	if (!NSCHECK(m->packet->iq, NS_BROWSE)
	    || jpacket_subtype(m->packet) != JPACKET__SET)
		return M_PASS;
	if (m->packet->to != NULL)
		return M_PASS;	/* if its to someone other than ourselves */

	log_debug("handling set request %s", xmlnode2str(m->packet->iq));

	/* no to implies to ourselves */
	if (m->packet->to != NULL)
		to = m->packet->to;
	else
		to = m->user->id;

	/* if we set to a resource, we need to make sure that resource's browse is in the users browse */
	if (to->resource != NULL) {
		browse = mod_browse_get(m, to);	/* get our browse info */
		xmlnode_hide_attrib(browse, "xmlns");	/* don't need a ns as a child */
		for (cur = xmlnode_get_firstchild(browse); cur != NULL;
		     cur = xmlnode_get_nextsibling(cur))
			xmlnode_hide(cur);	/* erase all children */
		xdb_act(m->si->xc, m->user->id, NS_BROWSE, "insert", spools(m->packet->p, "?jid=", jid_full(to), m->packet->p), browse);	/* insert and match replace */
		xmlnode_free(browse);
	}

	/* get the id of the new browse item */
	if ((cur = xmlnode_get_firstchild(m->packet->iq)) == NULL
	    || (id =
		jid_new(m->packet->p,
			xmlnode_get_attrib(cur, "jid"))) == NULL) {
		js_bounce(m->si, m->packet->x, TERROR_NOTACCEPTABLE);
		return M_HANDLED;
	}

	/* insert the new item into the resource it was sent to */
	xmlnode_hide_attrib(cur, "xmlns");	/* just in case, to make sure it inserts */
	if (xdb_act
	    (m->si->xc, to, NS_BROWSE, "insert",
	     spools(m->packet->p, "?jid=", jid_full(id), m->packet->p),
	     cur)) {
		js_bounce(m->si, m->packet->x, TERROR_UNAVAIL);
		return M_HANDLED;
	}

	/* if the new data we're inserting is to one of our resources, update that resource's browse */
	if (jid_cmpx(m->user->id, id, JID_USER | JID_SERVER) == 0
	    && id->resource != NULL) {
		/* get the old */
		browse = mod_browse_get(m, id);
		/* transform the new one into the old one */
		xmlnode_put_attrib(cur, "xmlns", NS_BROWSE);
		xmlnode_insert_node(cur, xmlnode_get_firstchild(browse));
		xdb_set(m->si->xc, id, NS_BROWSE, cur);	/* replace the resource's browse w/ this one */
		xmlnode_free(browse);
	}

	/* send response to the user */
	jutil_iqresult(m->packet->x);
	jpacket_reset(m->packet);
	js_session_to(m->s, m->packet);

	return M_HANDLED;
}