📄 mod_roster.c
字号:
* handle packets sent by the user in the jabber:iq:roster namespace * * @param mapi the mapi instance containing the packet * @return M_PASS if not in the jabber:iq:roster namespace, M_HANDLED otherwise */mreturn mod_roster_out_iq(mapi m) { xmlnode roster, cur, pres, item; int newflag; jid id; if (!NSCHECK(m->packet->iq,NS_ROSTER)) return M_PASS; roster = mod_roster_get(m->user); switch(jpacket_subtype(m->packet)) { case JPACKET__GET: log_debug2(ZONE, LOGT_ROSTER, "handling get request"); xmlnode_put_attrib(m->packet->x,"type","result"); m->s->roster = 1; /* insert the roster into the result */ xmlnode_hide(m->packet->iq); xmlnode_insert_tag_node(m->packet->x, roster); jpacket_reset(m->packet); /* filter out pending subscribes */ for(cur = xmlnode_get_firstchild(m->packet->iq); cur != NULL; cur = xmlnode_get_nextsibling(cur)) { if (xmlnode_get_attrib(cur,"subscribe") != NULL) xmlnode_hide_attrib(cur,"subscribe"); if (xmlnode_get_attrib(cur,"hidden") != NULL) xmlnode_hide(cur); } /* send to the user */ js_session_to(m->s,m->packet); /* redeliver those subscribes */ for(cur = xmlnode_get_firstchild(roster); cur != NULL; cur = xmlnode_get_nextsibling(cur)) if (xmlnode_get_attrib(cur,"subscribe") != NULL) { pres = xmlnode_new_tag("presence"); xmlnode_put_attrib(pres,"type","subscribe"); xmlnode_put_attrib(pres,"from",xmlnode_get_attrib(cur,"jid")); if (strlen(xmlnode_get_attrib(cur,"subscribe")) > 0) xmlnode_insert_cdata(xmlnode_insert_tag(pres,"status"),xmlnode_get_attrib(cur,"subscribe"),-1); js_session_to(m->s,jpacket_new(pres)); } break; case JPACKET__SET: log_debug2(ZONE, LOGT_ROSTER, "handling set request"); /* loop through the incoming items updating or creating */ for(cur = xmlnode_get_firstchild(m->packet->iq); cur != NULL; cur = xmlnode_get_nextsibling(cur)) { if (xmlnode_get_type(cur) != NTYPE_TAG || xmlnode_get_attrib(cur,"jid") == NULL) continue; id = jid_new(m->packet->p,xmlnode_get_attrib(cur,"jid")); if (id == NULL || jid_cmpx(jid_user(m->s->id),id,JID_USER|JID_SERVER) == 0) continue; /* zoom to find the existing item in the current roster, and hide it */ item = mod_roster_get_item(roster, id, &newflag); xmlnode_hide(item); /* drop you sukkah */ if (j_strcmp(xmlnode_get_attrib(cur,"subscription"),"remove") == 0) { /* cancel our subscription to them */ if (j_strcmp(xmlnode_get_attrib(item,"subscription"),"both") == 0 || j_strcmp(xmlnode_get_attrib(item,"subscription"),"to") == 0 || j_strcmp(xmlnode_get_attrib(item,"ask"),"subscribe") == 0) { jpacket jp = jpacket_new(jutil_presnew(JPACKET__UNSUBSCRIBE,xmlnode_get_attrib(cur,"jid"),NULL)); jp->flag = PACKET_FORCE_SENT_MAGIC; /* force to sent it, as we already remove the subscription state */ js_session_from(m->s, jp); } /* tell them their subscription to us is toast */ if (j_strcmp(xmlnode_get_attrib(item,"subscription"),"both") == 0 || j_strcmp(xmlnode_get_attrib(item,"subscription"),"from") == 0) { jpacket jp = jpacket_new(jutil_presnew(JPACKET__UNSUBSCRIBED,xmlnode_get_attrib(cur,"jid"),NULL)); jp->flag = PACKET_FORCE_SENT_MAGIC; /* force to sent it, as we already remove the subscription state */ js_session_from(m->s, jp); } /* push this remove out */ mod_roster_push(m->user,cur); continue; } /* copy the old stuff into the new one and insert it into the roster */ xmlnode_put_attrib(cur,"subscription",xmlnode_get_attrib(item,"subscription")); xmlnode_put_attrib(cur,"ask",xmlnode_get_attrib(item,"ask")); /* prolly not here, but just in case */ xmlnode_put_attrib(cur,"subscribe", xmlnode_get_attrib(item, "subscribe")); xmlnode_insert_tag_node(roster,cur); /* push the new item */ mod_roster_push(m->user,cur); } /* send to the user */ jutil_iqresult(m->packet->x); jpacket_reset(m->packet); js_session_to(m->s,m->packet); /* save the changes */ log_debug2(ZONE, LOGT_ROSTER, "SROSTER: %s",xmlnode2str(roster)); /* XXX what do we do if the set fails? hrmf... */ xdb_set(m->si->xc, m->user->id, NS_ROSTER, roster); break; default: /* JPACKET__RESULT: result from a roster push to the client */ xmlnode_free(m->packet->x); } xmlnode_free(roster); return M_HANDLED;}/** * handle outgoing packets: check for iq and subscription stanzas * * @param m the mapi instance (containing the packet) * @param arg not used/ignored * @return M_IGNORE if the packet is not an iq or subscription packet, else M_PASS if packet not handled or M_HANDLED if packet handled */mreturn mod_roster_out(mapi m, void *arg){ if (m->packet->type == JPACKET_IQ) return mod_roster_out_iq(m); if (m->packet->type == JPACKET_S10N) return mod_roster_out_s10n(m); return M_IGNORE;}/** * register mod_roster_out callback for outgoing stanzas when a new session starts * * @param m the mapi instance * @param arg unused/ignored * @return always M_PASS */mreturn mod_roster_session(mapi m, void *arg){ js_mapi_session(es_OUT,m->s,mod_roster_out,NULL); return M_PASS;}/** * handles subscription stanzas sent to an user * * @param m the mapi instance * @param arg not used/ignored * @return I_IGNORE if not a subscription stanza, else M_PASS if not handled or M_HANDLED if handled */mreturn mod_roster_s10n(mapi m, void *arg) { xmlnode roster, item, reply, reply2; char *status; session top; int newflag, drop, to, from, push, p_in, p_out; push = newflag = drop = to = from = p_in = p_out = 0; /* check for incoming s10n (subscription) requests */ if (m->packet->type != JPACKET_S10N) return M_IGNORE; /* the user must exist */ if (m->user == NULL) return M_PASS; /* don't handle packets sent from the user to himself */ if (jid_cmpx(m->packet->from, m->packet->to, JID_USER|JID_SERVER) == 0) return M_PASS; /* vanity complex */ /* now we can get to work and handle this user's incoming subscription crap */ roster = mod_roster_get(m->user); item = mod_roster_get_item(roster, m->packet->from, &newflag); reply2 = reply = NULL; jid_set(m->packet->to, NULL, JID_RESOURCE); /* make sure we're only dealing w/ the user id */ log_debug2(ZONE, LOGT_ROSTER, "s10n %s request from %s with existing item %s", xmlnode_get_attrib(m->packet->x, "type"), jid_full(m->packet->from), xmlnode2str(item)); /* vars containing the old state of the subscritpion */ if (j_strcmp(xmlnode_get_attrib(item,"subscription"),"to") == 0) to = 1; if (j_strcmp(xmlnode_get_attrib(item,"subscription"),"from") == 0) from = 1; if (j_strcmp(xmlnode_get_attrib(item,"subscription"),"both") == 0) to = from = 1; if (j_strcmp(xmlnode_get_attrib(item, "ask"), "subscribe") == 0) p_out = 1; if (xmlnode_get_attrib(item, "subscribe") != NULL) p_in = 1; /* ask='unsubscribe' can be in xdb from old data written by jabberd up to version 1.4.3 */ if (j_strcmp(xmlnode_get_attrib(item, "ask"), "unsubscribe") == 0) { to = 0; xmlnode_put_attrib(item, "subscription", from ? "from" : "none"); } switch(jpacket_subtype(m->packet)) { case JPACKET__SUBSCRIBE: if (from) { /* already subscribed, respond automatically */ reply = jutil_presnew(JPACKET__SUBSCRIBED, jid_full(m->packet->from), "Already Subscribed"); jid_set(m->packet->to, NULL, JID_RESOURCE); xmlnode_put_attrib(reply, "from", jid_full(m->packet->to)); drop = 1; /* the other person obviously is re-adding them to their roster, and should be told of the current presence */ reply2 = jutil_presnew(JPACKET__PROBE,jid_full(m->packet->to),NULL); xmlnode_put_attrib(reply2,"from",jid_full(m->packet->from)); } else if (p_in) { /* we already know that this contact asked for subscription */ drop = 1; /* no state change */ } else { /* tuck request in the roster */ drop = 0; status = xmlnode_get_tag_data(m->packet->x,"status"); if (status == NULL) xmlnode_put_attrib(item,"subscribe",""); else xmlnode_put_attrib(item,"subscribe",status); if (newflag) /* SPECIAL CASE: special flag so that we can hide these incoming subscribe requests */ xmlnode_put_attrib(item,"hidden",""); } break; case JPACKET__SUBSCRIBED: if (to || !p_out) { /* already subscribed, or we don't want to subscribe: drop */ drop = 1; } else { /* cancel any ask, s10n=to */ xmlnode_hide_attrib(item,"ask"); mod_roster_set_s10n(from, 1, item); push = 1; } break; case JPACKET__UNSUBSCRIBE: if (from || p_in) { /* respond automatically */ reply = jutil_presnew(JPACKET__UNSUBSCRIBED,jid_full(m->packet->from),"Autoreply"); jid_set(m->packet->to,NULL,JID_RESOURCE); xmlnode_put_attrib(reply,"from",jid_full(m->packet->to)); /* update state */ xmlnode_hide_attrib(item,"subscribe"); mod_roster_set_s10n(0, to, item); if (xmlnode_get_attrib(item,"hidden") != NULL) xmlnode_hide(item); else push = 1; } else { if (newflag) xmlnode_hide(item); drop = 1; } break; case JPACKET__UNSUBSCRIBED: if (to || p_out) { /* cancel any ask, remove s10n=to */ xmlnode_hide_attrib(item,"ask"); mod_roster_set_s10n(from, 0, item); push = 1; } else { if (newflag) xmlnode_hide(item); drop = 1; } } /* XXX what do we do if the set fails? hrmf... */ xdb_set(m->si->xc, m->user->id, NS_ROSTER, roster); /* these are delayed until after we check the roster back in, avoid rancid race conditions */ if (reply != NULL) js_deliver(m->si,jpacket_new(reply)); if (reply2 != NULL) js_deliver(m->si,jpacket_new(reply2)); /* find primary session */ top = js_session_primary(m->user); /* if we can, deliver this to that session */ if (!drop && top != NULL && top->roster) js_session_to(top,m->packet); else xmlnode_free(m->packet->x); if (push) mod_roster_push(m->user,item); xmlnode_free(roster); return M_HANDLED;}/** * init the mod_roster module * * Register the following callbacks: * - mod_roster_session for new sessions * - mod_roster_s10n for stanzas send to a user * * @param si the session manager instance */void mod_roster(jsmi si){ /* we just register for new sessions */ js_mapi_register(si,e_SESSION,mod_roster_session,NULL); js_mapi_register(si,e_DELIVER,mod_roster_s10n,NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -