Added API for enabling tethering
[profile/ivi/settings-daemon.git] / plugins / connman / technology.cpp
1 /**
2  * @file technology.cpp
3  *
4  * @brief Connman technology request handling.
5  *
6  * @author Ossama Othman @<ossama.othman@@intel.com@>
7  *
8  * @copyright @par
9  * Copyright 2013 Intel Corporation All Rights Reserved.
10  * @par
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation;
14  * version 2.1 of the License.
15  * @par
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  * @par
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA  02110-1301  USA
25  */
26
27 #include "technology.hpp"
28 #include "connman_manager.hpp"
29
30 #include <settingsd/response_callback.hpp>
31 #include <settingsd/glib_traits.hpp>
32 #include <settingsd/json_glib_traits.hpp>
33 #include <settingsd/unique_ptr.hpp>
34
35 #include <cstring>
36
37 ivi::settings::technology::technology(char const * path,
38                                       GDBusConnection * connection,
39                                       connman_manager & manager)
40   : connman_("net.connman.Technology",     // Interface
41              path,                         // Object path
42              connection)
43   , manager_(manager)
44 {
45 }
46
47 void
48 ivi::settings::technology::handle_request(char const * name,
49                                           JsonReader * reader,
50                                           response_callback & response)
51 {
52   if (name != nullptr) {
53     if (strcmp(name, "is_enabled") == 0)
54       get_powered(reader, response);
55     else if (strcmp(name, "enable") == 0)
56       set_powered(reader, response);
57     else if (strcmp(name, "scan") == 0)
58       scan(reader, response);
59     else if (strcmp(name, "tethering") == 0)
60       set_tethering(reader, response);
61     else {
62       response.send_error(
63         std::string("Unrecognized connman technology request name: ")
64         + name);
65     }
66   }
67 }
68
69 void
70 ivi::settings::technology::get_powered(JsonReader * reader,
71                                        response_callback & response)
72 {
73   bool null = false;
74   // The value is the second array element.
75   if (json_reader_read_element(reader, 1)) {
76     null = json_reader_get_null_value(reader);
77   }
78   json_reader_end_element(reader);
79
80   if (!null) {
81     response.send_error(
82       "connman::technology is_enabled parameter is not null.");
83     return;
84   }
85
86   unique_ptr<GVariant> const property(
87     get_property("Powered", G_VARIANT_TYPE_BOOLEAN, response));
88
89   if (property != nullptr) {
90     bool const powered = g_variant_get_boolean(property.get());
91
92     response.send_response(
93       [powered](JsonBuilder * builder)
94       {
95         json_builder_set_member_name(builder, "value");
96         json_builder_add_boolean_value(builder, powered);
97       });
98   }
99
100   // Error responses handled in get_property() method.
101 }
102
103 void
104 ivi::settings::technology::set_powered(JsonReader * reader,
105                                        response_callback & response)
106 {
107   bool enable = false;
108   // The value is the second array element.
109   if (json_reader_read_element(reader, 1)) {
110     enable = json_reader_get_boolean_value(reader);
111   }
112   json_reader_end_element(reader);
113
114   constexpr char const name[] = "Powered";
115
116   GError * error = nullptr;
117
118   unique_ptr<GVariant> ret(
119     connman_.set_property(name,
120                           g_variant_new_boolean(enable),
121                           error));
122
123   unique_ptr<GError> safe_error(error);
124
125   if (ret != nullptr) {
126       // Nothing to add to successful response.
127       response.send_response(
128         [](JsonBuilder * /* builder */) {});
129   } else if (error != nullptr) {
130     response.send_error(
131       std::string("Unable to set connman::technology powered state: ")
132       + error->message);
133   } else {
134     response.send_error(
135       "Malformed connman::technology enable request value.");
136   }
137 }
138
139 void
140 ivi::settings::technology::set_tethering(JsonReader * reader,
141                                   response_callback & response)
142 {
143   char const * ssid = nullptr;
144   char const * password = nullptr;
145   bool enabled = false, have_password = true, have_ssid = true;
146   constexpr char const identifier[] = "TetheringIdentifier";
147   constexpr char const passphrase[] = "TetheringPassphrase";
148   constexpr char const tethering[] = "Tethering";
149
150   if (json_reader_read_member(reader, "enabled")) {
151     enabled = json_reader_get_boolean_value(reader);
152     json_reader_end_element(reader);
153
154     // In case that we are enabling tethering we need to setup also SSID and passphrase
155     // Otherwise those values are not required
156     if (enabled) {
157       have_ssid = json_reader_read_member(reader, "ssid");
158       if (have_ssid) {
159         ssid = json_reader_get_string_value(reader);
160       }
161       json_reader_end_element(reader);
162
163       have_password = json_reader_read_member(reader, "password");
164       if (have_password) {
165         password = json_reader_get_string_value(reader);
166       }
167       json_reader_end_element(reader);
168     }
169
170     if (have_ssid && have_password) {
171       GError * identifier_error = nullptr, *passphrase_error = nullptr, *enabled_error = nullptr;
172       bool identifier_res = true, passphrase_res = true, enabled_res;
173
174       enabled_res = this->set_property(tethering, g_variant_new_boolean(enabled), response, enabled_error);
175
176       if (enabled && enabled_res) {
177         passphrase_res = this->set_property(passphrase, g_variant_new_string(password), response, passphrase_error);
178         identifier_res = this->set_property(identifier, g_variant_new_string(ssid), response, identifier_error);
179       }
180
181       if (enabled_res && identifier_res && passphrase_res) {
182         response.send_response(
183           [enabled](JsonBuilder * builder)
184           {
185             json_builder_set_member_name(builder, "value");
186             json_builder_add_boolean_value(builder, enabled);
187           });
188       } else {
189         std::string failed_part;
190         GError *error;
191
192         if (!enabled_res) {
193           error = enabled_error;
194           failed_part = std::string("status");
195         } else if (!identifier_res) {
196           error = identifier_error;
197           failed_part = std::string("identifier");
198         } else {
199           error = passphrase_error;
200           failed_part = std::string("passphrase");
201         }
202
203         if (error != nullptr) {
204           unique_ptr<GError> safe_error(error);
205           response.send_error(
206             std::string("Unable to set connman::technology tethering ")
207             + failed_part
208             + std::string(": ")
209             + enabled_error->message);
210         } else {
211           response.send_error(std::string("Malformed connman::technology tethering value ") + failed_part);
212         }
213       }
214     } else if (!have_ssid) {
215       response.send_error("connman::technology tether ssid parameter is null.");
216     } else {
217       response.send_error("connman::technology tether password parameter is null.");
218     }
219   } else {
220     response.send_error("connman::technology tether enabled parameter is null.");
221   }
222 }
223
224 bool
225 ivi::settings::technology::set_property(char const * name,
226                                    GVariant * value,
227                                    response_callback /* response */,
228                                    GError *& error)
229 {
230   unique_ptr<GVariant> const ret(
231     connman_.set_property(name, value, error));
232
233   return ret != nullptr;
234 }
235
236 void
237 ivi::settings::technology::scan(JsonReader * reader,
238                                 response_callback & response)
239 {
240   bool null = false;
241   // The value is the second array element.
242   if (json_reader_read_element(reader, 1)) {
243     null = json_reader_get_null_value(reader);
244   }
245   json_reader_end_element(reader);
246
247   if (!null) {
248     response.send_error(
249       "connman::technology scan parameter is not null.");
250     return;
251   }
252
253   // The scan could take a while.
254   constexpr gint const timeout = 10000;  // milliseconds
255   GError * error = nullptr;
256
257   unique_ptr<GVariant> const ret(
258     g_dbus_proxy_call_sync(connman_.proxy(),
259                            "Scan",
260                            nullptr,  // No parameters
261                            G_DBUS_CALL_FLAGS_NONE,
262                            timeout,
263                            nullptr,  // Not cancellable
264                            &error));
265
266   unique_ptr<GError> safe_error(error);
267
268   if (ret != nullptr) {
269     manager_.get_services(response);
270   } else if (error != nullptr) {
271     response.send_error(
272       std::string("Unable to scan connman::technology: ")
273       + error->message);
274   } else {
275     response.send_error(
276       "Malformed connman::technology scan request value.");
277   }
278 }
279
280 GVariant *
281 ivi::settings::technology::get_property(char const * name,
282                                         GVariantType const * type,
283                                         response_callback & response)
284 {
285   GError * error = nullptr;
286
287   std::string tech(connman_.object_path());
288   auto const n = tech.rfind('/');
289   if (n == std::string::npos) {
290     response.send_error(
291       "Unable to determine Connman technology.  Malformed object path.");
292
293     return nullptr;
294   }
295
296   tech = tech.substr(n + 1);
297
298   unique_ptr<GVariant> const properties(
299     manager_.get_properties(tech.c_str(), error));
300
301   unique_ptr<GError> safe_error(error);
302
303   unique_ptr<GVariant> property;
304   if (properties != nullptr) {
305     property.reset(
306       g_variant_lookup_value(properties.get(), name, type));
307
308     if (property == nullptr) {
309       response.send_error(
310         "Internal " + tech
311         + "error: \"" + name + "\" property lookup failed.");
312     }
313   } else if (error != nullptr) {
314     response.send_error(
315       "Unable to get " + tech + "properties: "
316       + error->message);
317   } else {
318     // This scenario will occur if the technology doesn't exist on
319     // the platform.  For example, attempting to retrieve the wifi
320     // "Powered" property on a platform without supported hardware
321     // will result in this error.
322     response.send_error(
323       "Connman technology properties are not available.");
324   }
325
326   return property.release();
327 }
328
329
330 // Local Variables:
331 // mode:c++
332 // c-basic-offset:2
333 // indent-tabs-mode: nil
334 // End: