Implemented event reporting to settings daemon clients.
[profile/ivi/settings-daemon.git] / plugins / connman / clock.cpp
1 /**
2  * @file clock.cpp
3  *
4  * @brief Connman-based clock settings.
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 "clock.hpp"
28
29 #include <settingsd/response_callback.hpp>
30 #include <settingsd/glib_traits.hpp>
31 #include <settingsd/json_glib_traits.hpp>
32 #include <settingsd/smart_ptr.hpp>
33
34 #include <cstring>
35 #include <boost/lexical_cast.hpp>
36
37
38 ivi::settings::clock::clock(event_callback const & e)
39   : connman_("net.connman.Clock", "/", e)
40 {
41 }
42
43 ivi::settings::clock::~clock()
44 {
45 }
46
47 std::string const &
48 ivi::settings::clock::id() const
49 {
50   static std::string const the_id("clock");
51
52   return the_id;
53 }
54
55 void
56 ivi::settings::clock::handle_request(std::string request,
57                                      response_callback response)
58 {
59   smart_ptr<JsonParser> const parser(json_parser_new());
60   json_parser_load_from_data(parser.get(), request.c_str(), -1, nullptr);
61
62   JsonReader * const reader =
63     json_reader_new(json_parser_get_root(parser.get()));
64
65   smart_ptr<JsonReader> safe_reader(reader);
66
67   char const * name = nullptr;
68   if (json_reader_read_member(reader, "name")) {
69     name = json_reader_get_string_value(reader);
70   }
71   json_reader_end_member(reader);
72
73   if (name != nullptr) {
74     GError * error = nullptr;
75     bool success = false;
76
77     if (strcmp(name, "time") == 0)
78       success = set_time(reader, response, error);
79     else if (strcmp(name, "time_updates") == 0)
80       success = set_updates("TimeUpdates", reader, response, error);
81     else if (strcmp(name, "timezone") == 0)
82       success = set_timezone(reader, response, error);
83     else if (strcmp(name, "timezone_updates") == 0)
84       success = set_updates("TimezoneUpdates", reader, response, error);
85     else if (strcmp(name, "is_time_updates_auto") == 0)
86       is_updates_auto("TimeUpdates", reader, response, error);
87     else if (strcmp(name, "is_timezone_updates_auto") == 0)
88       is_updates_auto("TimezoneUpdates", reader, response, error);
89     else {
90       response.send_error(
91         "Unrecognized " + id() + " request name: " + name);
92     }
93
94     smart_ptr<GError> safe_error(error);
95
96     if (success) {
97
98       // Nothing to add to successful response.
99       response.send_response(
100         [](JsonBuilder * /* builder */) {});
101
102     } else if (error != nullptr) {
103       response.send_error(
104         std::string("Unable to set ") + name + ": " + error->message);
105     }
106
107     // If success is false and error == nullptr a succesful response
108     // was sent by one of the functions above, e.g. is_update_auto().
109
110   } else {
111     response.send_error(
112       "Malformed " + id() + " request: \"name\" is missing.");
113   }
114 }
115
116 bool
117 ivi::settings::clock::set_time(JsonReader * reader,
118                                response_callback response,
119                                GError *& error)
120 {
121   int64_t time;
122   if (json_reader_read_member(reader, "value")) {
123     /**
124      * @bug @c json_read_get_int_value() returns a signed 64 bit
125      *      integer. However, the connman clock API expects an
126      *      unsigned 64 bit integer.  This means we cannot set time
127      *      values before the Unix epoch (< 0) or greater than
128      *      (2^63)-1, i.e the largest signed 64 bit integer.
129      */
130     time = json_reader_get_int_value(reader);
131   }
132
133   json_reader_end_member(reader);
134
135   bool success = false;
136
137   if (time >= 0) {
138     // Note that the connman clock API expects an unsigned 64 bit
139     // integer containing seconds since the Unix epoch.  We cast the
140     // positive int64_t value to an uint64_t value.  There is no
141     // chance of overflow in this case.
142     success =
143       set_property("Time",
144                    g_variant_new_uint64(static_cast<uint64_t>(time)),
145                    response,
146                    error);
147   } else {
148     response.send_error("Time value is earlier than epoch (negative): "
149                         + boost::lexical_cast<std::string>(time));
150   }
151
152   return success;
153 }
154
155 bool
156 ivi::settings::clock::set_timezone(JsonReader * reader,
157                                    response_callback response,
158                                    GError *& error)
159 {
160   bool success = false;
161
162   if (json_reader_read_member(reader, "value")) {
163     char const * const timezone = json_reader_get_string_value(reader);
164     success = this->set_property("Timezone",
165                                  g_variant_new_string(timezone),
166                                  response,
167                                  error);
168   }
169
170   json_reader_end_member(reader);
171
172   return success;
173 }
174
175 bool
176 ivi::settings::clock::set_updates(char const * name,
177                                   JsonReader * reader,
178                                   response_callback response,
179                                   GError *& error)
180 {
181   bool success = false;
182
183   char const * updates = nullptr;
184   if (json_reader_read_member(reader, "value")) {
185     updates = json_reader_get_string_value(reader);
186   }
187   json_reader_end_member(reader);
188
189   if (updates == nullptr
190       || (strcmp(updates, "manual") != 0
191           && strcmp(updates, "auto") != 0)) {
192     response.send_error(id()
193                         + ": updates value not \"manual\" "
194                         "or \"auto\": "
195                         + (updates == nullptr
196                            ? "<invalid_string>"
197                            : updates));
198   } else {
199     smart_ptr<GVariant> const current_value(get_property(name, error));
200
201     if (current_value != nullptr) {
202       char const * value =
203         g_variant_get_string(current_value.get(), nullptr);
204
205       if (strcmp(value, updates) == 0) {
206         // Already set.  Just return success, otherwise we'll timeout
207         // waiting for a PropertyChanged signal that'll never come.
208         return true;
209       }
210     }
211
212     success = set_property(name,
213                            g_variant_new_string(updates),
214                            response,
215                            error);
216   }
217
218   return success;
219 }
220
221 void
222 ivi::settings::clock::is_updates_auto(char const * name,
223                                       JsonReader * reader,
224                                       response_callback response,
225                                       GError *& error)
226 {
227   bool null = false;
228   if (json_reader_read_member(reader, "value")) {
229     null = json_reader_get_null_value(reader);
230   }
231   json_reader_end_member(reader);
232
233   if (!null) {
234     response.send_error(std::string(name) + " query parameter is not null.");
235     return;
236   }
237
238   smart_ptr<GVariant> const current_value(get_property(name, error));
239
240   if (current_value != nullptr) {
241     char const * value =
242       g_variant_get_string(current_value.get(), nullptr);
243
244     bool const is_auto = (strcmp(value, "auto") == 0);
245
246     response.send_response(
247       [is_auto](JsonBuilder * builder)
248       {
249         json_builder_set_member_name(builder, "value");
250         json_builder_add_boolean_value(builder, is_auto);
251       });
252   }
253 }
254
255 bool
256 ivi::settings::clock::set_property(char const * name,
257                                    GVariant * value,
258                                    response_callback /* response */,
259                                    GError *& error)
260 {
261   smart_ptr<GVariant> const ret(
262     connman_.set_property(name, value, error));
263
264   return ret.get() != nullptr;
265 }
266
267 GVariant *
268 ivi::settings::clock::get_property(char const * property,
269                                    GError *& error) const
270 {
271   constexpr gint const timeout = 5000;  // milliseconds
272
273   smart_ptr<GVariant> const dictionary(
274     g_dbus_proxy_call_sync(connman_.proxy(),
275                            "GetProperties",
276                            nullptr,  // No parameters
277                            G_DBUS_CALL_FLAGS_NONE,
278                            timeout,
279                            nullptr,  // Not cancellable
280                            &error));
281
282   smart_ptr<GVariant> value;
283
284   if (dictionary != nullptr) {
285     GVariantIter * i = nullptr;
286     g_variant_get(dictionary.get(), "(a{sv})", &i);
287     smart_ptr<GVariantIter> const iter(i);
288
289     gchar    * pname  = nullptr;
290     GVariant * pvalue = nullptr;
291
292     while (g_variant_iter_next(i, "{sv}", &pname, &pvalue)) {
293       smart_ptr<gchar> const name(pname);
294       value.reset(pvalue);
295
296       // Check if this is the property we want.
297       if (strcmp(name.get(), property) == 0)
298           break;
299     }
300   }
301
302   return value.release();
303 }
304
305
306 // Local Variables:
307 // mode:c++
308 // c-basic-offset:2
309 // indent-tabs-mode: nil
310 // End: