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

static mreturn mod_privacy_out_iq_set_list ( mapi  m,
xmlnode  new_list 
) [static]

handle a privacy list update

Todo:
RFC3920 requires that deleting a list fails if there is no such list. We are confirming such a deletion as well for performance reasons. Think about that.
Parameters:
m the mapi structure containing the request
new_list the new list definition (empty list element, to delete a list)
Returns:
M_HANDLED

Definition at line 1067 of file mod_privacy.cc.

References session_struct::aux_data, udata_struct::aux_data, udata_struct::id, j_strcmp(), j_strlen(), jpacket_reset(), js_bounce_xmpp(), js_session_to(), jutil_iqresult(), M_HANDLED, M_PASS, mod_privacy_activate_named(), mod_privacy_list_in_use_by_other(), mod_privacy_load_offline_list(), mod_privacy_no_active_list(), mod_privacy_safe_name(), mod_privacy_send_notify_new_list(), xmlnode_list_item_t::next, xmlnode_list_item_t::node, mapi_struct::packet, mapi_struct::s, mapi_struct::si, jsmi_struct::std_namespace_prefixes, mapi_struct::user, jsmi_struct::xc, xdb_act_path(), xdb_get(), xhash_get(), xmlnode_free(), xmlnode_get_attrib_ns(), xmlnode_get_tags(), xmlnode_put_attrib_ns(), and xmlnode_serialize_string().

Referenced by mod_privacy_out_iq_set().

                                                                     {
    const char* edited_list = NULL;
    char* edited_list_path = NULL;
    xmlnode_list_item new_items = NULL;
    int xdb_result = 0;
    xmlnode previous_lists = NULL;
    xmlnode_list_item previous_list = NULL;
    int is_default_update = 0;
    int list_items = 0;

    /* sanity check */
    if (m == NULL || new_list == NULL)
      return M_PASS;

    edited_list = xmlnode_get_attrib_ns(new_list, "name", NULL);

    /* for editing we need a list name */
    if (edited_list == NULL) {
      js_bounce_xmpp(m->si, m->s, m->packet->x, XTERROR_BAD);
      return M_HANDLED;
    }

    log_debug2(ZONE, LOGT_EXECFLOW, "Setting new privacy list definition for list '%s'", edited_list);

    /* we cannot handle some names */
    if (!mod_privacy_safe_name(edited_list)) {
      log_debug2(ZONE, LOGT_EXECFLOW, "We cannot accept this privacy list name.");
      js_bounce_xmpp(m->si, m->s, m->packet->x, (xterror){406, N_("The server cannot accept that privacy list name."), "modify", "not-acceptable"});
      return M_HANDLED;
    }

    /* the list must not be in use by another session */
    if (mod_privacy_list_in_use_by_other(m->s, edited_list) > 0) {
      log_debug2(ZONE, LOGT_EXECFLOW, "Privacy list is in use and cannot be updated.");
      js_bounce_xmpp(m->si, m->s, m->packet->x, XTERROR_CONFLICT);
      return M_HANDLED;
    }

    /* is the edited list the default list? */
    previous_lists = xdb_get(m->si->xc, m->user->id, NS_PRIVACY);
    edited_list_path = spools(m->packet->p, "privacy:list[@name='", edited_list, "']", m->packet->p);
    previous_list = xmlnode_get_tags(previous_lists, edited_list_path, m->si->std_namespace_prefixes);
    if (previous_list != NULL && xmlnode_get_attrib_ns(previous_list->node, "default", NS_JABBERD_WRAPPER) != NULL) {
      is_default_update = 1;
      xmlnode_put_attrib_ns(new_list, "default", "jabberd", NS_JABBERD_WRAPPER, "default");
    }

    /* is it an edit or a delete request? */
    log_debug2(ZONE, LOGT_EXECFLOW, "Checking the new list: %s", xmlnode_serialize_string(new_list, xmppd::ns_decl_list(), 0));
    for (new_items = xmlnode_get_tags(new_list, "privacy:item", m->si->std_namespace_prefixes); new_items != NULL; new_items = new_items->next) {
      const char* type = xmlnode_get_attrib_ns(new_items->node, "type", NULL);
      const char* value = xmlnode_get_attrib_ns(new_items->node, "value", NULL);
      const char* action = xmlnode_get_attrib_ns(new_items->node, "action", NULL);
      const char* order = xmlnode_get_attrib_ns(new_items->node, "order", NULL);

      /* validate this item */
      if (order == NULL) {
          xmlnode_free(previous_lists);
          js_bounce_xmpp(m->si, m->s, m->packet->x, (xterror){400, N_("Privacy list is invalid: item without order attribute"),"modify","bad-request"});
          return M_HANDLED;
      }
      if (j_strcmp(action, "deny") != 0 && j_strcmp(action, "allow") != 0) {
          xmlnode_free(previous_lists);
          js_bounce_xmpp(m->si, m->s, m->packet->x, (xterror){400, N_("Privacy list is invalid: item action has to be either 'deny' or 'allow'"),"modify","bad-request"});
          return M_HANDLED;
      }
      if (type == NULL) {
          if (value != NULL) {
            xmlnode_free(previous_lists);
            js_bounce_xmpp(m->si, m->s, m->packet->x, (xterror){400, N_("Privacy list is invalid: fall-through item is not allowed to have a value"),"modify","bad-request"});
            return M_HANDLED;
          }
      } else if (j_strcmp(type, "jid") == 0) {
          jid test_jid = jid_new(m->packet->p, value);
          if (test_jid == NULL) {
            xmlnode_free(previous_lists);
            js_bounce_xmpp(m->si, m->s, m->packet->x, (xterror){400, N_("Privacy list is invalid: if type is 'jid', value has to be a valid JID"),"modify","bad-request"});
            return M_HANDLED;
          }
      } else if (j_strcmp(type, "group") == 0) {
          if (j_strlen(value) <= 0) {
            xmlnode_free(previous_lists);
            js_bounce_xmpp(m->si, m->s, m->packet->x, (xterror){400, N_("Privacy list is invalid: if type is 'group', value has to be a roster group name"),"modify","bad-request"});
            return M_HANDLED;
          }
          /* XXX TODO: check that roster group exists */
      } else if (j_strcmp(type, "subscription") == 0) {
          if (j_strcmp(value, "both") != 0 && j_strcmp(value, "none") != 0 && j_strcmp(value, "to") != 0 && j_strcmp(value, "from") != 0) {
            xmlnode_free(previous_lists);
            js_bounce_xmpp(m->si, m->s, m->packet->x, (xterror){400, N_("Privacy list is invalid: if type is 'subscription', value has to be one of 'none', 'from', 'to', or 'both'"),"modify","bad-request"});
            return M_HANDLED;
          }
      } else {
          xmlnode_free(previous_lists);
          js_bounce_xmpp(m->si, m->s, m->packet->x, (xterror){400, N_("Privacy list is invalid: if type is present, it has to be one of 'jid', 'group', or 'subscription'"),"modify","bad-request"});
          return M_HANDLED;
      }

      list_items++;
    }

    if (new_items <= 0) {
      log_debug2(ZONE, LOGT_EXECFLOW, "This is a deletion request");
    }

    /* save the new list */
    xdb_result = xdb_act_path(m->si->xc, m->user->id, NS_PRIVACY, "insert", edited_list_path, m->si->std_namespace_prefixes, list_items > 0 ? new_list : NULL);
    if (xdb_result) {
      xmlnode_free(previous_lists);
      log_debug2(ZONE, LOGT_STORAGE, "Error updating stored data.");
      js_bounce_xmpp(m->si, m->s, m->packet->x, XTERROR_INTERNAL);
      return M_HANDLED;
    }

    log_debug2(ZONE, LOGT_STORAGE, "New privacy list definition has been stored.");

    /* if it has been the default list, do we have to update the user's offline list? */
    if (xhash_get(m->user->aux_data, "mod_privacy_lists_loaded")) {
      mod_privacy_load_offline_list(m->user);
    }

    /* do we use this list? */
    if (j_strcmp(static_cast<char*>(xhash_get(m->s->aux_data, "mod_privacy_active")), edited_list) == 0) {
      log_debug2(ZONE, LOGT_EXECFLOW, "The edited list was in use by us. Updating used list.");
      if (list_items > 0) {
          mod_privacy_activate_named(m->si, m->s, edited_list);
      } else {
          mod_privacy_no_active_list(m->si, m->s);
      }
    }

    /* send push to all resources */
    mod_privacy_send_notify_new_list(m->user, edited_list);

    /* send result */
    jutil_iqresult(m->packet->x);
    jpacket_reset(m->packet);
    js_session_to(m->s, m->packet);
    xmlnode_free(previous_lists);
    return M_HANDLED;
}


Generated by  Doxygen 1.6.0   Back to index