/* NOTE: any jpacket sent to deliver *MUST* match jpacket_new(p->x), * jpacket is simply a convenience wrapper */ void js_deliver(jsmi si, jpacket p) { if (p->to == NULL) { log_warn(NULL, "jsm: Invalid Recipient, returning data %s", xmlnode2str(p->x)); js_bounce(si, p->x, TERROR_BAD); return; } if (p->from == NULL) { log_warn(NULL, "jsm: Invalid Sender, discarding data %s", xmlnode2str(p->x)); xmlnode_free(p->x); return; } log_debug("deliver(to[%s],from[%s],type[%d],packet[%s])", jid_full(p->to), jid_full(p->from), p->type, xmlnode2str(p->x)); /* is it our */ if (j_strcmp(si->host, p->to->server) == 0) { js_deliver_local(si, p); return; } deliver(dpacket_new(p->x), si->i); }
/* handle a packet from jabberd */ result at_phandler(instance i,dpacket p,void *arg) { int ret; ati ti; at_mtq_data amd; if(i == NULL || p == NULL) return r_ERR; ti = (ati)arg; switch(p->type) { case p_NONE: case p_NORM: log_debug(ZONE, "[AT] we got a packet from jabberd: %s", xmlnode2str(p->x)); amd = pmalloco(p->p, sizeof(_at_mtq_data)); amd->jp = jpacket_new(p->x); amd->p = p->p; amd->ti = ti; mtq_send(NULL, p->p, at_parse_packet, (void *)amd); return r_DONE; default: log_debug(ZONE, "[AT] ignoring packet from jabberd: %s", xmlnode2str(p->x)); return r_PASS; } }
void deliver(dpacket d, void *a) { extern jcr_instance jcr; if (d == NULL) return; while (jcr->stream_state != _STREAM_CONNECTED) { log_debug(JDBG, "Stream not ready ... waiting to queue pkts"); sleep(1); } log_debug(JDBG, "queued %d bytes : >>> %s <<<", strlen(xmlnode2str(d->x)), xmlnode2str(d->x)); g_async_queue_push(jcr->dqueue, d); }
void dnsrv_process_xstream_io(int type, xmlnode x, void* arg) { dns_io di = (dns_io)arg; char* hostname = NULL; char* ipaddr = NULL; char* resendhost = NULL; dns_packet_list head = NULL; dns_packet_list heado = NULL; /* Node Format: <host ip="201.83.28.2">foo.org</host> */ if (type == XSTREAM_NODE) { log_debug(ZONE,"incoming resolution: %s",xmlnode2str(x)); hostname = xmlnode_get_data(x); /* whatever the response was, let's cache it */ xmlnode_free((xmlnode)xhash_get(di->cache_table,hostname)); /* free any old cache, shouldn't ever be any */ xmlnode_put_vattrib(x,"t",(void*)time(NULL)); xhash_put(di->cache_table,hostname,(void*)x); /* Get the hostname and look it up in the hashtable */ head = xhash_get(di->packet_table, hostname); /* Process the packet list */ if (head != NULL) { ipaddr = xmlnode_get_attrib(x, "ip"); resendhost = xmlnode_get_attrib(x, "to"); /* Remove the list from the hashtable */ xhash_zap(di->packet_table, hostname); /* Walk the list and insert IPs */ while(head != NULL) { heado = head; /* Move to next.. */ head = head->next; /* Deliver the packet */ dnsrv_resend(heado->packet->x, ipaddr, resendhost); } } /* Host name was not found, something is _TERRIBLY_ wrong! */ else log_debug(ZONE, "Resolved unknown host/ip request: %s\n", xmlnode2str(x)); return; /* we cached x above, so we don't free it below :) */ } xmlnode_free(x); }
/* do not create t.m.p file. We don't need this file because xdb_file moule is thread safe and there is no way to acces the file in many threads returns 1 write oki 0 if maxsize reached, not written -1 error */ int xdb_file2file(char * file, xmlnode node, int maxsize) { char *doc; int fd, i, docsize; if(file == NULL || node == NULL) return -1; doc = xmlnode2str(node); docsize = strlen(doc); if (maxsize && (docsize >= maxsize)) return 0; fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0600); if(fd < 0) return -1; i = write(fd,doc,strlen(doc)); if(i < 0) { close(fd); return -1; } close(fd); return 1; }
/* always deliver threads */ static void js_outgoing_packet(jsmi si, jpacket jp, dpacket p) { session s = NULL; udata u; /* attempt to locate the session by matching the special resource */ u = js_user(si, p->id, 0); if (u == NULL) { log_notice(p->host, "Bouncing packet intended for nonexistant user: %s", xmlnode2str(p->x)); deliver_fail(dpacket_new(p->x), "Invalid User"); return; } 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; } 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"); }
/* Coprocess functionality */ void dnsrv_child_process_xstream_io(int type, xmlnode x, void* args) { dns_io di = (dns_io)args; char* hostname; char* str = NULL; dns_resend_list iternode = NULL; if (type == XSTREAM_NODE) { /* Get the hostname out... */ hostname = xmlnode_get_data(x); log_debug(ZONE, "dnsrv: Recv'd lookup request for %s", hostname); if (hostname != NULL) { /* For each entry in the svclist, try and resolve using the specified service and resend it to the specified host */ iternode = di->svclist; while (iternode != NULL) { str = srv_lookup(x->p, iternode->service, hostname); if (str != NULL) { log_debug(ZONE, "Resolved %s(%s): %s\tresend to:%s", hostname, iternode->service, str, iternode->host); xmlnode_put_attrib(x, "ip", str); xmlnode_put_attrib(x, "to", iternode->host); break; } iternode = iternode->next; } str = xmlnode2str(x); write(di->out, str, strlen(str)); } } xmlnode_free(x); }
int xmlnode2file(char *file, xmlnode node) { char *doc, *ftmp; int fd, i; if(file == NULL || node == NULL) return -1; ftmp = spools(xmlnode_pool(node),file,".t.m.p",xmlnode_pool(node)); fd = open(ftmp, O_CREAT | O_WRONLY | O_TRUNC, 0600); if(fd < 0) return -1; doc = xmlnode2str(node); i = write(fd,doc,strlen(doc)); if(i < 0) return -1; close(fd); if(rename(ftmp,file) < 0) { unlink(ftmp); return -1; } return 1; }
void con_room_leaveall(gpointer key, gpointer data, gpointer arg) { cnu user = (cnu)data; xmlnode info = (xmlnode)arg; char *alt, *reason; xmlnode presence; xmlnode tag; xmlnode element; xmlnode node; xmlnode destroy; log_debug(NAME, "[%s] reason : %s", FZONE, xmlnode2str(info)); if(user == NULL) { log_warn(NAME, "[%s] Aborting - NULL user attribute found", FZONE); return; } if (user->remote == 1) return; presence = jutil_presnew(JPACKET__UNAVAILABLE, NULL, NULL); tag = xmlnode_insert_tag(presence,"x"); xmlnode_put_attrib(tag, "xmlns", NS_MUC_USER); element = xmlnode_insert_tag(tag, "item"); xmlnode_put_attrib(element, "role", "none"); xmlnode_put_attrib(element, "affiliation", "none"); if (info != NULL) { destroy = xmlnode_insert_tag(tag, "destroy"); reason = xmlnode_get_tag_data(info, "reason"); node = xmlnode_insert_tag(destroy, "reason"); if(reason != NULL) { xmlnode_insert_cdata(node, reason, -1); } alt = xmlnode_get_attrib(info, "jid"); if (alt != NULL) { xmlnode_put_attrib(destroy, "jid", alt); } } con_user_send(user, user, presence); }
void con_room_forward_decline(cnr room, jpacket jp, xmlnode decline) { cnu user; jid user_jid; if (room == NULL || decline == NULL || jp == NULL) { log_warn(NAME, "[%s] Aborting - NULL attribute found", FZONE); xmlnode_free(jp->x); return; } user_jid=jid_new(decline->p,xmlnode_get_attrib(decline,"to")); if ((room->invitation == 1 && !is_member(room, jp->from) && !is_owner(room, jp->from)) || user_jid == NULL) { log_warn(NAME, "[%s] Aborting - User is not allowed to send a decline", FZONE); jutil_error(jp->x, TERROR_MUC_OUTSIDE); deliver(dpacket_new(jp->x), NULL); return; } if (user_jid->resource == NULL) { log_warn(NAME, "[%s] Aborting - cannot send back decline, bare jid found", FZONE); return; } if (room->visible == 1) { user = g_hash_table_lookup(room->remote, jid_full(jid_fix(user_jid))); } else { user = g_hash_table_lookup(room->local, user_jid->resource); } if (user == NULL){ log_warn(NAME, "[%s] Aborting - Decline recipient is not in the room", FZONE); jutil_error(jp->x, TERROR_MUC_OUTSIDE); deliver(dpacket_new(jp->x), NULL); return; } log_debug(NAME, "[%s] Sending invitation decline", FZONE); xmlnode_put_attrib(decline, "from", jid_full(jp->from)); xmlnode_hide_attrib(decline, "to"); xmlnode_put_attrib(jp->x, "to", jid_full(user->realid)); xmlnode_put_attrib(jp->x, "from", jid_full(room->id)); log_debug(NAME, "[%s] >>>%s<<<", FZONE, xmlnode2str(jp->x)); deliver(dpacket_new(jp->x), NULL); return; }
result xdb_results(instance id, dpacket p, void *arg) { xdbcache xc = (xdbcache) arg; xdbrequest_p cur, last; unsigned int idnum; char *idstr; if (p->type != p_NORM || *(xmlnode_get_name(p->x)) != 'x') return r_PASS; /* yes, we are matching ANY <x*> element */ log_debug("xdb_results checking xdb packet %s", xmlnode2str(p->x)); if ((idstr = xmlnode_get_attrib(p->x, "id")) == NULL) return r_ERR; idnum = atoi(idstr); SEM_LOCK(xc->sem); for (last = NULL, cur = xc->first; (cur) && (cur->id != idnum); last = cur, cur = cur->next); if (!cur) { pool_free(p->p); SEM_UNLOCK(xc->sem); return r_DONE; } /* associte only a non-error packet w/ waiting cache */ if (j_strcmp(xmlnode_get_attrib(p->x, "type"), "error") == 0) { cur->data = NULL; pool_free(p->p); } else cur->data = p->x; if (!last) xc->first = cur->next; else last->next = cur->next; cur->external = 0; SEM_UNLOCK(xc->sem); cur->preblock = 1; return r_DONE; }
result dnsrv_deliver(instance i, dpacket p, void* args) { dns_io di = (dns_io)args; xmlnode c; int timeout = di->cache_timeout; char *ip; jid to; /* if we get a route packet, it has to be to *us* and have the child as the real packet */ if(p->type == p_ROUTE) { if(j_strcmp(p->host,i->id) != 0 || (to = jid_new(p->p,xmlnode_get_attrib(xmlnode_get_firstchild(p->x),"to"))) == NULL) return r_ERR; p->x=xmlnode_get_firstchild(p->x); p->id = to; p->host = to->server; } /* Ensure this packet doesn't already have an IP */ if(xmlnode_get_attrib(p->x, "ip") || xmlnode_get_attrib(p->x, "iperror")) { log_notice(p->host, "dropping looping dns lookup request: %s", xmlnode2str(p->x)); xmlnode_free(p->x); return r_DONE; } /* try the cache first */ if((c = xhash_get(di->cache_table, p->host)) != NULL) { /* if there's no IP, cached failed lookup, time those out 10 times faster! (weird, I know, *shrug*) */ if((ip = xmlnode_get_attrib(c,"ip")) == NULL) timeout = timeout / 10; if((time(NULL) - (int)xmlnode_get_vattrib(c,"t")) > timeout) { /* timed out of the cache, lookup again */ xmlnode_free(c); xhash_zap(di->cache_table,p->host); }else{ /* yay, send back right from the cache */ dnsrv_resend(p->x, ip, xmlnode_get_attrib(c,"to")); return r_DONE; } } dnsrv_lookup(di, p); return r_DONE; }
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; /* yes, we are matching ANY <x*> element */ 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); pthread_mutex_lock(&(xc->sem)); for(curx = xc->next; curx->id != idnum && curx != xc; curx = curx->next); /* spin till we are where we started or find our id# */ /* we got an id we didn't have cached, could be a dup, ignore and move on */ if(curx->id != idnum) { pool_free(p->p); pthread_mutex_unlock(&(xc->sem)); return r_DONE; } /* associte only a non-error packet w/ waiting cache */ if(j_strcmp(xmlnode_get_attrib(p->x,"type"),"error") == 0) { curx->data = NULL; pool_free(p->p); // very bad memory leak } else curx->data = p->x; /* remove from ring */ curx->prev->next = curx->next; curx->next->prev = curx->prev; pthread_mutex_unlock(&(xc->sem)); /* free the thread! */ curx->preblock = 1; return r_DONE; /* we processed it */ }
/* Hostname lookup requested */ void dnsrv_lookup(dns_io d, dpacket p) { dns_packet_list l, lnew; xmlnode req; char *reqs; /* make sure we have a child! */ if(d->out <= 0) { deliver_fail(p, "DNS Resolver Error"); return; } /* Attempt to lookup this hostname in the packet table */ l = (dns_packet_list)xhash_get(d->packet_table, p->host); /* IF: hashtable has the hostname, a lookup is already pending, so push the packet on the top of the list (most recent at the top) */ if (l != NULL) { log_debug(ZONE, "dnsrv: Adding lookup request for %s to pending queue.", p->host); lnew = pmalloco(p->p, sizeof(_dns_packet_list)); lnew->packet = p; lnew->stamp = time(NULL); lnew->next = l; xhash_put(d->packet_table, p->host, lnew); return; } /* insert the packet into the packet_table using the hostname as the key and send a request to the coprocess */ log_debug(ZONE, "dnsrv: Creating lookup request queue for %s", p->host); l = pmalloco(p->p, sizeof(_dns_packet_list)); l->packet = p; l->stamp = time(NULL); xhash_put(d->packet_table, p->host, l); req = xmlnode_new_tag_pool(p->p,"host"); xmlnode_insert_cdata(req,p->host,-1); reqs = xmlnode2str(req); log_debug(ZONE, "dnsrv: Transmitting lookup request: %s", reqs); pth_write(d->out, reqs, strlen(reqs)); }
void jabber_node(Stream *s,xmlnode x){ char *name; packets_in++; name=xmlnode_get_name(x); if (strcmp(name,"stream:stream")==0) jabber_stream_start(s,x); else if (strcmp(name,"handshake")==0) jabber_handshake(s,x); else if (strcmp(name,"stream:error")==0) jabber_stream_error(s,x); else if (strcmp(name,"iq")==0) jabber_iq(s,x); else if (strcmp(name,"presence")==0) jabber_presence(s,x); else if (strcmp(name,"message")==0) jabber_message(s,x); else g_warning(N_("Unsupported tag: %s"),xmlnode2str(x)); xmlnode_free(x); }
void session_print(Session *s,int indent){ char *space,*space1; GList *it; Resource *r,*cr; char *njid; space=g_strnfill(indent*2,' '); space1=g_strnfill((indent+1)*2,' '); njid=jid_normalized(s->jid,0); g_message(L_("%sSession: %p"),space,s); g_message("%sJID: %s",space,s->jid); g_message(L_("%sUser:"******"%sResources:"),space); cr=session_get_cur_resource(s); for(it=g_list_first(s->resources);it;it=g_list_next(it)){ r=(Resource *)it->data; g_message(L_("%sResource: %p%s"),space1,r,(r==cr)?N_(" (current)"):""); if (njid && r->name) g_message("%sJID: %s/%s",space1,njid,r->name); else g_message("%sJID: %s",space1,s->jid); g_message(L_("%sPriority: %i"),space1,r->priority); g_message(L_("%sAvailable: %i"),space1,r->available); if (r->show) g_message(L_("%sShow: %s"),space1,r->show); if (r->status) g_message(L_("%sStatus: %s"),space1,r->status); } g_message(L_("%sGG session: %p"),space,s->ggs); g_message(L_("%sGSource: %p"),space,s->g_source); g_message(L_("%sStream: %p"),space,s->s); g_message(L_("%sConnected: %i"),space,s->connected); g_message(L_("%sRequest id: %s"),space,s->req_id?s->req_id:"(null)"); g_message(L_("%sRequest query: %s"),space,s->query?xmlnode2str(s->query):"(null)"); g_message(L_("%sWaiting for ping: %i"),space,(int)s->waiting_for_pong); g_free(njid); g_free(space1); g_free(space); }
/* 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; }
/** Callback processing incoming Jabber packets. */ result it_receive(instance i, dpacket d, void *arg) { iti ti = (iti) arg; jpacket jp; session s; session_ref alt_s; unsigned char *user; log_debug(ti->i->id,"Packet received: %s\n",xmlnode2str(d->x)); switch(d->type) { case p_ROUTE: { /* ignore */ return r_PASS; } case p_NONE: case p_NORM: jp = jpacket_new(d->x); break; default: return r_ERR; } if (!jp->from ||/* !jp->from->user ||*/ jp->type == JPACKET_UNKNOWN /* || jpacket_subtype(jp) == JPACKET__ERROR */) { /* ignore invalid packets */ xmlnode_free(jp->x); return r_DONE; } /* JID user part should be case insensitive */ /* convert user part of from JID to lower case */ if(jp->from->user != NULL) for(user = jp->from->user; *user != '\0'; user++) if(*user < 128) *user = tolower(*user); /* Mangle "from" JID, save original attribute for XDB conversion */ xmlnode_put_attrib(jp->x, "origfrom", xmlnode_get_attrib(jp->x, "from")); xmlnode_put_attrib(jp->x, "from", jid_full(jp->from)); SEM_LOCK(ti->sessions_sem); s = (session) wpxhash_get(ti->sessions,jid_full(jid_user(jp->from))); alt_s = (session_ref) wpxhash_get(ti->sessions_alt,jp->to->user); if (s != NULL) { if (s->exit_flag) { SEM_UNLOCK(ti->sessions_sem); log_alert("exit flag","message to exiting session"); if (jp->type != JPACKET_PRESENCE){ jutil_error(jp->x,TERROR_NOTFOUND); it_deliver(ti,jp->x); } else xmlnode_free(jp->x); } else if ((alt_s != NULL) && ( (jp->type == JPACKET_MESSAGE) // all messages || ((jp->type == JPACKET_IQ) && (j_strcmp(xmlnode_get_attrib(jp->iq,"xmlns"),NS_VCARD) == -1)) // all IQs except of vCard || (jp->type == JPACKET_PRESENCE) )) { // all presences _targeted_to_specific_user_ // rewriting "to" and "from" and putting packet back on the wire xmlnode_put_attrib(jp->x, "from", jid_full(it_uin2jid(jp->p,s->uin,jp->to->server))); xmlnode_put_attrib(jp->x, "to", jid_full(alt_s->s->orgid)); SEM_UNLOCK(ti->sessions_sem); it_deliver(ti,jp->x); } else { jp->aux1 = (void *) s; mtq_send(s->q,jp->p,it_session_jpacket,(void *) jp); SEM_UNLOCK(ti->sessions_sem); } } else { SEM_UNLOCK(ti->sessions_sem); if(jpacket_subtype(jp)!=JPACKET__ERROR) it_unknown(ti,jp); else xmlnode_free(jp->x); } return r_DONE; }
int jabber_presence(struct stream_s *stream,xmlnode tag){ char *type; char *from; char *to; xmlnode prio_n; xmlnode show_n; xmlnode status_n; char *show,*status; int priority; char *tmp; User *u; type=xmlnode_get_attrib(tag,"type"); from=xmlnode_get_attrib(tag,"from"); to=xmlnode_get_attrib(tag,"to"); if (from) u=user_get_by_jid(from); else u=NULL; user_load_locale(u); if (!acl_is_allowed(from,tag)){ if (type && !strcmp(type,"error")){ debug("Ignoring forbidden presence error"); return -1; } if (!from) return -1; presence_send_error(stream,to,from,405,_("Not allowed")); return -1; } show_n=xmlnode_get_tag(tag,"show"); if (show_n) show=xmlnode_get_data(show_n); else show=NULL; status_n=xmlnode_get_tag(tag,"status"); if (status_n) status=xmlnode_get_data(status_n); else status=NULL; prio_n=xmlnode_get_tag(tag,"priority"); if (prio_n){ tmp=xmlnode_get_data(prio_n); if (tmp) priority=atoi(tmp); else priority=-1; } else priority=-1; if (!type) type="available"; if (!from || !to){ if (strcmp(type,"error")) presence_send_error(stream,to,from,406,_("Not Acceptable")); g_warning(N_("Bad <presence/>: %s"),xmlnode2str(tag)); return -1; } if (!jid_is_my(to)){ if (strcmp(type,"error")) presence_send_error(stream,to,from,406,_("Not Acceptable")); g_warning(N_("Wrong 'to' in %s"),xmlnode2str(tag)); return -1; } if (!strcmp(type,"available")){ if (jid_has_uin(to)) return presence_direct_available(stream,from,to); else return presence(stream,from,to,1,show,status,priority); } else if (!strcmp(type,"unavailable")){ if (jid_has_uin(to)) return presence_direct_unavailable(stream,from,to); else return presence(stream,from,to,0,show,status,priority); } if (!strcmp(type,"invisible")){ if (jid_has_uin(to)) return presence_direct_unavailable(stream,from,to); else return presence(stream,from,to,-1,show,status,priority); } else if (!strcmp(type,"subscribe")) return presence_subscribe(stream,from,to); else if (!strcmp(type,"unsubscribe")) return presence_unsubscribe(stream,from,to); else if (!strcmp(type,"subscribed")) return presence_subscribed(stream,from,to); else if (!strcmp(type,"unsubscribed")) return presence_unsubscribed(stream,from,to); else if (!strcmp(type,"probe")) return presence_probe(stream,from,to); else if (!strcmp(type,"error")){ g_warning(N_("Error presence received: %s"),xmlnode2str(tag)); return 0; } g_warning(N_("Unsupported type in %s"),xmlnode2str(tag)); presence_send_error(stream,to,from,501,_("Not Implemented")); return -1; }
int user_save(User *u){ FILE *f; char *fn; char *str; char *njid; int r; xmlnode xml,tag,ctag,userlist; g_assert(u!=NULL); str=strchr(u->jid,'/'); g_assert(str==NULL); if (!u->confirmed){ g_message(L_("Not saving user '%s' - account not confirmed."),u->jid); return -1; } g_debug(L_("Saving user '%s'"),u->jid); njid=jid_normalized(u->jid,0); g_assert(njid!=NULL); fn=g_strdup_printf("%s.new",njid); f=fopen(fn,"w"); if (!f){ g_warning(L_("Couldn't open '%s': %s"),fn,g_strerror(errno)); g_free(fn); g_free(njid); return -1; } xml=xmlnode_new_tag("user"); tag=xmlnode_insert_tag(xml,"version"); str=g_strdup_printf("%08x",USER_FILE_FORMAT_VERSION); xmlnode_put_attrib(tag,"file_format",str); g_free(str); tag=xmlnode_insert_tag(xml,"jid"); xmlnode_insert_cdata(tag,u->jid,-1); set_subscribe(tag, u->subscribe); tag=xmlnode_insert_tag(xml,"uin"); str=g_strdup_printf("%lu",(unsigned long)u->uin); xmlnode_insert_cdata(tag,str,-1); g_free(str); tag=xmlnode_insert_tag(xml,"password"); xmlnode_insert_cdata(tag,u->password,-1); if (u->last_sys_msg>0){ tag=xmlnode_insert_tag(xml,"last_sys_msg"); str=g_strdup_printf("%i",u->last_sys_msg); xmlnode_insert_cdata(tag,str,-1); g_free(str); } if (u->invisible) tag=xmlnode_insert_tag(xml,"invisible"); if (u->friends_only) tag=xmlnode_insert_tag(xml,"friendsonly"); if (u->ignore_unknown) tag=xmlnode_insert_tag(xml,"ignore_unknown"); if (u->locale){ tag=xmlnode_insert_tag(xml,"locale"); xmlnode_insert_cdata(tag,u->locale,-1); } if (u->status){ tag=xmlnode_insert_tag(xml,"status"); xmlnode_insert_cdata(tag,to_utf8(u->status),-1); } if (u->contacts){ GList *it; Contact *c; userlist=xmlnode_insert_tag(xml,"userlist"); for(it=g_list_first(u->contacts);it;it=it->next){ c=(Contact *)it->data; ctag=xmlnode_insert_tag(userlist,"contact"); str=g_strdup_printf("%lu",(unsigned long)c->uin); xmlnode_put_attrib(ctag,"uin",str); if (c->ignored) xmlnode_put_attrib(ctag,"ignored","ignored"); if (c->blocked) xmlnode_put_attrib(ctag,"blocked","blocked"); set_subscribe(ctag, c->subscribe); g_free(str); } } str=xmlnode2str(xml); r=fputs(str,f); if (r<0){ g_warning(L_("Couldn't save '%s': %s"),u->jid,g_strerror(errno)); fclose(f); unlink(fn); xmlnode_free(xml); g_free(fn); g_free(njid); return -1; } fclose(f); r=unlink(njid); if (r && errno!=ENOENT){ g_warning(L_("Couldn't unlink '%s': %s"),njid,g_strerror(errno)); xmlnode_free(xml); g_free(fn); g_free(njid); return -1; } r=rename(fn,njid); if (r){ g_warning(L_("Couldn't rename '%s' to '%s': %s"),fn,u->jid,g_strerror(errno)); xmlnode_free(xml); g_free(fn); g_free(njid); return -1; } xmlnode_free(xml); g_free(fn); g_free(njid); return 0; }
/* Handles logging for each room, simply returning if logfile is not defined */ void con_room_log(cnr room, char *nick, char *message) { time_t t; xmlnode xml; jid user; char *output; char timestr[80]; size_t timelen = 79; FILE *logfile; pool p; if(message == NULL || room == NULL) { log_warn(NAME, "[%s] ERR: Aborting - NULL reference found - ", FZONE); return; } logfile = room->logfile; if(logfile == NULL) { log_debug(NAME, "[%s] Logging not enabled for this room", FZONE); return; } p = pool_heap(1024); /* nicked from mod_time */ t = time(NULL); if(room->logformat == LOG_XHTML) strftime(timestr, timelen, "<a name=\"t%H:%M:%S\" href=\"#t%H:%M:%S\">[%H:%M:%S]</a>", localtime(&t)); else strftime(timestr, timelen, "[%H:%M:%S]", localtime(&t)); if(room->logformat == LOG_XML) { xml = jutil_msgnew("groupchat", jid_full(room->id) , NULL, strescape(p, message)); user = jid_new(xmlnode_pool(xml), jid_full(room->id)); jid_set(user, strescape(p, nick), JID_RESOURCE); xmlnode_put_attrib(xml, "from", jid_full(user)); jutil_delay(xml, NULL); fprintf(logfile, "%s\n", xmlnode2str(xml)); xmlnode_free(xml); } else if(room->logformat == LOG_XHTML) { if(nick) { if(j_strncmp(message, "/me ", 4) == 0) { output = extractAction(_con_room_xhtml_strescape(p, message), p); fprintf(logfile, "<span class=\"time\">%s</span> * <span class=\"nick\">%s</span>%s<br />\n", timestr, strescape(p, nick), output); } else { fprintf(logfile, "<span class=\"time\">%s</span> <<span class=\"nick\">%s</span>> %s<br />\n", timestr, strescape(p, nick), _con_room_xhtml_strescape(p, message)); } } else { fprintf(logfile, "<span class=\"time\">%s</span> --- %s<br />\n", timestr, message); } } else { if(nick) { if(j_strncmp(message, "/me ", 4) == 0) { output = extractAction(message, p); fprintf(logfile, "%s * %s%s\n", timestr, nick, output); } else { fprintf(logfile, "%s <%s> %s\n", timestr, nick, message); } } else { fprintf(logfile, "%s --- %s\n", timestr, message); } } fflush(logfile); pool_free(p); return; }
void dnsrv(instance i, xmlnode x) { xdbcache xc = NULL; xmlnode config = NULL; xmlnode iternode = NULL; dns_resend_list tmplist = NULL; /* Setup a struct to hold dns_io handles */ dns_io di; di = pmalloco(i->p, sizeof(_dns_io)); di->mempool = i->p; /* Load config from xdb */ xc = xdb_cache(i); config = xdb_get(xc, jid_new(xmlnode_pool(x), "config@-internal"), "jabber:config:dnsrv"); /* Build a list of services/resend hosts */ iternode = xmlnode_get_lastchild(config); while (iternode != NULL) { if (j_strcmp("resend", xmlnode_get_name(iternode)) != 0) { iternode = xmlnode_get_prevsibling(iternode); continue; } /* Allocate a new list node */ tmplist = pmalloco(di->mempool, sizeof(_dns_resend_list)); tmplist->service = pstrdup(di->mempool, xmlnode_get_attrib(iternode, "service")); tmplist->host = pstrdup(di->mempool, xmlnode_get_data(iternode)); /* Insert this node into the list */ tmplist->next = di->svclist; di->svclist = tmplist; /* Move to next child */ iternode = xmlnode_get_prevsibling(iternode); } log_debug(ZONE, "dnsrv debug: %s\n", xmlnode2str(config)); /* Setup the hash of dns_packet_list */ di->packet_table = xhash_new(j_atoi(xmlnode_get_attrib(config,"queuemax"),101)); di->packet_timeout = j_atoi(xmlnode_get_attrib(config,"queuetimeout"),60); register_beat(di->packet_timeout, dnsrv_beat_packets, (void *)di); /* Setup the internal hostname cache */ di->cache_table = xhash_new(j_atoi(xmlnode_get_attrib(config,"cachemax"),1999)); di->cache_timeout = j_atoi(xmlnode_get_attrib(config,"cachetimeout"),3600); /* 1 hour dns cache? XXX would be nice to get the right value from dns! */ xmlnode_free(config); /* spawn a thread that get's forked, and wait for it since it sets up the fd's */ pth_join(pth_spawn(PTH_ATTR_DEFAULT,(void*)dnsrv_thread,(void*)di),NULL); if(di->pid < 0) { log_error(i->id,"dnsrv failed to start, unable to fork and/or create pipes"); return; } /* Start IO thread */ pth_spawn(PTH_ATTR_DEFAULT, dnsrv_process_io, di); /* Register an incoming packet handler */ register_phandler(i, o_DELIVER, dnsrv_deliver, (void*)di); /* register a cleanup function */ pool_cleanup(i->p, dnsrv_shutdown, (void*)di); }
void con_room_send_invite(cnu sender, xmlnode node) { xmlnode result; xmlnode element; xmlnode invite; xmlnode pass; char *body, *user, *reason, *inviter; cnr room; pool p; if(sender == NULL || node == NULL) { log_warn(NAME, "[%s] Aborting - NULL attribute found", FZONE); return; } log_debug(NAME, "[%s] Sending room invite", FZONE); room = sender->room; invite = xmlnode_get_tag(node, "invite"); user = xmlnode_get_attrib(invite, "to"); reason = xmlnode_get_tag_data(invite, "reason"); p = xmlnode_pool(node); if(room->visible == 1) { inviter = jid_full(sender->realid); } else { inviter = jid_full(sender->localid); } xmlnode_put_attrib(invite, "from", inviter); xmlnode_hide_attrib(invite, "to"); if(reason == NULL) { reason = spools(p, "None given", p); } body = spools(p, "You have been invited to the ", jid_full(room->id), " room by ", inviter, "\nReason: ", reason, p); result = jutil_msgnew("normal", user , "Invitation", body); xmlnode_put_attrib(result, "from", jid_full(room->id)); xmlnode_insert_node(result, node); if(room->secret != NULL) { pass = xmlnode_get_tag(result, "x"); xmlnode_insert_cdata(xmlnode_insert_tag(pass, "password"), room->secret, -1); } element = xmlnode_insert_tag(result, "x"); xmlnode_put_attrib(element, "jid", jid_full(room->id)); xmlnode_put_attrib(element, "xmlns", NS_X_CONFERENCE); xmlnode_insert_cdata(element, reason, -1); log_debug(NAME, "[%s] >>>%s<<<", FZONE, xmlnode2str(result)); deliver(dpacket_new(result), NULL); return; }
/* session thread */ mreturn mod_presence_out(mapi m, void *arg) { xmlnode pnew, delay, pold; modpres mp = (modpres) arg; session cur = NULL; int oldpri, newpri; char *priority; if (m->packet->type != JPACKET_PRESENCE) return M_IGNORE; if (m->packet->to != NULL || jpacket_subtype(m->packet) == JPACKET__PROBE || jpacket_subtype(m->packet) == JPACKET__ERROR) return M_PASS; log_debug("new presence from %s of %s", jid_full(m->s->id), xmlnode2str(m->packet->x)); /* pre-existing conditions (no, we are not an insurance company) */ oldpri = m->s->priority; /* check that the priority is in the valid range */ priority = xmlnode_get_tag_data(m->packet->x, "priority"); if (priority == NULL) { newpri = 0; } else { newpri = j_atoi(priority, 0); if (newpri < -128 || newpri > 127) { log_notice("mod_presence", "got presence with invalid priority value from %s", jid_full(m->s->id)); xmlnode_free(m->packet->x); return M_HANDLED; } } /* invisible mode is special, don't you wish you were special too? */ if (jpacket_subtype(m->packet) == JPACKET__INVISIBLE) { log_debug("handling invisible mode request"); /* if we get this and we're available, it means go unavail first then reprocess this packet, nifty trick :) */ if (oldpri >= -128) { js_session_from(m->s, jpacket_new(jutil_presnew (JPACKET__UNAVAILABLE, NULL, xmlnode_get_tag_data(m->packet->x,"status") ))); js_session_from(m->s, m->packet); return M_HANDLED; } /* now, pretend we come online :) */ /* (this is the handling of the reinjected invisible presence * or an initial invisible presence) */ mp->invisible = 1; mod_presence_roster(m, NULL); /* send out probes to users we are subscribed to */ m->s->priority = newpri; /* store presence in xdb? */ if (mp->conf->pres_to_xdb > 0) mod_presence_store(m); xmlnode_free(m->packet->x); /* we do not broadcast invisible presences without a to attribute */ return M_HANDLED; } /* our new presence */ pnew = xmlnode_dup(m->packet->x); /* store presence in xdb? */ if (mp->conf->pres_to_xdb > 0) mod_presence_store(m); /* stamp the sessions presence */ delay = xmlnode_insert_tag(pnew, "x"); xmlnode_put_attrib(delay, "xmlns", NS_DELAY); xmlnode_put_attrib(delay, "from", jid_full(m->s->id)); xmlnode_put_attrib(delay, "stamp", jutil_timestamp()); /* our old presence */ pold = m->s->presence; m->s->presence = pnew; m->s->priority = jutil_priority(pnew); log_debug("presence oldp %d newp %d", oldpri, m->s->priority); /* if we're going offline now, let everyone know */ if (m->s->priority < -128) { /* jutil_priority returns -129 in case the "type" attribute is missing */ if (!mp->invisible) /* bcc's don't get told if we were invisible */ _mod_presence_broadcast(m->s, mp->conf->bcc, m->packet->x, NULL); _mod_presence_broadcast(m->s, mp->A, m->packet->x, NULL); _mod_presence_broadcast(m->s, mp->I, m->packet->x, NULL); /* reset vars */ mp->invisible = 0; mp->A->next = NULL; mp->I = NULL; xmlnode_free(m->packet->x); xmlnode_free(pold); return M_HANDLED; } /* available presence updates, intersection of A and T */ if (oldpri >= -128 && !mp->invisible) { _mod_presence_broadcast_trusted(m->s, mp->A, m->packet->x); xmlnode_free(m->packet->x); xmlnode_free(pold); return M_HANDLED; } /* at this point we're coming out of the closet */ mp->invisible = 0; /* make sure we get notified for any presence about ourselves */ /* XXX: the following is the original code: it caused existing presences * to be stamped several times and the presence to be sent out twice. pnew = jutil_presnew(JPACKET__PROBE,jid_full(m->s->uid),NULL); xmlnode_put_attrib(pnew,"from",jid_full(m->s->uid)); js_session_from(m->s, jpacket_new(pnew)); */ /* XXX: I think this should be okay as well: */ /* send us all presences of our other resources */ for (cur = m->user->sessions; cur != NULL; cur = cur->next) { pool pool_for_existing_presence = NULL; xmlnode duplicated_presence = NULL; jpacket packet = NULL; /* skip our own session (and sanity check) */ if (cur == m->s || cur->presence == NULL) { continue; } /* send the presence to us: we need a new pool as js_session_to() will free the packet's pool */ pool_for_existing_presence = pool_new(); duplicated_presence = xmlnode_dup_pool(pool_for_existing_presence, cur->presence); xmlnode_put_attrib(duplicated_presence, "to", jid_full(m->user->id)); packet = jpacket_new(duplicated_presence); js_session_to(m->s, packet); } /* probe s10ns and populate A */ mod_presence_roster(m, mp->A); /* we broadcast this baby! */ _mod_presence_broadcast(m->s, mp->conf->bcc, m->packet->x, NULL); _mod_presence_broadcast(m->s, mp->A, m->packet->x, NULL); xmlnode_free(m->packet->x); xmlnode_free(pold); return M_HANDLED; }
int jabber_message(struct stream_s *stream,xmlnode tag){ char *type; char *from; char *to; char *subject; char *body; int chat; xmlnode subject_n; xmlnode body_n; Session *s; User *u; body_n=xmlnode_get_tag(tag,"body"); if (body_n!=NULL) body=xmlnode_get_data(body_n); else body=NULL; subject_n=xmlnode_get_tag(tag,"subject"); if (subject_n!=NULL) subject=xmlnode_get_data(subject_n); else subject=NULL; from=xmlnode_get_attrib(tag,"from"); to=xmlnode_get_attrib(tag,"to"); type=xmlnode_get_attrib(tag,"type"); if (!acl_is_allowed(from,tag)){ if (type && !strcmp(type,"error")){ debug("Ignoring forbidden message error"); return -1; } if (!from) return -1; message_send_error(stream,to,from,NULL,405,_("Not allowed")); return -1; } if (from) u=user_get_by_jid(from); else u=NULL; user_load_locale(u); if (!type || !strcmp(type,"normal")) chat=0; else if (!strcmp(type,"chat")) chat=1; else if (!strcmp(type,"error")){ g_warning(N_("Error message received: %s"),xmlnode2str(tag)); return 0; } else{ g_warning(N_("Unsupported message type")); message_send_error(stream,to,from,body,500,_("Internal Server Error")); return -1; } if (!to || !jid_is_my(to)){ g_warning(N_("Bad 'to' in: %s"),xmlnode2str(tag)); message_send_error(stream,to,from,body,400,_("Bad Request")); return -1; } if (!jid_has_uin(to)){ return message_to_me(stream,from,to,body,tag); } if (!from){ g_warning(N_("Anonymous message? %s"),xmlnode2str(tag)); message_send_error(stream,to,from,body,400,_("Bad Request")); return -1; } s=session_get_by_jid(from,NULL,0); if (!s || !s->connected){ g_warning(N_("%s not logged in. While processing %s"),from,xmlnode2str(tag)); message_send_error(stream,to,from,body,407,_("Not logged in")); return -1; } if (subject) body=g_strdup_printf("Subject: %s\n%s",subject,body); session_send_message(s,jid_get_uin(to),chat,string_to_gg(body)); if (subject) g_free(body); return 0; }
/* returns a valid nick from the list, x is the first <nick>foo</nick> xmlnode, checks siblings */ char *con_room_nick(cnr room, cnu user, xmlnode x) { char *nick = NULL; xmlnode cur; int count = 1; if(room == NULL || user == NULL) { log_warn(NAME, "[%s] Aborting - NULL attribute found", FZONE); return NULL; } log_debug(NAME, "[%s] looking for valid nick in room %s from starter %s", FZONE, jid_full(room->id), xmlnode2str(x)); /* make-up-a-nick phase */ if(x == NULL) { nick = pmalloco(user->p, j_strlen(user->realid->user) + 10); log_debug(NAME, "[%s] Malloc: Nick = %d", FZONE, j_strlen(user->realid->user) + 10); sprintf(nick, "%s", user->realid->user); while(g_hash_table_lookup(room->local, nick) != NULL) sprintf(nick, "%s%d", user->realid->user,count++); return nick; } /* scan the list */ for(cur = x; cur != NULL; cur = xmlnode_get_nextsibling(cur)) { if(j_strcmp(xmlnode_get_name(cur),"nick") == 0 && (nick = xmlnode_get_data(cur)) != NULL) if(g_hash_table_lookup(room->local, nick) == NULL) break; } if(is_registered(room->master, jid_full(jid_user(user->realid)), nick) == -1) nick = NULL; return nick; }
void jcr_queue_deliver(void *a) { extern jcr_instance jcr; GIOStatus rc = G_IO_STATUS_NORMAL; GString *buffer; gsize bytes; int left, len, pkts; dpacket d; GTimeVal timeout; int buf_size = j_atoi(xmlnode_get_data(xmlnode_get_tag(jcr->config,"send-buffer")), 8192); log_warn(JDBG, "packet delivery thread starting."); buffer = g_string_new(NULL); while(TRUE) { g_string_set_size(buffer, 0); pkts = 0; g_get_current_time(&timeout); g_time_val_add(&timeout, (5 * G_USEC_PER_SEC)); d = (dpacket)g_async_queue_timed_pop(jcr->dqueue, &timeout); if (d == NULL) { if (jcr->stream_state == _STREAM_CONNECTED) continue; else break; } g_string_append(buffer, xmlnode2str(d->x)); xmlnode_free(d->x); d = NULL; left = len = buffer->len; pkts++; while ((g_async_queue_length(jcr->dqueue) > 0) && (buffer->len < buf_size)) { d = (dpacket)g_async_queue_pop(jcr->dqueue); g_string_append(buffer, xmlnode2str(d->x)); xmlnode_free(d->x); d = NULL; left = len = buffer->len; pkts++; } // log_debug(JDBG, "%d '%s'", len, buf); while ((left > 0) && (rc == G_IO_STATUS_NORMAL)) { rc = g_io_channel_write_chars(jcr->gio, (buffer->str+(len - left)), left, &bytes, NULL); left = left - bytes; if (rc != G_IO_STATUS_NORMAL) { log_warn(JDBG, "Send packet failed, dropping packet"); } log_debug(JDBG, "wrote %d packets of %d bytes", pkts, bytes); // fprintf(stderr, "wrote %d packets of %d bytes\n", pkts, bytes); if (left==0){ //queue is empty, flushing the socket g_io_channel_flush(jcr->gio, NULL); } } } log_warn(JDBG, "packet delivery thread exiting."); log_warn(JDBG, " Last DvryQ Buffer='%.*s'", buffer->len, buffer->str); g_string_free(buffer, TRUE); }
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; }