send_specific_attrs(Slapi_Entry *e, char **attrs, Slapi_Operation *op, Slapi_PBlock *pb, BerElement *ber, int attrsonly, int ldapversion __attribute__((unused)), int real_attrs_only)
{
    int i = 0;
    int rc = 0;
    int vattr_flags = 0;
    vattr_context *ctx;
    char **attrs_ext = NULL;
    char **my_searchattrs = NULL;

    if (real_attrs_only == SLAPI_SEND_VATTR_FLAG_REALONLY) {
        vattr_flags = SLAPI_REALATTRS_ONLY;
    } else {
        vattr_flags = SLAPI_VIRTUALATTRS_REQUEST_POINTERS;
        if (real_attrs_only == SLAPI_SEND_VATTR_FLAG_VIRTUALONLY)
            vattr_flags |= SLAPI_VIRTUALATTRS_ONLY;
    }

    /* Create a copy of attrs with no duplicates */
    if (attrs) {
        for (i = 0; attrs[i]; i++) {
            if (!charray_inlist(attrs_ext, attrs[i])) {
                slapi_ch_array_add(&attrs_ext, slapi_ch_strdup(attrs[i]));
                slapi_ch_array_add(&my_searchattrs, slapi_ch_strdup(op->o_searchattrs[i]));
            }
        }
    }
    if (attrs_ext) {
        attrs = attrs_ext;
    }

    for (i = 0; my_searchattrs && attrs && attrs[i] != NULL; i++) {
        char *current_type_name = attrs[i];
        Slapi_ValueSet **values = NULL;
        int attr_free_flags = 0;
        char *name_to_return = NULL;
        char **actual_type_name = NULL;
        int *type_name_disposition = 0;
        int item_count = 0;
        int iter = 0;
        Slapi_DN *namespace_dn;
        Slapi_Backend *be = 0;

        /*
         * Here we call the computed attribute code to see whether
         * the requested attribute is to be computed.
         * The subroutine compute_attribute calls encode_attr on our behalf, in order
         * to avoid the inefficiency of returning a complex structure
         * which we'd have to free
         */
        rc = compute_attribute(attrs[i], pb, ber, e, attrsonly, my_searchattrs[i]);
        if (0 == rc) {
            continue; /* Means this was a computed attr and we prcessed it OK. */
        }
        if (-1 != rc) {
            /* Means that some error happened */
            return rc;
        } else {
            rc = 0; /* Means that we just didn't recognize this as a computed attr */
        }

        /* get the namespace dn */
        slapi_pblock_get(pb, SLAPI_BACKEND, (void *)&be);
        namespace_dn = (Slapi_DN *)slapi_be_getsuffix(be, 0);

        /* Get the attribute value from the vattr service */
        /* This call handles subtype, as well.
         * e.g., current_type_name: cn
         * ==>
         * item_count: 5; actual_type_name: cn;sub0, ..., cn;sub4 */
        /* ctx will be freed by attr_context_ungrok() */
        ctx = vattr_context_new(pb);
        rc = slapi_vattr_namespace_values_get_sp(
            ctx,
            e,
            namespace_dn,
            current_type_name,
            &values,
            &type_name_disposition,
            &actual_type_name,
            vattr_flags,
            &attr_free_flags,
            &item_count);
        if ((0 == rc) && (item_count > 0)) {
            for (iter = 0; iter < item_count; iter++) {
                if (rc != 0) {
                    /* we hit an error - we need to free all of the stuff allocated by
                       slapi_vattr_namespace_values_get_sp */
                    slapi_vattr_values_free(&(values[iter]), &(actual_type_name[iter]), attr_free_flags);
                    continue;
                }
                if (SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE == type_name_disposition[iter]) {
                    name_to_return = actual_type_name[iter];
                    if ((iter > 0) && charray_inlist(attrs, name_to_return)) {
                        /* subtype retrieved by slapi_vattr_namespace_values_get_sp is
                         * included in the attr list.  Skip the dup. */
                        continue;
                    }
                } else {
                    name_to_return = my_searchattrs[i];
                }

                /* need to pass actual_type_name (e.g., sn;en to evaluate the ACL */
                rc = encode_attr_2(pb, ber, e, values[iter], attrsonly,
                                   actual_type_name[iter], name_to_return);
                slapi_vattr_values_free(&(values[iter]), &(actual_type_name[iter]), attr_free_flags);
            }

            slapi_ch_free((void **)&actual_type_name);
            slapi_ch_free((void **)&type_name_disposition);
            slapi_ch_free((void **)&values);
            if (rc != 0) {
                goto exit;
            }

        } else {
            /* if we got here, then either values is NULL or values contains no elements
               either way we can free it */
            slapi_ch_free((void **)&values);
            slapi_ch_free((void **)&actual_type_name);
            slapi_ch_free((void **)&type_name_disposition);
            rc = 0;
        }
    }
exit:
    slapi_ch_array_free(attrs_ext);
    slapi_ch_array_free(my_searchattrs);
    return rc;
}
send_specific_attrs(Slapi_Entry *e, char **attrs, Slapi_Operation *op, Slapi_PBlock *pb, BerElement *ber, int attrsonly, int ldapversion __attribute__((unused)), int real_attrs_only)
{
    int i = 0;
    int rc = 0;
    int vattr_flags = 0;
    vattr_context *ctx;
    char **attrs_ext = NULL;
    char **my_searchattrs = NULL;

    if (real_attrs_only == SLAPI_SEND_VATTR_FLAG_REALONLY) {
        vattr_flags = SLAPI_REALATTRS_ONLY;
    } else {
        vattr_flags = SLAPI_VIRTUALATTRS_REQUEST_POINTERS;
        if (real_attrs_only == SLAPI_SEND_VATTR_FLAG_VIRTUALONLY)
            vattr_flags |= SLAPI_VIRTUALATTRS_ONLY;
    }

     
    if (attrs) {
        for (i = 0; attrs[i]; i++) {
            if (!charray_inlist(attrs_ext, attrs[i])) {
                slapi_ch_array_add(&attrs_ext, slapi_ch_strdup(attrs[i]));
                slapi_ch_array_add(&my_searchattrs, slapi_ch_strdup(op->o_searchattrs[i]));
            }
        }
    }
    if (attrs_ext) {
        attrs = attrs_ext;
    }

    for (i = 0; my_searchattrs && attrs && attrs[i] != NULL; i++) {
        char *current_type_name = attrs[i];
        Slapi_ValueSet **values = NULL;
        int attr_free_flags = 0;
        char *name_to_return = NULL;
        char **actual_type_name = NULL;
        int *type_name_disposition = 0;
        int item_count = 0;
        int iter = 0;
        Slapi_DN *namespace_dn;
        Slapi_Backend *be = 0;

         
        rc = compute_attribute(attrs[i], pb, ber, e, attrsonly, my_searchattrs[i]);
        if (0 == rc) {
            continue;  
        }
        if (-1 != rc) {
             
            return rc;
        } else {
            rc = 0;  
        }

         
        slapi_pblock_get(pb, SLAPI_BACKEND, (void *)&be);
        namespace_dn = (Slapi_DN *)slapi_be_getsuffix(be, 0);

         
         
         
        ctx = vattr_context_new(pb);
        rc = slapi_vattr_namespace_values_get_sp(
            ctx,
            e,
            namespace_dn,
            current_type_name,
            &values,
            &type_name_disposition,
            &actual_type_name,
            vattr_flags,
            &attr_free_flags,
            &item_count);
        if ((0 == rc) && (item_count > 0)) {
            for (iter = 0; iter < item_count; iter++) {
                if (rc != 0) {
                     
                    slapi_vattr_values_free(&(values[iter]), &(actual_type_name[iter]), attr_free_flags);
                    continue;
                }
                if (SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE == type_name_disposition[iter]) {
                    name_to_return = actual_type_name[iter];
                    if ((iter > 0) && charray_inlist(attrs, name_to_return)) {
                         
                        continue;
                    }
                } else {
                    name_to_return = my_searchattrs[i];
                }

                 
                rc = encode_attr_2(pb, ber, e, values[iter], attrsonly,
                                   actual_type_name[iter], name_to_return);
                slapi_vattr_values_free(&(values[iter]), &(actual_type_name[iter]), attr_free_flags);
            }

            slapi_ch_free((void **)&actual_type_name);
            slapi_ch_free((void **)&type_name_disposition);
            slapi_ch_free((void **)&values);
            if (rc != 0) {
                goto exit;
            }

        } else {
             
            slapi_ch_free((void **)&values);
            slapi_ch_free((void **)&actual_type_name);
            slapi_ch_free((void **)&type_name_disposition);
            rc = 0;
        }
    }
exit:
    slapi_ch_array_free(attrs_ext);
    slapi_ch_array_free(my_searchattrs);
    return rc;
}