/*
    Generated by sbus code generator

    Copyright (C) 2017 Red Hat

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <errno.h>
#include <talloc.h>
#include <tevent.h>
#include <dbus/dbus.h>

#include "sbus/sbus_private.h"
#include "sbus/interface/sbus_iterator_readers.h"
#include "sbus/interface_dbus/sbus_dbus_client_async.h"
#include "sbus/interface_dbus/sbus_dbus_arguments.h"
#include "sbus/interface_dbus/sbus_dbus_keygens.h"
#include "sbus/interface_dbus/sbus_dbus_client_properties.h"

struct sbus_method_in__out_s_state {
    struct _sbus_dbus_invoker_args_s *out;
};

static void sbus_method_in__out_s_done(struct tevent_req *subreq);

static struct tevent_req *
sbus_method_in__out_s_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     sbus_invoker_keygen keygen,
     const char *bus,
     const char *path,
     const char *iface,
     const char *method)
{
    struct sbus_method_in__out_s_state *state;
    struct tevent_req *subreq;
    struct tevent_req *req;
    errno_t ret;

    req = tevent_req_create(mem_ctx, &state, struct sbus_method_in__out_s_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
        return NULL;
    }

    state->out = talloc_zero(state, struct _sbus_dbus_invoker_args_s);
    if (state->out == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Unable to allocate space for output parameters!\n");
        ret = ENOMEM;
        goto done;
    }


    subreq = sbus_call_method_send(state, conn, NULL, keygen, NULL,
                                   bus, path, iface, method, NULL);
    if (subreq == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
        ret = ENOMEM;
        goto done;
    }

    tevent_req_set_callback(subreq, sbus_method_in__out_s_done, req);

    ret = EAGAIN;

done:
    if (ret != EAGAIN) {
        tevent_req_error(req, ret);
        tevent_req_post(req, conn->ev);
    }

    return req;
}

static void sbus_method_in__out_s_done(struct tevent_req *subreq)
{
    struct sbus_method_in__out_s_state *state;
    struct tevent_req *req;
    DBusMessage *reply;
    errno_t ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sbus_method_in__out_s_state);

    ret = sbus_call_method_recv(state, subreq, &reply);
    talloc_zfree(subreq);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    ret = sbus_read_output(state->out, reply, (sbus_invoker_reader_fn)_sbus_dbus_invoker_read_s, state->out);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    tevent_req_done(req);
    return;
}

static errno_t
sbus_method_in__out_s_recv
    (TALLOC_CTX *mem_ctx,
     struct tevent_req *req,
     const char ** _arg0)
{
    struct sbus_method_in__out_s_state *state;
    state = tevent_req_data(req, struct sbus_method_in__out_s_state);

    TEVENT_REQ_RETURN_ON_ERROR(req);

    *_arg0 = talloc_steal(mem_ctx, state->out->arg0);

    return EOK;
}

struct sbus_method_in_raw_out__state {
    int dummy;
};

static void sbus_method_in_raw_out__done(struct tevent_req *subreq);

static struct tevent_req *
sbus_method_in_raw_out__send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     DBusMessage *raw_message)
{
    struct sbus_method_in_raw_out__state *state;
    struct tevent_req *subreq;
    struct tevent_req *req;
    errno_t ret;

    req = tevent_req_create(mem_ctx, &state, struct sbus_method_in_raw_out__state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
        return NULL;
    }


    subreq = sbus_call_method_send(state, conn, raw_message, NULL, NULL, NULL,
                                   dbus_message_get_path(raw_message),
                                   dbus_message_get_interface(raw_message),
                                   dbus_message_get_member(raw_message), NULL);
    if (subreq == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
        ret = ENOMEM;
        goto done;
    }

    tevent_req_set_callback(subreq, sbus_method_in_raw_out__done, req);

    ret = EAGAIN;

done:
    if (ret != EAGAIN) {
        tevent_req_error(req, ret);
        tevent_req_post(req, conn->ev);
    }

    return req;
}

static void sbus_method_in_raw_out__done(struct tevent_req *subreq)
{
    struct sbus_method_in_raw_out__state *state;
    struct tevent_req *req;
    DBusMessage *reply;
    errno_t ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sbus_method_in_raw_out__state);

    ret = sbus_call_method_recv(state, subreq, &reply);
    talloc_zfree(subreq);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    tevent_req_done(req);
    return;
}

static errno_t
sbus_method_in_raw_out__recv
    (struct tevent_req *req)
{
    TEVENT_REQ_RETURN_ON_ERROR(req);

    return EOK;
}

struct sbus_method_in_s_out_raw_state {
    struct _sbus_dbus_invoker_args_s in;
    DBusMessage *reply;
};

static void sbus_method_in_s_out_raw_done(struct tevent_req *subreq);

static struct tevent_req *
sbus_method_in_s_out_raw_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     sbus_invoker_keygen keygen,
     const char *bus,
     const char *path,
     const char *iface,
     const char *method,
     const char * arg0)
{
    struct sbus_method_in_s_out_raw_state *state;
    struct tevent_req *subreq;
    struct tevent_req *req;
    errno_t ret;

    req = tevent_req_create(mem_ctx, &state, struct sbus_method_in_s_out_raw_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
        return NULL;
    }

    state->in.arg0 = arg0;

    subreq = sbus_call_method_send(state, conn, NULL, keygen,
                                   (sbus_invoker_writer_fn)_sbus_dbus_invoker_write_s,
                                   bus, path, iface, method, &state->in);
    if (subreq == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
        ret = ENOMEM;
        goto done;
    }

    tevent_req_set_callback(subreq, sbus_method_in_s_out_raw_done, req);

    ret = EAGAIN;

done:
    if (ret != EAGAIN) {
        tevent_req_error(req, ret);
        tevent_req_post(req, conn->ev);
    }

    return req;
}

static void sbus_method_in_s_out_raw_done(struct tevent_req *subreq)
{
    struct sbus_method_in_s_out_raw_state *state;
    struct tevent_req *req;
    DBusMessage *reply;
    errno_t ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sbus_method_in_s_out_raw_state);

    ret = sbus_call_method_recv(state, subreq, &reply);
    talloc_zfree(subreq);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    state->reply = reply;

    tevent_req_done(req);
    return;
}

static errno_t
sbus_method_in_s_out_raw_recv
    (TALLOC_CTX *mem_ctx,
     struct tevent_req *req,
     DBusMessage **_reply)
{
    errno_t ret;
    struct sbus_method_in_s_out_raw_state *state;
    state = tevent_req_data(req, struct sbus_method_in_s_out_raw_state);

    TEVENT_REQ_RETURN_ON_ERROR(req);

    /* Bounded reference cannot be unreferenced with dbus_message_unref.
     * For that reason we do not allow NULL memory context as it would
     * result in leaking the message memory. */
    if (mem_ctx == NULL) {
        return EINVAL;
    }

    ret = sbus_message_bound_steal(mem_ctx, state->reply);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
              ret, sss_strerror(ret));
        return ret;
    }

    *_reply = state->reply;

    return EOK;
}

struct sbus_method_in_s_out_u_state {
    struct _sbus_dbus_invoker_args_s in;
    struct _sbus_dbus_invoker_args_u *out;
};

static void sbus_method_in_s_out_u_done(struct tevent_req *subreq);

static struct tevent_req *
sbus_method_in_s_out_u_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     sbus_invoker_keygen keygen,
     const char *bus,
     const char *path,
     const char *iface,
     const char *method,
     const char * arg0)
{
    struct sbus_method_in_s_out_u_state *state;
    struct tevent_req *subreq;
    struct tevent_req *req;
    errno_t ret;

    req = tevent_req_create(mem_ctx, &state, struct sbus_method_in_s_out_u_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
        return NULL;
    }

    state->out = talloc_zero(state, struct _sbus_dbus_invoker_args_u);
    if (state->out == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Unable to allocate space for output parameters!\n");
        ret = ENOMEM;
        goto done;
    }

    state->in.arg0 = arg0;

    subreq = sbus_call_method_send(state, conn, NULL, keygen,
                                   (sbus_invoker_writer_fn)_sbus_dbus_invoker_write_s,
                                   bus, path, iface, method, &state->in);
    if (subreq == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
        ret = ENOMEM;
        goto done;
    }

    tevent_req_set_callback(subreq, sbus_method_in_s_out_u_done, req);

    ret = EAGAIN;

done:
    if (ret != EAGAIN) {
        tevent_req_error(req, ret);
        tevent_req_post(req, conn->ev);
    }

    return req;
}

static void sbus_method_in_s_out_u_done(struct tevent_req *subreq)
{
    struct sbus_method_in_s_out_u_state *state;
    struct tevent_req *req;
    DBusMessage *reply;
    errno_t ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sbus_method_in_s_out_u_state);

    ret = sbus_call_method_recv(state, subreq, &reply);
    talloc_zfree(subreq);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    ret = sbus_read_output(state->out, reply, (sbus_invoker_reader_fn)_sbus_dbus_invoker_read_u, state->out);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    tevent_req_done(req);
    return;
}

static errno_t
sbus_method_in_s_out_u_recv
    (struct tevent_req *req,
     uint32_t* _arg0)
{
    struct sbus_method_in_s_out_u_state *state;
    state = tevent_req_data(req, struct sbus_method_in_s_out_u_state);

    TEVENT_REQ_RETURN_ON_ERROR(req);

    *_arg0 = state->out->arg0;

    return EOK;
}

struct sbus_method_in_ss_out_raw_state {
    struct _sbus_dbus_invoker_args_ss in;
    DBusMessage *reply;
};

static void sbus_method_in_ss_out_raw_done(struct tevent_req *subreq);

static struct tevent_req *
sbus_method_in_ss_out_raw_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     sbus_invoker_keygen keygen,
     const char *bus,
     const char *path,
     const char *iface,
     const char *method,
     const char * arg0,
     const char * arg1)
{
    struct sbus_method_in_ss_out_raw_state *state;
    struct tevent_req *subreq;
    struct tevent_req *req;
    errno_t ret;

    req = tevent_req_create(mem_ctx, &state, struct sbus_method_in_ss_out_raw_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
        return NULL;
    }

    state->in.arg0 = arg0;
    state->in.arg1 = arg1;

    subreq = sbus_call_method_send(state, conn, NULL, keygen,
                                   (sbus_invoker_writer_fn)_sbus_dbus_invoker_write_ss,
                                   bus, path, iface, method, &state->in);
    if (subreq == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
        ret = ENOMEM;
        goto done;
    }

    tevent_req_set_callback(subreq, sbus_method_in_ss_out_raw_done, req);

    ret = EAGAIN;

done:
    if (ret != EAGAIN) {
        tevent_req_error(req, ret);
        tevent_req_post(req, conn->ev);
    }

    return req;
}

static void sbus_method_in_ss_out_raw_done(struct tevent_req *subreq)
{
    struct sbus_method_in_ss_out_raw_state *state;
    struct tevent_req *req;
    DBusMessage *reply;
    errno_t ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sbus_method_in_ss_out_raw_state);

    ret = sbus_call_method_recv(state, subreq, &reply);
    talloc_zfree(subreq);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    state->reply = reply;

    tevent_req_done(req);
    return;
}

static errno_t
sbus_method_in_ss_out_raw_recv
    (TALLOC_CTX *mem_ctx,
     struct tevent_req *req,
     DBusMessage **_reply)
{
    errno_t ret;
    struct sbus_method_in_ss_out_raw_state *state;
    state = tevent_req_data(req, struct sbus_method_in_ss_out_raw_state);

    TEVENT_REQ_RETURN_ON_ERROR(req);

    /* Bounded reference cannot be unreferenced with dbus_message_unref.
     * For that reason we do not allow NULL memory context as it would
     * result in leaking the message memory. */
    if (mem_ctx == NULL) {
        return EINVAL;
    }

    ret = sbus_message_bound_steal(mem_ctx, state->reply);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to steal message [%d]: %s\n",
              ret, sss_strerror(ret));
        return ret;
    }

    *_reply = state->reply;

    return EOK;
}

struct sbus_method_in_su_out_u_state {
    struct _sbus_dbus_invoker_args_su in;
    struct _sbus_dbus_invoker_args_u *out;
};

static void sbus_method_in_su_out_u_done(struct tevent_req *subreq);

static struct tevent_req *
sbus_method_in_su_out_u_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     sbus_invoker_keygen keygen,
     const char *bus,
     const char *path,
     const char *iface,
     const char *method,
     const char * arg0,
     uint32_t arg1)
{
    struct sbus_method_in_su_out_u_state *state;
    struct tevent_req *subreq;
    struct tevent_req *req;
    errno_t ret;

    req = tevent_req_create(mem_ctx, &state, struct sbus_method_in_su_out_u_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
        return NULL;
    }

    state->out = talloc_zero(state, struct _sbus_dbus_invoker_args_u);
    if (state->out == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Unable to allocate space for output parameters!\n");
        ret = ENOMEM;
        goto done;
    }

    state->in.arg0 = arg0;
    state->in.arg1 = arg1;

    subreq = sbus_call_method_send(state, conn, NULL, keygen,
                                   (sbus_invoker_writer_fn)_sbus_dbus_invoker_write_su,
                                   bus, path, iface, method, &state->in);
    if (subreq == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
        ret = ENOMEM;
        goto done;
    }

    tevent_req_set_callback(subreq, sbus_method_in_su_out_u_done, req);

    ret = EAGAIN;

done:
    if (ret != EAGAIN) {
        tevent_req_error(req, ret);
        tevent_req_post(req, conn->ev);
    }

    return req;
}

static void sbus_method_in_su_out_u_done(struct tevent_req *subreq)
{
    struct sbus_method_in_su_out_u_state *state;
    struct tevent_req *req;
    DBusMessage *reply;
    errno_t ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sbus_method_in_su_out_u_state);

    ret = sbus_call_method_recv(state, subreq, &reply);
    talloc_zfree(subreq);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    ret = sbus_read_output(state->out, reply, (sbus_invoker_reader_fn)_sbus_dbus_invoker_read_u, state->out);
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    tevent_req_done(req);
    return;
}

static errno_t
sbus_method_in_su_out_u_recv
    (struct tevent_req *req,
     uint32_t* _arg0)
{
    struct sbus_method_in_su_out_u_state *state;
    state = tevent_req_data(req, struct sbus_method_in_su_out_u_state);

    TEVENT_REQ_RETURN_ON_ERROR(req);

    *_arg0 = state->out->arg0;

    return EOK;
}

struct tevent_req *
sbus_call_DBus_GetConnectionUnixUser_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     const char *busname,
     const char *object_path,
     const char * arg_name)
{
    return sbus_method_in_s_out_u_send(mem_ctx, conn, _sbus_dbus_key_s_0,
        busname, object_path, "org.freedesktop.DBus", "GetConnectionUnixUser", arg_name);
}

errno_t
sbus_call_DBus_GetConnectionUnixUser_recv
    (struct tevent_req *req,
     uint32_t* _uid)
{
    return sbus_method_in_s_out_u_recv(req, _uid);
}

struct tevent_req *
sbus_call_DBus_Hello_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     const char *busname,
     const char *object_path)
{
    return sbus_method_in__out_s_send(mem_ctx, conn, NULL,
        busname, object_path, "org.freedesktop.DBus", "Hello");
}

errno_t
sbus_call_DBus_Hello_recv
    (TALLOC_CTX *mem_ctx,
     struct tevent_req *req,
     const char ** _name)
{
    return sbus_method_in__out_s_recv(mem_ctx, req, _name);
}

struct tevent_req *
sbus_call_DBus_RequestName_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     const char *busname,
     const char *object_path,
     const char * arg_name,
     uint32_t arg_flags)
{
    return sbus_method_in_su_out_u_send(mem_ctx, conn, NULL,
        busname, object_path, "org.freedesktop.DBus", "RequestName", arg_name, arg_flags);
}

errno_t
sbus_call_DBus_RequestName_recv
    (struct tevent_req *req,
     uint32_t* _result)
{
    return sbus_method_in_su_out_u_recv(req, _result);
}

struct tevent_req *
sbus_call_DBusProperties_Get_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     const char *busname,
     const char *object_path,
     const char * arg_interface_name,
     const char * arg_property_name)
{
    return sbus_method_in_ss_out_raw_send(mem_ctx, conn, _sbus_dbus_key_ss_0_1,
        busname, object_path, "org.freedesktop.DBus.Properties", "Get", arg_interface_name, arg_property_name);
}

errno_t
sbus_call_DBusProperties_Get_recv
    (TALLOC_CTX *mem_ctx,
     struct tevent_req *req,
     DBusMessage **_reply)
{
    return sbus_method_in_ss_out_raw_recv(mem_ctx, req, _reply);
}

struct tevent_req *
sbus_call_DBusProperties_GetAll_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     const char *busname,
     const char *object_path,
     const char * arg_interface_name)
{
    return sbus_method_in_s_out_raw_send(mem_ctx, conn, _sbus_dbus_key_s_0,
        busname, object_path, "org.freedesktop.DBus.Properties", "GetAll", arg_interface_name);
}

errno_t
sbus_call_DBusProperties_GetAll_recv
    (TALLOC_CTX *mem_ctx,
     struct tevent_req *req,
     DBusMessage **_reply)
{
    return sbus_method_in_s_out_raw_recv(mem_ctx, req, _reply);
}

struct tevent_req *
sbus_call_DBusProperties_Set_send
    (TALLOC_CTX *mem_ctx,
     struct sbus_connection *conn,
     DBusMessage *raw_message)
{
    return sbus_method_in_raw_out__send(mem_ctx, conn, raw_message);
}

errno_t
sbus_call_DBusProperties_Set_recv
    (struct tevent_req *req)
{
    return sbus_method_in_raw_out__recv(req);
}
