summaryrefslogtreecommitdiff
path: root/libgupnp/gupnp-service-proxy-action-private.h
blob: e2a3dca50a086d7be64d41186da0554e80060113 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * Copyright (C) 2018,2019 The GUPnP maintainers.
 *
 * Author: Jens Georg <mail@jensge.org>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#ifndef GUPNP_SERVICE_PROXY_ACTION_H
#define GUPNP_SERVICE_PROXY_ACTION_H

#include <gobject/gvaluecollector.h>
#include <libxml/tree.h>

G_BEGIN_DECLS

/* Initializes hash table to hold arg names as keys and GValues of
 * given type and value.
 */
#define VAR_ARGS_TO_IN_LIST(var_args, names, values) \
        G_STMT_START { \
                const gchar *arg_name = va_arg (var_args, const gchar *); \
         \
                while (arg_name != NULL) { \
                        GValue *value = g_new0 (GValue, 1); \
                        gchar *__error = NULL; \
                        GType type = va_arg (var_args, GType); \
         \
                        G_VALUE_COLLECT_INIT (value, \
                                              type, \
                                              var_args, \
                                              G_VALUE_NOCOPY_CONTENTS, \
                                              &__error); \
                        if (__error == NULL) { \
                                names = g_list_prepend (names, g_strdup (arg_name)); \
                                values = g_list_prepend (values, value); \
                        } else { \
                                g_warning ("Failed to collect value of type %s for %s: %s", \
                                           g_type_name (type), \
                                           arg_name, \
                                           __error); \
                                g_free (__error); \
                        } \
                        arg_name = va_arg (var_args, const gchar *); \
                } \
                names = g_list_reverse (names); \
                values = g_list_reverse (values); \
        } G_STMT_END

/* This is a skip variant of G_VALUE_LCOPY, same as there is
 * G_VALUE_COLLECT_SKIP for G_VALUE_COLLECT.
 */
#define VALUE_LCOPY_SKIP(value_type, var_args) \
        G_STMT_START { \
                GTypeValueTable *_vtable = g_type_value_table_peek (value_type); \
                const gchar *_lcopy_format = _vtable->lcopy_format; \
         \
                while (*_lcopy_format) { \
                        switch (*_lcopy_format++) { \
                        case G_VALUE_COLLECT_INT: \
                                va_arg ((var_args), gint); \
                                break; \
                        case G_VALUE_COLLECT_LONG: \
                                va_arg ((var_args), glong); \
                                break; \
                        case G_VALUE_COLLECT_INT64: \
                                va_arg ((var_args), gint64); \
                                break; \
                        case G_VALUE_COLLECT_DOUBLE: \
                                va_arg ((var_args), gdouble); \
                                break; \
                        case G_VALUE_COLLECT_POINTER: \
                                va_arg ((var_args), gpointer); \
                                break; \
                        default: \
                                g_assert_not_reached (); \
                        } \
                } \
        } G_STMT_END

/* Initializes hash table to hold arg names as keys and GValues of
 * given type, but without any specific value. Note that if you are
 * going to use OUT_HASH_TABLE_TO_VAR_ARGS then you have to store a
 * copy of var_args with G_VA_COPY before using this macro.
 */
#define VAR_ARGS_TO_OUT_HASH_TABLE(var_args, hash) \
        G_STMT_START { \
                const gchar *arg_name = va_arg (var_args, const gchar *); \
         \
                while (arg_name != NULL) { \
                        GValue *value = g_new0 (GValue, 1); \
                        GType type = va_arg (var_args, GType); \
         \
                        VALUE_LCOPY_SKIP (type, var_args); \
                        g_value_init (value, type); \
                        g_hash_table_insert (hash, g_strdup (arg_name), value); \
                        arg_name = va_arg (var_args, const gchar *); \
                } \
        } G_STMT_END

/* Puts values stored in hash table with GValues into var args.
 */
#define OUT_HASH_TABLE_TO_VAR_ARGS(hash, var_args) \
        G_STMT_START { \
                const gchar *arg_name = va_arg (var_args, const gchar *); \
         \
                while (arg_name != NULL) { \
                        GValue *value = g_hash_table_lookup (hash, arg_name); \
                        GType type = va_arg (var_args, GType); \
         \
                        if (value == NULL) { \
                                g_warning ("No value for %s", arg_name); \
                                G_VALUE_COLLECT_SKIP (type, var_args); \
                        } else if (G_VALUE_TYPE (value) != type) { \
                                g_warning ("Different GType in value (%s) and in var args (%s) for %s.", \
                                           G_VALUE_TYPE_NAME (value), \
                                           g_type_name (type), \
                                           arg_name); \
                        } else { \
                                gchar *__error = NULL; \
         \
                                G_VALUE_LCOPY (value, var_args, 0, &__error); \
                                if (__error != NULL) { \
                                        g_warning ("Failed to lcopy the value of type %s for %s: %s", \
                                                   g_type_name (type), \
                                                   arg_name, \
                                                   __error); \
                                        g_free (__error); \
                                } \
                        } \
                        arg_name = va_arg (var_args, const gchar *); \
                } \
        } G_STMT_END

struct _GUPnPServiceProxyAction {
        GUPnPServiceProxy *proxy;
        char *name;
        gint header_pos;

        SoupMessage *msg;
        GBytes *response;
        GString *msg_str;

        gulong cancellable_connection_id;

        gpointer user_data;
        GError *error; /* If non-NULL, description of error that
                          occurred when preparing message */

        GPtrArray *args;
        GHashTable *arg_map;
        gboolean pending;
        xmlDocPtr doc;
        xmlNodePtr params;
};

G_GNUC_INTERNAL GUPnPServiceProxyAction *
gupnp_service_proxy_action_new_internal (const char *action);

G_GNUC_INTERNAL gboolean
gupnp_service_proxy_action_get_result_valist (GUPnPServiceProxyAction *action,
                                              GError                 **error,
                                              va_list                  var_args);

G_GNUC_INTERNAL void
gupnp_service_proxy_action_serialize (GUPnPServiceProxyAction *action,
                                      const char *service_type);

G_GNUC_INTERNAL void
gupnp_service_proxy_action_check_response (GUPnPServiceProxyAction *action);
G_END_DECLS

#endif /* GUPNP_SERVICE_PROXY_ACTION_H */