Logo Search packages:      
Sourcecode: jabberd14 version File versions  Download package

static mreturn mod_roster_s10n ( mapi  m,
void *  arg 
) [static]

handles subscription stanzas sent to an user

Parameters:
m the mapi instance
arg not used/ignored
Returns:
I_IGNORE if not a subscription stanza, else M_PASS if not handled or M_HANDLED if handled

Definition at line 492 of file mod_roster.cc.

References udata_struct::id, j_strcmp(), jpacket_new(), jpacket_subtype(), js_deliver(), js_remove_trustee(), js_seen_jids(), js_session_primary(), js_session_to(), jutil_delay(), jutil_presnew(), M_HANDLED, M_IGNORE, M_PASS, messages_get(), mod_roster_changed(), mod_roster_get(), mod_roster_get_item(), mod_roster_push(), mod_roster_set_s10n(), mapi_struct::packet, session_struct::roster, mapi_struct::s, mapi_struct::si, jsmi_struct::std_namespace_prefixes, mapi_struct::user, jsmi_struct::xc, xdb_act_path(), xdb_set(), xmlnode_dup(), xmlnode_free(), xmlnode_get_attrib_ns(), xmlnode_get_data(), xmlnode_get_lang(), xmlnode_get_list_item(), xmlnode_get_tags(), xmlnode_hide(), xmlnode_hide_attrib_ns(), xmlnode_put_attrib_ns(), and xmlnode_serialize_string().

Referenced by mod_roster().

                                                  {
    xmlnode roster, item, reply, reply2;
    char *status;
    session top;
    int newflag, drop, to, from, push, p_in, p_out;
    int store_request = 0;

    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_ns(m->packet->x, "type", NULL), jid_full(m->packet->from), xmlnode_serialize_string(item, xmppd::ns_decl_list(), 0));

    /* vars containing the old state of the subscritpion */
    if (j_strcmp(xmlnode_get_attrib_ns(item, "subscription", NULL), "to") == 0)
        to = 1;
    if (j_strcmp(xmlnode_get_attrib_ns(item, "subscription", NULL), "from") == 0)
        from = 1;
    if (j_strcmp(xmlnode_get_attrib_ns(item, "subscription", NULL), "both") == 0)
        to = from = 1;
    if (j_strcmp(xmlnode_get_attrib_ns(item, "ask", NULL), "subscribe") == 0)
      p_out = 1;
    if (xmlnode_get_attrib_ns(item, "subscribe", NULL) != 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_ns(item, "ask", NULL), "unsubscribe") == 0) {
      to = 0;
      xmlnode_put_attrib_ns(item, "subscription", NULL, NULL, 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), messages_get(xmlnode_get_lang(m->packet->x), N_("Already Subscribed")));
            jid_set(m->packet->to, NULL, JID_RESOURCE);
            xmlnode_put_attrib_ns(reply, "from", NULL, NULL, 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_ns(reply2, "from", NULL, NULL, jid_full(m->packet->from));
          } else if (p_in) {
            /* we already know that this contact asked for subscription */
            drop = 1;
            /* no state change */

            /* but we update the subscription request in xdb */
            store_request = 1;
          } else {
            /* tuck request in the roster */
            drop = 0;
            status = xmlnode_get_data(xmlnode_get_list_item(xmlnode_get_tags(m->packet->x, "status", m->si->std_namespace_prefixes), 0));
            if (status == NULL)
                xmlnode_put_attrib_ns(item, "subscribe", NULL, NULL, "");
            else
                xmlnode_put_attrib_ns(item, "subscribe", NULL, NULL, status);
            if (newflag) /* SPECIAL CASE: special flag so that we can hide these incoming subscribe requests */
                xmlnode_put_attrib_ns(item, "hidden", NULL, NULL, "");

            /* store the request stanza in xdb */
            store_request = 1;
          }
          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_ns(item, "ask", NULL);
            mod_roster_set_s10n(from, 1, item);
            push = 1;
            jid_append(js_seen_jids(m->user), m->packet->from); /* make them seen now */
          }
          break;
      case JPACKET__UNSUBSCRIBE:
          if (from || p_in) {
            /* respond automatically */
            reply = jutil_presnew(JPACKET__UNSUBSCRIBED,jid_full(m->packet->from), messages_get(xmlnode_get_lang(m->packet->x), N_("Autoreply")));
            jid_set(m->packet->to,NULL,JID_RESOURCE);
            xmlnode_put_attrib_ns(reply, "from", NULL, NULL, jid_full(m->packet->to));

            /* update state */
            js_remove_trustee(m->user, m->packet->from);
            xmlnode_hide_attrib_ns(item, "subscribe", NULL);
            mod_roster_set_s10n(0, to, item);
            if (xmlnode_get_attrib_ns(item, "hidden", NULL) != 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_ns(item, "ask", NULL);
            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);

    /* store the request in xdb */
    if (store_request) {
      xmlnode request = xmlnode_dup(m->packet->x);
      jutil_delay(request, N_("Offline Storage"));
      xdb_act_path(m->si->xc, m->user->id, NS_JABBERD_STOREDREQUEST, "insert", spools(m->packet->p, "presence[@from='", jid_full(m->packet->from), "']", m->packet->p), m->si->std_namespace_prefixes, request);
    }

    /* 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), m->s);
    if (reply2 != NULL)
      js_deliver(m->si, jpacket_new(reply2), m->s);

    /* 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);

      /* fire event to notify about changed roster */
      mod_roster_changed(m->user, roster);
    }

    xmlnode_free(roster);
    return M_HANDLED;
}


Generated by  Doxygen 1.6.0   Back to index