/**
 * @internal
 * wrapper
 */
static int
_mfd_usmDHUserKeyTable_post_request(netsnmp_mib_handler *handler,
                                    netsnmp_handler_registration *reginfo,
                                    netsnmp_agent_request_info
                                    *agtreq_info,
                                    netsnmp_request_info *requests)
{
    usmDHUserKeyTable_rowreq_ctx *rowreq_ctx =
        netsnmp_container_table_row_extract(requests);
    int             rc, packet_rc;

    DEBUGMSGTL(("internal:usmDHUserKeyTable:_mfd_usmDHUserKeyTable_post_request", "called\n"));

    /*
     * release row context, if deleted
     */
    if (rowreq_ctx && (rowreq_ctx->rowreq_flags & MFD_ROW_DELETED))
        usmDHUserKeyTable_release_rowreq_ctx(rowreq_ctx);

    /*
     * wait for last call before calling user
     */
    if (1 != netsnmp_row_merge_status_last(reginfo, agtreq_info)) {
        DEBUGMSGTL(("internal:usmDHUserKeyTable",
                    "waiting for last post_request\n"));
        return SNMP_ERR_NOERROR;
    }

    packet_rc = netsnmp_check_all_requests_error(agtreq_info->asp, 0);
    if ((MFD_SUCCESS != packet_rc) && usmDHUserKeyTable_dirty_get()) {
        /*
         * we shouldn't get here. the undo steps should also clear
         * the dirty flags.
         */
        snmp_log(LOG_WARNING,
                 "usmDHUserKeyTable dirty flag set in post_request "
                 "but status != SUCCESS.\n");
    }

    rc = usmDHUserKeyTable_post_request(usmDHUserKeyTable_if_ctx.user_ctx,
                                        packet_rc);
    if (MFD_SUCCESS != rc) {
        /*
         * nothing we can do about it but log it
         */
        DEBUGMSGTL(("usmDHUserKeyTable", "error %d from "
                    "usmDHUserKeyTable_post_request\n", rc));
    }

    return SNMP_ERR_NOERROR;
}                               /* _mfd_usmDHUserKeyTable_post_request */
/*
 *********************************************************************
 * @internal
 * allocate resources for a usmDHUserKeyTable_rowreq_ctx
 */
usmDHUserKeyTable_rowreq_ctx *
usmDHUserKeyTable_allocate_rowreq_ctx(usmDHUserKeyTable_data * data,
                                      void *user_init_ctx)
{
    usmDHUserKeyTable_rowreq_ctx *rowreq_ctx =
        SNMP_MALLOC_TYPEDEF(usmDHUserKeyTable_rowreq_ctx);

    DEBUGMSGTL(("internal:usmDHUserKeyTable:usmDHUserKeyTable_allocate_rowreq_ctx", "called\n"));

    if (NULL == rowreq_ctx) {
        snmp_log(LOG_ERR, "Couldn't allocate memory for a "
                 "usmDHUserKeyTable_rowreq_ctx.\n");
        return NULL;
    } else {
        if (NULL != data) {
            /*
             * track if we got data from user
             */
            rowreq_ctx->rowreq_flags |= MFD_ROW_DATA_FROM_USER;
            rowreq_ctx->data = data;
        } else if (NULL ==
                   (rowreq_ctx->data =
                    usmDHUserKeyTable_allocate_data())) {
            SNMP_FREE(rowreq_ctx);
            return NULL;
        }
    }

    /*
     * undo context will be allocated when needed (in *_undo_setup)
     */

    rowreq_ctx->oid_idx.oids = rowreq_ctx->oid_tmp;

    rowreq_ctx->usmDHUserKeyTable_data_list = NULL;

    /*
     * if we allocated data, call init routine
     */
    if (!(rowreq_ctx->rowreq_flags & MFD_ROW_DATA_FROM_USER)) {
        if (SNMPERR_SUCCESS !=
            usmDHUserKeyTable_rowreq_ctx_init(rowreq_ctx, user_init_ctx)) {
            usmDHUserKeyTable_release_rowreq_ctx(rowreq_ctx);
            rowreq_ctx = NULL;
        }
    }

    return rowreq_ctx;
}                               /* usmDHUserKeyTable_allocate_rowreq_ctx */
/**
 * load initial data
 *
 * TODO:350:M: Implement usmDHUserKeyTable data load
 * This function will also be called by the cache helper to load
 * the container again (after the container free function has been
 * called to free the previous contents).
 *
 * @param container container to which items should be inserted
 *
 * @retval MFD_SUCCESS              : success.
 * @retval MFD_RESOURCE_UNAVAILABLE : Can't access data source
 * @retval MFD_ERROR                : other error.
 *
 *  This function is called to load the index(es) (and data, optionally)
 *  for the every row in the data set.
 *
 * @remark
 *  While loading the data, the only important thing is the indexes.
 *  If access to your data is cheap/fast (e.g. you have a pointer to a
 *  structure in memory), it would make sense to update the data here.
 *  If, however, the accessing the data invovles more work (e.g. parsing
 *  some other existing data, or peforming calculations to derive the data),
 *  then you can limit yourself to setting the indexes and saving any
 *  information you will need later. Then use the saved information in
 *  usmDHUserKeyTable_row_prep() for populating data.
 *
 * @note
 *  If you need consistency between rows (like you want statistics
 *  for each row to be from the same time frame), you should set all
 *  data here.
 *
 */
int
usmDHUserKeyTable_container_load(netsnmp_container * container)
{
    usmDHUserKeyTable_rowreq_ctx *rowreq_ctx;
    struct usmUser *usmuser;
    size_t          count = 0;

    DEBUGMSGTL(("verbose:usmDHUserKeyTable:usmDHUserKeyTable_container_load", "called\n"));

    /*
     * TODO:351:M: |-> Load/update data in the usmDHUserKeyTable container.
     * loop over your usmDHUserKeyTable data, allocate a rowreq context,
     * set the index(es) [and data, optionally] and insert into
     * the container.
     */
          /*
     * Retrieve the first user from the USM DB
           */
    usmuser = usm_get_userList();
    if (NULL == usmuser) {
        return MFD_SUCCESS;
    }
  
    for (; usmuser; usmuser = usmuser->next) {

        /*
         * TODO:352:M: |   |-> set indexes in new usmDHUserKeyTable rowreq context.
         * data context will be set from the first param (unless NULL,
         *      in which case a new data context will be allocated)
         * the second param will be passed, with the row context, to
         *      usmDHUserKeyTablerowreq_ctx_init.
         */
        rowreq_ctx = usmDHUserKeyTable_allocate_rowreq_ctx(usmuser, NULL);
        if (NULL == rowreq_ctx) {
            snmp_log(LOG_ERR, "memory allocation failed\n");
            return MFD_RESOURCE_UNAVAILABLE;
        }
        if (MFD_SUCCESS !=
            usmDHUserKeyTable_indexes_set(rowreq_ctx,
                                          usmuser->engineID,
                                          usmuser->engineIDLen,
                                          usmuser->name,
                                          strlen(usmuser->name))) {
            snmp_log(LOG_ERR,
                     "error setting index while loading "
                     "usmDHUserKeyTable data.\n");
            usmDHUserKeyTable_release_rowreq_ctx(rowreq_ctx);
            continue;
        }

        /*
         * TODO:352:r: |   |-> populate usmDHUserKeyTable data context.
         * Populate data context here. (optionally, delay until row prep)
         */
        /*
         * non-TRANSIENT data: no need to copy. set pointer to data 
         */

        /*
         * insert into table container
         */
        CONTAINER_INSERT(container, rowreq_ctx);
        ++count;
    }

    DEBUGMSGT(("verbose:usmDHUserKeyTable:usmDHUserKeyTable_container_load", "inserted %d records\n", (int)count));

    return MFD_SUCCESS;
}                               /* usmDHUserKeyTable_container_load */