/* * * Connection Manager * * Copyright (C) 2013 Intel Corporation. All rights reserved. * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include "input.h" #include "dbus_helpers.h" #define TIMEOUT 120000 void __connmanctl_dbus_print(DBusMessageIter *iter, const char *pre, const char *dict, const char *sep) { int arg_type; dbus_bool_t b; unsigned char c; dbus_uint16_t u16; dbus_uint32_t u; dbus_int32_t i; double d; char *str; DBusMessageIter entry; if (!pre) pre = ""; while ((arg_type = dbus_message_iter_get_arg_type(iter)) != DBUS_TYPE_INVALID) { fprintf(stdout, "%s", pre); switch (arg_type) { case DBUS_TYPE_STRUCT: fprintf(stdout, "{ "); dbus_message_iter_recurse(iter, &entry); __connmanctl_dbus_print(&entry, "", "=", " "); fprintf(stdout, " }"); break; case DBUS_TYPE_ARRAY: fprintf(stdout, "[ "); dbus_message_iter_recurse(iter, &entry); __connmanctl_dbus_print(&entry, "", "=", ", "); fprintf(stdout, " ]"); break; case DBUS_TYPE_DICT_ENTRY: dbus_message_iter_recurse(iter, &entry); __connmanctl_dbus_print(&entry, "", dict, dict); break; case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: dbus_message_iter_get_basic(iter, &str); fprintf(stdout, "%s", str); break; case DBUS_TYPE_VARIANT: dbus_message_iter_recurse(iter, &entry); __connmanctl_dbus_print(&entry, pre, dict, sep); break; case DBUS_TYPE_BOOLEAN: dbus_message_iter_get_basic(iter, &b); if (!b) fprintf(stdout, "False"); else fprintf(stdout, "True"); break; case DBUS_TYPE_BYTE: dbus_message_iter_get_basic(iter, &c); fprintf(stdout, "%d", c); break; case DBUS_TYPE_UINT16: dbus_message_iter_get_basic(iter, &u16); fprintf(stdout, "%u", u16); break; case DBUS_TYPE_UINT32: dbus_message_iter_get_basic(iter, &u); fprintf(stdout, "%d", u); break; case DBUS_TYPE_INT32: dbus_message_iter_get_basic(iter, &i); fprintf(stdout, "%d", i); break; case DBUS_TYPE_DOUBLE: dbus_message_iter_get_basic(iter, &d); fprintf(stdout, "%f", d); break; default: fprintf(stdout, "", arg_type); break; } if (dbus_message_iter_has_next(iter)) fprintf(stdout, "%s", sep); dbus_message_iter_next(iter); } } struct dbus_callback { connmanctl_dbus_method_return_func_t cb; void *user_data; }; static void dbus_method_reply(DBusPendingCall *call, void *user_data) { struct dbus_callback *callback = user_data; int res = 0; DBusMessage *reply; DBusMessageIter iter; __connmanctl_save_rl(); reply = dbus_pending_call_steal_reply(call); if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { DBusError err; dbus_error_init(&err); dbus_set_error_from_message(&err, reply); callback->cb(NULL, err.message, callback->user_data); dbus_error_free(&err); goto end; } dbus_message_iter_init(reply, &iter); res = callback->cb(&iter, NULL, callback->user_data); end: __connmanctl_redraw_rl(); if (__connmanctl_is_interactive() == false && res != -EINPROGRESS) __connmanctl_quit(); g_free(callback); dbus_message_unref(reply); } static int send_method_call(DBusConnection *connection, DBusMessage *message, connmanctl_dbus_method_return_func_t cb, void *user_data) { int res = -ENXIO; DBusPendingCall *call; struct dbus_callback *callback; if (!dbus_connection_send_with_reply(connection, message, &call, TIMEOUT)) goto end; if (!call) goto end; if (cb) { callback = g_new0(struct dbus_callback, 1); callback->cb = cb; callback->user_data = user_data; dbus_pending_call_set_notify(call, dbus_method_reply, callback, NULL); res = -EINPROGRESS; } end: dbus_message_unref(message); return res; } static int append_variant(DBusMessageIter *iter, const char *property, int type, void *value) { DBusMessageIter variant; char *type_str; switch(type) { case DBUS_TYPE_BOOLEAN: type_str = DBUS_TYPE_BOOLEAN_AS_STRING; break; case DBUS_TYPE_BYTE: type_str = DBUS_TYPE_BYTE_AS_STRING; break; case DBUS_TYPE_STRING: type_str = DBUS_TYPE_STRING_AS_STRING; break; case DBUS_TYPE_INT32: type_str = DBUS_TYPE_INT32_AS_STRING; break; default: return -EOPNOTSUPP; } dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property); dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type_str, &variant); dbus_message_iter_append_basic(&variant, type, value); dbus_message_iter_close_container(iter, &variant); return 0; } int __connmanctl_dbus_method_call(DBusConnection *connection, const char *service, const char *path, const char *interface, const char *method, connmanctl_dbus_method_return_func_t cb, void *user_data, connmanctl_dbus_append_func_t append_func, void *append_data) { DBusMessage *message; DBusMessageIter iter; message = dbus_message_new_method_call(service, path, interface, method); if (!message) return -ENOMEM; if (append_func) { dbus_message_iter_init_append(message, &iter); append_func(&iter, append_data); } return send_method_call(connection, message, cb, user_data); } int __connmanctl_dbus_set_property(DBusConnection *connection, const char *path, const char *interface, connmanctl_dbus_method_return_func_t cb, void * user_data, const char *property, int type, void *value) { DBusMessage *message; DBusMessageIter iter; message = dbus_message_new_method_call("net.connman", path, interface, "SetProperty"); if (!message) return -ENOMEM; dbus_message_iter_init_append(message, &iter); if (append_variant(&iter, property, type, value) < 0) { dbus_message_unref(message); return -EINVAL; } return send_method_call(connection, message, cb, user_data); } void __connmanctl_dbus_append_dict(DBusMessageIter *iter, connmanctl_dbus_append_func_t append_fn, void *append_data) { DBusMessageIter dict; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); if (append_fn) append_fn(&dict, append_data); dbus_message_iter_close_container(iter, &dict); } void __connmanctl_dbus_append_dict_entry(DBusMessageIter *iter, const char *property, int type, void *value) { DBusMessageIter dict_entry; dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry); append_variant(&dict_entry, property, type, value); dbus_message_iter_close_container(iter, &dict_entry); } int __connmanctl_dbus_set_property_dict(DBusConnection *connection, const char *path, const char *interface, connmanctl_dbus_method_return_func_t cb, void *user_data, const char *property, int type, connmanctl_dbus_append_func_t append_fn, void *append_user_data) { DBusMessage *message; DBusMessageIter iter, variant, dict; message = dbus_message_new_method_call("net.connman", path, interface, "SetProperty"); if (!message) return -ENOMEM; dbus_message_iter_init_append(message, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property); dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &variant); dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); append_fn(&dict, append_user_data); dbus_message_iter_close_container(&variant, &dict); dbus_message_iter_close_container(&iter, &variant); return send_method_call(connection, message, cb, user_data); } static void append_variant_array(DBusMessageIter *iter, const char *property, connmanctl_dbus_append_func_t append_fn, void *append_user_data) { DBusMessageIter variant, array; dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property); dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, &variant); dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &array); append_fn(&array, append_user_data); dbus_message_iter_close_container(&variant, &array); dbus_message_iter_close_container(iter, &variant); } void __connmanctl_dbus_append_dict_string_array(DBusMessageIter *iter, const char *property, connmanctl_dbus_append_func_t append_fn, void *append_user_data) { DBusMessageIter dict_entry; dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry); append_variant_array(&dict_entry, property, append_fn, append_user_data); dbus_message_iter_close_container(iter, &dict_entry); } int __connmanctl_dbus_set_property_array(DBusConnection *connection, const char *path, const char *interface, connmanctl_dbus_method_return_func_t cb, void *user_data, const char *property, int type, connmanctl_dbus_append_func_t append_fn, void *append_user_data) { DBusMessage *message; DBusMessageIter iter; if (type != DBUS_TYPE_STRING) return -EOPNOTSUPP; message = dbus_message_new_method_call("net.connman", path, interface, "SetProperty"); if (!message) return -ENOMEM; dbus_message_iter_init_append(message, &iter); append_variant_array(&iter, property, append_fn, append_user_data); return send_method_call(connection, message, cb, user_data); } int __connmanctl_dbus_session_change(DBusConnection *connection, const char *session_path, connmanctl_dbus_method_return_func_t cb, void * user_data, const char *property, int type, void *value) { DBusMessage *message; DBusMessageIter iter; message = dbus_message_new_method_call("net.connman", session_path, "net.connman.Session", "Change"); if (!message) return -ENOMEM; dbus_message_iter_init_append(message, &iter); if (append_variant(&iter, property, type, value) < 0) { dbus_message_unref(message); return -EINVAL; } return send_method_call(connection, message, cb, user_data); } int __connmanctl_dbus_session_change_array(DBusConnection *connection, const char *session_path, connmanctl_dbus_method_return_func_t cb, void *user_data, const char *property, connmanctl_dbus_append_func_t append_fn, void *append_user_data) { DBusMessage *message; DBusMessageIter iter; message = dbus_message_new_method_call("net.connman", session_path, "net.connman.Session", "Change"); if (!message) return -ENOMEM; dbus_message_iter_init_append(message, &iter); append_variant_array(&iter, property, append_fn, append_user_data); return send_method_call(connection, message, cb, user_data); }