af5d762fd1cd74adcc7160e3983b84d271f0e7b9
[profile/ivi/ofono.git] / src / stkagent.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #define _GNU_SOURCE
27 #include <stdint.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include <glib.h>
32 #include <gdbus.h>
33
34 #include "ofono.h"
35
36 #include "common.h"
37 #include "smsutil.h"
38 #include "stkutil.h"
39 #include "stkagent.h"
40
41 #ifndef DBUS_TIMEOUT_INFINITE
42 #define DBUS_TIMEOUT_INFINITE ((int) 0x7fffffff)
43 #endif
44
45 enum allowed_error {
46         ALLOWED_ERROR_GO_BACK   = 0x1,
47         ALLOWED_ERROR_TERMINATE = 0x2,
48         ALLOWED_ERROR_BUSY              = 0x4,
49 };
50
51 struct stk_agent {
52         char *path;                             /* Agent Path */
53         char *bus;                              /* Agent bus */
54         guint disconnect_watch;                 /* DBus disconnect watch */
55         ofono_bool_t remove_on_terminate;
56         ofono_destroy_func removed_cb;
57         void *removed_data;
58         DBusMessage *msg;
59         DBusPendingCall *call;
60         void *user_cb;
61         void *user_data;
62         ofono_destroy_func user_destroy;
63
64         const struct stk_menu *request_selection_menu;
65 };
66
67 #define ERROR_PREFIX OFONO_SERVICE ".Error"
68 #define GOBACK_ERROR ERROR_PREFIX ".GoBack"
69 #define TERMINATE_ERROR ERROR_PREFIX ".EndSession"
70 #define BUSY_ERROR ERROR_PREFIX ".Busy"
71
72 static void stk_agent_send_noreply(struct stk_agent *agent, const char *method)
73 {
74         DBusConnection *conn = ofono_dbus_get_connection();
75         DBusMessage *message;
76
77         message = dbus_message_new_method_call(agent->bus, agent->path,
78                                                 OFONO_SIM_APP_INTERFACE,
79                                                 method);
80         if (message == NULL)
81                 return;
82
83         dbus_message_set_no_reply(message, TRUE);
84
85         g_dbus_send_message(conn, message);
86 }
87
88 static inline void stk_agent_send_release(struct stk_agent *agent)
89 {
90         stk_agent_send_noreply(agent, "Release");
91 }
92
93 static inline void stk_agent_send_cancel(struct stk_agent *agent)
94 {
95         stk_agent_send_noreply(agent, "Cancel");
96 }
97
98 static void stk_agent_request_end(struct stk_agent *agent)
99 {
100         if (agent->msg) {
101                 dbus_message_unref(agent->msg);
102                 agent->msg = NULL;
103         }
104
105         if (agent->call) {
106                 dbus_pending_call_unref(agent->call);
107                 agent->call = NULL;
108         }
109
110         if (agent->user_destroy)
111                 agent->user_destroy(agent->user_data);
112
113         agent->user_destroy = NULL;
114         agent->user_data = NULL;
115         agent->user_cb = NULL;
116 }
117
118 ofono_bool_t stk_agent_matches(struct stk_agent *agent,
119                                 const char *path, const char *sender)
120 {
121         return !strcmp(agent->path, path) && !strcmp(agent->bus, sender);
122 }
123
124 void stk_agent_set_removed_notify(struct stk_agent *agent,
125                                         ofono_destroy_func destroy,
126                                         void *user_data)
127 {
128         agent->removed_cb = destroy;
129         agent->removed_data = user_data;
130 }
131
132 void stk_agent_request_cancel(struct stk_agent *agent)
133 {
134         if (agent->call == NULL)
135                 return;
136
137         dbus_pending_call_cancel(agent->call);
138
139         if (agent->disconnect_watch)
140                 stk_agent_send_cancel(agent);
141
142         stk_agent_request_end(agent);
143 }
144
145 void stk_agent_free(struct stk_agent *agent)
146 {
147         DBusConnection *conn = ofono_dbus_get_connection();
148
149         stk_agent_request_cancel(agent);
150
151         if (agent->disconnect_watch) {
152                 stk_agent_send_release(agent);
153
154                 g_dbus_remove_watch(conn, agent->disconnect_watch);
155                 agent->disconnect_watch = 0;
156         }
157
158         if (agent->removed_cb)
159                 agent->removed_cb(agent->removed_data);
160
161         g_free(agent->path);
162         g_free(agent->bus);
163         g_free(agent);
164 }
165
166 static int check_error(struct stk_agent *agent, DBusMessage *reply,
167                                 int allowed_errors,
168                                 enum stk_agent_result *out_result)
169 {
170         DBusError err;
171         int result = 0;
172
173         dbus_error_init(&err);
174
175         if (dbus_set_error_from_message(&err, reply) == FALSE) {
176                 *out_result = STK_AGENT_RESULT_OK;
177                 return 0;
178         }
179
180         ofono_debug("SimToolkitAgent %s replied with error %s, %s",
181                         agent->path, err.name, err.message);
182
183         /* Timeout is always valid */
184         if (g_str_equal(err.name, DBUS_ERROR_NO_REPLY)) {
185                 /* Send a Cancel() to the agent since its taking too long */
186                 stk_agent_send_cancel(agent);
187                 *out_result = STK_AGENT_RESULT_TIMEOUT;
188                 goto out;
189         }
190
191         if ((allowed_errors & ALLOWED_ERROR_GO_BACK) &&
192                         g_str_equal(err.name, GOBACK_ERROR)) {
193                 *out_result = STK_AGENT_RESULT_BACK;
194                 goto out;
195         }
196
197         if ((allowed_errors & ALLOWED_ERROR_TERMINATE) &&
198                         g_str_equal(err.name, TERMINATE_ERROR)) {
199                 *out_result = STK_AGENT_RESULT_TERMINATE;
200                 goto out;
201         }
202
203         if ((allowed_errors & ALLOWED_ERROR_BUSY) &&
204                         g_str_equal(err.name, BUSY_ERROR)) {
205                 *out_result = STK_AGENT_RESULT_BUSY;
206                 goto out;
207         }
208
209         result = -EINVAL;
210
211 out:
212         dbus_error_free(&err);
213         return result;
214 }
215
216 static void stk_agent_disconnect_cb(DBusConnection *conn, void *user_data)
217 {
218         struct stk_agent *agent = user_data;
219
220         ofono_debug("Agent exited without calling Unregister");
221
222         agent->disconnect_watch = 0;
223
224         stk_agent_free(agent);
225 }
226
227 struct stk_agent *stk_agent_new(const char *path, const char *sender,
228                                 ofono_bool_t remove_on_terminate)
229 {
230         struct stk_agent *agent = g_try_new0(struct stk_agent, 1);
231         DBusConnection *conn = ofono_dbus_get_connection();
232
233         if (agent == NULL)
234                 return NULL;
235
236         agent->path = g_strdup(path);
237         agent->bus = g_strdup(sender);
238         agent->remove_on_terminate = remove_on_terminate;
239
240         agent->disconnect_watch = g_dbus_add_disconnect_watch(conn, sender,
241                                                         stk_agent_disconnect_cb,
242                                                         agent, NULL);
243
244         return agent;
245 }
246
247 static void append_menu_items(DBusMessageIter *iter,
248                                 const struct stk_menu_item *item)
249 {
250         DBusMessageIter array, entry;
251
252         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
253                                                 "(sy)", &array);
254
255         while (item && item->text) {
256                 dbus_message_iter_open_container(&array, DBUS_TYPE_STRUCT,
257                                                         NULL, &entry);
258
259                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
260                                                 &item->text);
261                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BYTE,
262                                                 &item->icon_id);
263
264                 dbus_message_iter_close_container(&array, &entry);
265                 item++;
266         }
267
268         dbus_message_iter_close_container(iter, &array);
269 }
270
271 void append_menu_items_variant(DBusMessageIter *iter,
272                                 const struct stk_menu_item *items)
273 {
274         DBusMessageIter variant;
275
276         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
277                                                 "a(sy)", &variant);
278
279         append_menu_items(&variant, items);
280
281         dbus_message_iter_close_container(iter, &variant);
282 }
283
284 #define CALLBACK_END()                                          \
285 done:                                                           \
286         if (result == STK_AGENT_RESULT_TERMINATE &&             \
287                         agent->remove_on_terminate)             \
288                 remove_agent = TRUE;                            \
289         else                                                    \
290                 remove_agent = FALSE;                           \
291                                                                 \
292 error:                                                          \
293         stk_agent_request_end(agent);                           \
294         dbus_message_unref(reply);                              \
295                                                                 \
296         if (remove_agent)                                       \
297                 stk_agent_free(agent)                           \
298
299 static void request_selection_cb(DBusPendingCall *call, void *data)
300 {
301         struct stk_agent *agent = data;
302         const struct stk_menu *menu = agent->request_selection_menu;
303         stk_agent_selection_cb cb = (stk_agent_selection_cb) agent->user_cb;
304         DBusMessage *reply = dbus_pending_call_steal_reply(call);
305         unsigned char selection, i;
306         enum stk_agent_result result;
307         gboolean remove_agent;
308
309         if (check_error(agent, reply,
310                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
311                         &result) == -EINVAL) {
312                 remove_agent = TRUE;
313                 goto error;
314         }
315
316         if (result != STK_AGENT_RESULT_OK) {
317                 cb(result, 0, agent->user_data);
318                 goto done;
319         }
320
321         if (dbus_message_get_args(reply, NULL,
322                                         DBUS_TYPE_BYTE, &selection,
323                                         DBUS_TYPE_INVALID) == FALSE) {
324                 ofono_error("Can't parse the reply to RequestSelection()");
325                 remove_agent = TRUE;
326                 goto error;
327         }
328
329         for (i = 0; i < selection && menu->items[i].text; i++);
330
331         if (i != selection) {
332                 ofono_error("Invalid item selected");
333                 remove_agent = TRUE;
334                 goto error;
335         }
336
337         cb(result, menu->items[selection].item_id, agent->user_data);
338
339         CALLBACK_END();
340 }
341
342 int stk_agent_request_selection(struct stk_agent *agent,
343                                 const struct stk_menu *menu,
344                                 stk_agent_selection_cb cb,
345                                 void *user_data, ofono_destroy_func destroy,
346                                 int timeout)
347 {
348         DBusConnection *conn = ofono_dbus_get_connection();
349         dbus_int16_t default_item = menu->default_item;
350         DBusMessageIter iter;
351
352         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
353                                                         OFONO_SIM_APP_INTERFACE,
354                                                         "RequestSelection");
355         if (agent->msg == NULL)
356                 return -ENOMEM;
357
358         dbus_message_iter_init_append(agent->msg, &iter);
359
360         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &menu->title);
361         dbus_message_iter_append_basic(&iter, DBUS_TYPE_BYTE, &menu->icon.id);
362         append_menu_items(&iter, menu->items);
363         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT16, &default_item);
364
365         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
366                                                 timeout) == FALSE ||
367                         agent->call == NULL)
368                 return -EIO;
369
370         agent->user_cb = cb;
371         agent->user_data = user_data;
372         agent->user_destroy = destroy;
373
374         agent->request_selection_menu = menu;
375
376         dbus_pending_call_set_notify(agent->call, request_selection_cb,
377                                         agent, NULL);
378
379         return 0;
380 }
381
382 static void display_text_cb(DBusPendingCall *call, void *data)
383 {
384         struct stk_agent *agent = data;
385         stk_agent_display_text_cb cb = agent->user_cb;
386         DBusMessage *reply = dbus_pending_call_steal_reply(call);
387         enum stk_agent_result result;
388         gboolean remove_agent;
389
390         if (check_error(agent, reply,
391                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE |
392                         ALLOWED_ERROR_BUSY, &result) == -EINVAL) {
393                 remove_agent = TRUE;
394                 goto error;
395         }
396
397         if (result != STK_AGENT_RESULT_OK) {
398                 cb(result, agent->user_data);
399                 goto done;
400         }
401
402         if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) {
403                 ofono_error("Can't parse the reply to DisplayText()");
404                 remove_agent = TRUE;
405                 goto error;
406         }
407
408         cb(result, agent->user_data);
409
410         CALLBACK_END();
411 }
412
413 int stk_agent_display_text(struct stk_agent *agent, const char *text,
414                                 const struct stk_icon_id *icon,
415                                 ofono_bool_t urgent,
416                                 stk_agent_display_text_cb cb,
417                                 void *user_data, ofono_destroy_func destroy,
418                                 int timeout)
419 {
420         DBusConnection *conn = ofono_dbus_get_connection();
421         dbus_bool_t priority = urgent;
422
423         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
424                                                         OFONO_SIM_APP_INTERFACE,
425                                                         "DisplayText");
426         if (agent->msg == NULL)
427                 return -ENOMEM;
428
429         dbus_message_append_args(agent->msg,
430                                         DBUS_TYPE_STRING, &text,
431                                         DBUS_TYPE_BYTE, &icon->id,
432                                         DBUS_TYPE_BOOLEAN, &priority,
433                                         DBUS_TYPE_INVALID);
434
435         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
436                                                 timeout) == FALSE ||
437                         agent->call == NULL)
438                 return -EIO;
439
440         agent->user_cb = cb;
441         agent->user_data = user_data;
442         agent->user_destroy = destroy;
443
444         dbus_pending_call_set_notify(agent->call, display_text_cb,
445                                         agent, NULL);
446
447         return 0;
448 }
449
450 static void get_confirmation_cb(DBusPendingCall *call, void *data)
451 {
452         struct stk_agent *agent = data;
453         stk_agent_confirmation_cb cb = agent->user_cb;
454         DBusMessage *reply = dbus_pending_call_steal_reply(call);
455         enum stk_agent_result result;
456         gboolean remove_agent;
457         dbus_bool_t confirm;
458
459         if (check_error(agent, reply,
460                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
461                         &result) == -EINVAL) {
462                 remove_agent = TRUE;
463                 goto error;
464         }
465
466         if (result != STK_AGENT_RESULT_OK) {
467                 cb(result, FALSE, agent->user_data);
468                 goto done;
469         }
470
471         if (dbus_message_get_args(reply, NULL,
472                                         DBUS_TYPE_BOOLEAN, &confirm,
473                                         DBUS_TYPE_INVALID) == FALSE) {
474                 ofono_error("Can't parse the reply to GetConfirmation()");
475                 remove_agent = TRUE;
476                 goto error;
477         }
478
479         cb(result, confirm, agent->user_data);
480
481         CALLBACK_END();
482 }
483
484 int stk_agent_request_confirmation(struct stk_agent *agent, const char *text,
485                                         const struct stk_icon_id *icon,
486                                         stk_agent_confirmation_cb cb,
487                                         void *user_data,
488                                         ofono_destroy_func destroy,
489                                         int timeout)
490 {
491         DBusConnection *conn = ofono_dbus_get_connection();
492
493         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
494                                                         OFONO_SIM_APP_INTERFACE,
495                                                         "RequestConfirmation");
496         if (agent->msg == NULL)
497                 return -ENOMEM;
498
499         dbus_message_append_args(agent->msg,
500                                         DBUS_TYPE_STRING, &text,
501                                         DBUS_TYPE_BYTE, &icon->id,
502                                         DBUS_TYPE_INVALID);
503
504         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
505                                                 timeout) == FALSE ||
506                         agent->call == NULL)
507                 return -EIO;
508
509         agent->user_cb = cb;
510         agent->user_data = user_data;
511         agent->user_destroy = destroy;
512
513         dbus_pending_call_set_notify(agent->call, get_confirmation_cb,
514                                         agent, NULL);
515
516         return 0;
517 }
518
519 static void get_digit_cb(DBusPendingCall *call, void *data)
520 {
521         struct stk_agent *agent = data;
522         stk_agent_string_cb cb = agent->user_cb;
523         DBusMessage *reply = dbus_pending_call_steal_reply(call);
524         enum stk_agent_result result;
525         gboolean remove_agent;
526         char *digit;
527
528         if (check_error(agent, reply,
529                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
530                         &result) == -EINVAL) {
531                 remove_agent = TRUE;
532                 goto error;
533         }
534
535         if (result != STK_AGENT_RESULT_OK) {
536                 cb(result, NULL, agent->user_data);
537                 goto done;
538         }
539
540         if (dbus_message_get_args(reply, NULL,
541                                         DBUS_TYPE_STRING, &digit,
542                                         DBUS_TYPE_INVALID) == FALSE ||
543                         strlen(digit) != 1 ||
544                         !valid_phone_number_format(digit)) {
545                 ofono_error("Can't parse the reply to GetDigit()");
546                 remove_agent = TRUE;
547                 goto error;
548         }
549
550         cb(result, digit, agent->user_data);
551
552         CALLBACK_END();
553 }
554
555 int stk_agent_request_digit(struct stk_agent *agent, const char *text,
556                                 const struct stk_icon_id *icon,
557                                 stk_agent_string_cb cb, void *user_data,
558                                 ofono_destroy_func destroy, int timeout)
559 {
560         DBusConnection *conn = ofono_dbus_get_connection();
561
562         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
563                                                         OFONO_SIM_APP_INTERFACE,
564                                                         "RequestDigit");
565         if (agent->msg == NULL)
566                 return -ENOMEM;
567
568         dbus_message_append_args(agent->msg,
569                                         DBUS_TYPE_STRING, &text,
570                                         DBUS_TYPE_BYTE, &icon->id,
571                                         DBUS_TYPE_INVALID);
572
573         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
574                                                 timeout) == FALSE ||
575                         agent->call == NULL)
576                 return -EIO;
577
578         agent->user_cb = cb;
579         agent->user_data = user_data;
580         agent->user_destroy = destroy;
581
582         dbus_pending_call_set_notify(agent->call, get_digit_cb, agent, NULL);
583
584         return 0;
585 }
586
587 int stk_agent_request_quick_digit(struct stk_agent *agent, const char *text,
588                                         const struct stk_icon_id *icon,
589                                         stk_agent_string_cb cb, void *user_data,
590                                         ofono_destroy_func destroy, int timeout)
591 {
592         DBusConnection *conn = ofono_dbus_get_connection();
593
594         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
595                                                         OFONO_SIM_APP_INTERFACE,
596                                                         "RequestQuickDigit");
597         if (agent->msg == NULL)
598                 return -ENOMEM;
599
600         dbus_message_append_args(agent->msg,
601                                         DBUS_TYPE_STRING, &text,
602                                         DBUS_TYPE_BYTE, &icon->id,
603                                         DBUS_TYPE_INVALID);
604
605         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
606                                                 timeout) == FALSE ||
607                         agent->call == NULL)
608                 return -EIO;
609
610         agent->user_cb = cb;
611         agent->user_data = user_data;
612         agent->user_destroy = destroy;
613
614         dbus_pending_call_set_notify(agent->call, get_digit_cb, agent, NULL);
615
616         return 0;
617 }
618
619 static void get_key_cb(DBusPendingCall *call, void *data)
620 {
621         struct stk_agent *agent = data;
622         stk_agent_string_cb cb = agent->user_cb;
623         DBusMessage *reply = dbus_pending_call_steal_reply(call);
624         enum stk_agent_result result;
625         gboolean remove_agent;
626         char *key;
627
628         if (check_error(agent, reply,
629                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
630                         &result) == -EINVAL) {
631                 remove_agent = TRUE;
632                 goto error;
633         }
634
635         if (result != STK_AGENT_RESULT_OK) {
636                 cb(result, NULL, agent->user_data);
637                 goto done;
638         }
639
640         if (dbus_message_get_args(reply, NULL,
641                                         DBUS_TYPE_STRING, &key,
642                                         DBUS_TYPE_INVALID) == FALSE ||
643                         g_utf8_strlen(key, 10) != 1) {
644                 ofono_error("Can't parse the reply to GetKey()");
645                 remove_agent = TRUE;
646                 goto error;
647         }
648
649         cb(result, key, agent->user_data);
650
651         CALLBACK_END();
652 }
653
654 int stk_agent_request_key(struct stk_agent *agent, const char *text,
655                                 const struct stk_icon_id *icon,
656                                 ofono_bool_t unicode_charset,
657                                 stk_agent_string_cb cb, void *user_data,
658                                 ofono_destroy_func destroy, int timeout)
659 {
660         DBusConnection *conn = ofono_dbus_get_connection();
661
662         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
663                                                         OFONO_SIM_APP_INTERFACE,
664                                                         "RequestKey");
665         if (agent->msg == NULL)
666                 return -ENOMEM;
667
668         dbus_message_append_args(agent->msg,
669                                         DBUS_TYPE_STRING, &text,
670                                         DBUS_TYPE_BYTE, &icon->id,
671                                         DBUS_TYPE_INVALID);
672
673         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
674                                                 timeout) == FALSE ||
675                         agent->call == NULL)
676                 return -EIO;
677
678         agent->user_cb = cb;
679         agent->user_data = user_data;
680         agent->user_destroy = destroy;
681
682         dbus_pending_call_set_notify(agent->call, get_key_cb, agent, NULL);
683
684         return 0;
685 }
686
687 static void get_digits_cb(DBusPendingCall *call, void *data)
688 {
689         struct stk_agent *agent = data;
690         stk_agent_string_cb cb = agent->user_cb;
691         DBusMessage *reply = dbus_pending_call_steal_reply(call);
692         enum stk_agent_result result;
693         gboolean remove_agent;
694         char *string;
695
696         if (check_error(agent, reply,
697                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
698                         &result) == -EINVAL) {
699                 remove_agent = TRUE;
700                 goto error;
701         }
702
703         if (result != STK_AGENT_RESULT_OK) {
704                 cb(result, NULL, agent->user_data);
705                 goto done;
706         }
707
708         if (dbus_message_get_args(reply, NULL,
709                                         DBUS_TYPE_STRING, &string,
710                                         DBUS_TYPE_INVALID) == FALSE) {
711                 ofono_error("Can't parse the reply to GetDigits()");
712                 remove_agent = TRUE;
713                 goto error;
714         }
715
716         cb(result, string, agent->user_data);
717
718         CALLBACK_END();
719 }
720
721 int stk_agent_request_digits(struct stk_agent *agent, const char *text,
722                                 const struct stk_icon_id *icon,
723                                 const char *default_text,
724                                 int min, int max, ofono_bool_t hidden,
725                                 stk_agent_string_cb cb, void *user_data,
726                                 ofono_destroy_func destroy, int timeout)
727 {
728         DBusConnection *conn = ofono_dbus_get_connection();
729         uint8_t min_val = min;
730         uint8_t max_val = max;
731         dbus_bool_t hidden_val = hidden;
732
733         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
734                                                         OFONO_SIM_APP_INTERFACE,
735                                                         "RequestDigits");
736         if (agent->msg == NULL)
737                 return -ENOMEM;
738
739         if (default_text == NULL)
740                 default_text = "";
741
742         dbus_message_append_args(agent->msg,
743                                         DBUS_TYPE_STRING, &text,
744                                         DBUS_TYPE_BYTE, &icon->id,
745                                         DBUS_TYPE_STRING, &default_text,
746                                         DBUS_TYPE_BYTE, &min_val,
747                                         DBUS_TYPE_BYTE, &max_val,
748                                         DBUS_TYPE_BOOLEAN, &hidden_val,
749                                         DBUS_TYPE_INVALID);
750
751         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
752                                                 timeout) == FALSE ||
753                         agent->call == NULL)
754                 return -EIO;
755
756         agent->user_cb = cb;
757         agent->user_data = user_data;
758         agent->user_destroy = destroy;
759
760         dbus_pending_call_set_notify(agent->call, get_digits_cb, agent, NULL);
761
762         return 0;
763 }
764
765 static void get_input_cb(DBusPendingCall *call, void *data)
766 {
767         struct stk_agent *agent = data;
768         stk_agent_string_cb cb = agent->user_cb;
769         DBusMessage *reply = dbus_pending_call_steal_reply(call);
770         enum stk_agent_result result;
771         gboolean remove_agent;
772         char *string;
773
774         if (check_error(agent, reply,
775                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
776                         &result) == -EINVAL) {
777                 remove_agent = TRUE;
778                 goto error;
779         }
780
781         if (result != STK_AGENT_RESULT_OK) {
782                 cb(result, NULL, agent->user_data);
783                 goto done;
784         }
785
786         if (dbus_message_get_args(reply, NULL,
787                                         DBUS_TYPE_STRING, &string,
788                                         DBUS_TYPE_INVALID) == FALSE) {
789                 ofono_error("Can't parse the reply to GetInput()");
790                 remove_agent = TRUE;
791                 goto error;
792         }
793
794         cb(result, string, agent->user_data);
795
796         CALLBACK_END();
797 }
798
799 int stk_agent_request_input(struct stk_agent *agent, const char *text,
800                                 const struct stk_icon_id *icon,
801                                 const char *default_text,
802                                 ofono_bool_t unicode_charset, int min, int max,
803                                 ofono_bool_t hidden, stk_agent_string_cb cb,
804                                 void *user_data, ofono_destroy_func destroy,
805                                 int timeout)
806 {
807         DBusConnection *conn = ofono_dbus_get_connection();
808         uint8_t min_val = min;
809         uint8_t max_val = max;
810         dbus_bool_t hidden_val = hidden;
811
812         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
813                                                         OFONO_SIM_APP_INTERFACE,
814                                                         "RequestInput");
815         if (agent->msg == NULL)
816                 return -ENOMEM;
817
818         if (default_text == NULL)
819                 default_text = "";
820
821         dbus_message_append_args(agent->msg,
822                                         DBUS_TYPE_STRING, &text,
823                                         DBUS_TYPE_BYTE, &icon->id,
824                                         DBUS_TYPE_STRING, &default_text,
825                                         DBUS_TYPE_BYTE, &min_val,
826                                         DBUS_TYPE_BYTE, &max_val,
827                                         DBUS_TYPE_BOOLEAN, &hidden_val,
828                                         DBUS_TYPE_INVALID);
829
830         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
831                                                 timeout) == FALSE ||
832                         agent->call == NULL)
833                 return -EIO;
834
835         agent->user_cb = cb;
836         agent->user_data = user_data;
837         agent->user_destroy = destroy;
838
839         dbus_pending_call_set_notify(agent->call, get_input_cb, agent, NULL);
840
841         return 0;
842 }
843
844 static void confirm_call_cb(DBusPendingCall *call, void *data)
845 {
846         struct stk_agent *agent = data;
847         stk_agent_confirmation_cb cb = agent->user_cb;
848         DBusMessage *reply = dbus_pending_call_steal_reply(call);
849         enum stk_agent_result result;
850         gboolean remove_agent;
851         dbus_bool_t confirm;
852
853         if (check_error(agent, reply,
854                         ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) {
855                 remove_agent = TRUE;
856                 goto error;
857         }
858
859         if (result != STK_AGENT_RESULT_OK) {
860                 cb(result, FALSE, agent->user_data);
861                 goto done;
862         }
863
864         if (dbus_message_get_args(reply, NULL,
865                                         DBUS_TYPE_BOOLEAN, &confirm,
866                                         DBUS_TYPE_INVALID) == FALSE) {
867                 ofono_error("Can't parse the reply to ConfirmCallSetup()");
868                 remove_agent = TRUE;
869                 goto error;
870         }
871
872         cb(result, confirm, agent->user_data);
873
874         CALLBACK_END();
875 }
876
877 int stk_agent_confirm_call(struct stk_agent *agent, const char *text,
878                                 const struct stk_icon_id *icon,
879                                 stk_agent_confirmation_cb cb,
880                                 void *user_data, ofono_destroy_func destroy,
881                                 int timeout)
882 {
883         DBusConnection *conn = ofono_dbus_get_connection();
884
885         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
886                                                         OFONO_SIM_APP_INTERFACE,
887                                                         "ConfirmCallSetup");
888         if (agent->msg == NULL)
889                 return -ENOMEM;
890
891         dbus_message_append_args(agent->msg,
892                                         DBUS_TYPE_STRING, &text,
893                                         DBUS_TYPE_BYTE, &icon->id,
894                                         DBUS_TYPE_INVALID);
895
896         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
897                                                 timeout) == FALSE ||
898                         agent->call == NULL)
899                 return -EIO;
900
901         agent->user_cb = cb;
902         agent->user_data = user_data;
903         agent->user_destroy = destroy;
904
905         dbus_pending_call_set_notify(agent->call, confirm_call_cb, agent, NULL);
906
907         return 0;
908 }
909
910 static void play_tone_cb(DBusPendingCall *call, void *data)
911 {
912         struct stk_agent *agent = data;
913         stk_agent_tone_cb cb = agent->user_cb;
914         DBusMessage *reply = dbus_pending_call_steal_reply(call);
915         enum stk_agent_result result;
916         gboolean remove_agent;
917
918         if (check_error(agent, reply,
919                         ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) {
920                 remove_agent = TRUE;
921                 goto error;
922         }
923
924         if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) {
925                 ofono_error("Can't parse the reply to PlayTone()");
926                 remove_agent = TRUE;
927                 goto error;
928         }
929
930         cb(result, agent->user_data);
931         goto done;
932
933         CALLBACK_END();
934 }
935
936 int stk_agent_play_tone(struct stk_agent *agent, const char *text,
937                         const struct stk_icon_id *icon, ofono_bool_t vibrate,
938                         const char *tone, stk_agent_tone_cb cb, void *user_data,
939                         ofono_destroy_func destroy, int timeout)
940 {
941         DBusConnection *conn = ofono_dbus_get_connection();
942
943         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
944                                                         OFONO_SIM_APP_INTERFACE,
945                                                         "PlayTone");
946         if (agent->msg == NULL)
947                 return -ENOMEM;
948
949         dbus_message_append_args(agent->msg,
950                                         DBUS_TYPE_STRING, &tone,
951                                         DBUS_TYPE_STRING, &text,
952                                         DBUS_TYPE_BYTE, &icon->id,
953                                         DBUS_TYPE_INVALID);
954
955         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
956                                                 timeout) == FALSE ||
957                         agent->call == NULL)
958                 return -EIO;
959
960         agent->user_cb = cb;
961         agent->user_data = user_data;
962         agent->user_destroy = destroy;
963
964         dbus_pending_call_set_notify(agent->call, play_tone_cb,
965                                         agent, NULL);
966
967         return 0;
968 }
969
970 int stk_agent_loop_tone(struct stk_agent *agent, const char *text,
971                         const struct stk_icon_id *icon, ofono_bool_t vibrate,
972                         const char *tone, stk_agent_tone_cb cb, void *user_data,
973                         ofono_destroy_func destroy, int timeout)
974 {
975         DBusConnection *conn = ofono_dbus_get_connection();
976
977         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
978                                                         OFONO_SIM_APP_INTERFACE,
979                                                         "LoopTone");
980         if (agent->msg == NULL)
981                 return -ENOMEM;
982
983         dbus_message_append_args(agent->msg,
984                                         DBUS_TYPE_STRING, &tone,
985                                         DBUS_TYPE_STRING, &text,
986                                         DBUS_TYPE_BYTE, &icon->id,
987                                         DBUS_TYPE_INVALID);
988
989         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
990                                                 timeout) == FALSE ||
991                         agent->call == NULL)
992                 return -EIO;
993
994         agent->user_cb = cb;
995         agent->user_data = user_data;
996         agent->user_destroy = destroy;
997
998         dbus_pending_call_set_notify(agent->call, play_tone_cb,
999                                         agent, NULL);
1000
1001         return 0;
1002 }
1003
1004 static void action_info_cb(DBusPendingCall *call, void *data)
1005 {
1006         struct stk_agent *agent = data;
1007         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1008         enum stk_agent_result result;
1009         gboolean remove_agent;
1010
1011         if (check_error(agent, reply, 0, &result) == -EINVAL) {
1012                 remove_agent = TRUE;
1013                 goto error;
1014         }
1015
1016         if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) {
1017                 ofono_error("Can't parse the reply to DisplayActionInfo()");
1018                 remove_agent = TRUE;
1019                 goto error;
1020         }
1021
1022         goto done;
1023
1024         CALLBACK_END();
1025 }
1026
1027 int stk_agent_display_action_info(struct stk_agent *agent, const char *text,
1028                                         const struct stk_icon_id *icon)
1029 {
1030         DBusConnection *conn = ofono_dbus_get_connection();
1031
1032         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
1033                                                 OFONO_SIM_APP_INTERFACE,
1034                                                 "DisplayActionInformation");
1035         if (agent->msg == NULL)
1036                 return -ENOMEM;
1037
1038         dbus_message_append_args(agent->msg,
1039                                         DBUS_TYPE_STRING, &text,
1040                                         DBUS_TYPE_BYTE, &icon->id,
1041                                         DBUS_TYPE_INVALID);
1042
1043         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
1044                                         DBUS_TIMEOUT_INFINITE) == FALSE ||
1045                         agent->call == NULL)
1046                 return -EIO;
1047
1048         dbus_pending_call_set_notify(agent->call, action_info_cb, agent, NULL);
1049
1050         return 0;
1051 }
1052
1053 static void confirm_launch_browser_cb(DBusPendingCall *call, void *data)
1054 {
1055         struct stk_agent *agent = data;
1056         stk_agent_confirmation_cb cb = agent->user_cb;
1057         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1058         enum stk_agent_result result;
1059         gboolean remove_agent;
1060         dbus_bool_t confirm;
1061
1062         if (check_error(agent, reply, 0, &result) == -EINVAL) {
1063                 remove_agent = TRUE;
1064                 cb(STK_AGENT_RESULT_TERMINATE, FALSE, agent->user_data);
1065                 goto error;
1066         }
1067
1068         if (result != STK_AGENT_RESULT_OK) {
1069                 cb(result, FALSE, agent->user_data);
1070                 goto done;
1071         }
1072
1073         if (dbus_message_get_args(reply, NULL,
1074                                         DBUS_TYPE_BOOLEAN, &confirm,
1075                                         DBUS_TYPE_INVALID) == FALSE) {
1076                 ofono_error("Can't parse the reply to ConfirmLaunchBrowser()");
1077                 remove_agent = TRUE;
1078                 goto error;
1079         }
1080
1081         cb(result, confirm, agent->user_data);
1082
1083         CALLBACK_END();
1084 }
1085
1086 int stk_agent_confirm_launch_browser(struct stk_agent *agent, const char *text,
1087                                         unsigned char icon_id, const char *url,
1088                                         stk_agent_confirmation_cb cb,
1089                                         void *user_data,
1090                                         ofono_destroy_func destroy, int timeout)
1091 {
1092         DBusConnection *conn = ofono_dbus_get_connection();
1093
1094         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
1095                                                         OFONO_SIM_APP_INTERFACE,
1096                                                         "ConfirmLaunchBrowser");
1097         if (agent->msg == NULL)
1098                 return -ENOMEM;
1099
1100         if (url == NULL)
1101                 url = "";
1102
1103         dbus_message_append_args(agent->msg,
1104                                         DBUS_TYPE_STRING, &text,
1105                                         DBUS_TYPE_BYTE, &icon_id,
1106                                         DBUS_TYPE_STRING, &url,
1107                                         DBUS_TYPE_INVALID);
1108
1109         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
1110                                                 timeout) == FALSE ||
1111                                                 agent->call == NULL)
1112                 return -EIO;
1113
1114         agent->user_cb = cb;
1115         agent->user_data = user_data;
1116         agent->user_destroy = destroy;
1117
1118         dbus_pending_call_set_notify(agent->call, confirm_launch_browser_cb,
1119                                         agent, NULL);
1120
1121         return 0;
1122 }
1123
1124 static void display_action_cb(DBusPendingCall *call, void *data)
1125 {
1126         struct stk_agent *agent = data;
1127         stk_agent_display_action_cb cb = agent->user_cb;
1128         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1129         enum stk_agent_result result;
1130         gboolean remove_agent;
1131
1132         if (check_error(agent, reply,
1133                         ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) {
1134                 remove_agent = TRUE;
1135                 goto error;
1136         }
1137
1138         if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) {
1139                 ofono_error("Can't parse the reply to DisplayAction()");
1140                 remove_agent = TRUE;
1141                 goto error;
1142         }
1143
1144         cb(result, agent->user_data);
1145         goto done;
1146
1147         CALLBACK_END();
1148 }
1149
1150 int stk_agent_display_action(struct stk_agent *agent,
1151                                         const char *text,
1152                                         const struct stk_icon_id *icon,
1153                                         stk_agent_display_action_cb cb,
1154                                         void *user_data,
1155                                         ofono_destroy_func destroy)
1156 {
1157         DBusConnection *conn = ofono_dbus_get_connection();
1158
1159         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
1160                                                 OFONO_SIM_APP_INTERFACE,
1161                                                 "DisplayAction");
1162         if (agent->msg == NULL)
1163                 return -ENOMEM;
1164
1165         dbus_message_append_args(agent->msg,
1166                                         DBUS_TYPE_STRING, &text,
1167                                         DBUS_TYPE_BYTE, &icon->id,
1168                                         DBUS_TYPE_INVALID);
1169
1170         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
1171                                         DBUS_TIMEOUT_INFINITE) == FALSE ||
1172                         agent->call == NULL)
1173                 return -EIO;
1174
1175         agent->user_cb = cb;
1176         agent->user_data = user_data;
1177         agent->user_destroy = destroy;
1178
1179         dbus_pending_call_set_notify(agent->call, display_action_cb,
1180                                         agent, NULL);
1181
1182         return 0;
1183 }
1184
1185 static void confirm_open_channel_cb(DBusPendingCall *call, void *data)
1186 {
1187         struct stk_agent *agent = data;
1188         stk_agent_confirmation_cb cb = agent->user_cb;
1189         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1190         enum stk_agent_result result;
1191         gboolean remove_agent;
1192         dbus_bool_t confirm;
1193
1194         if (check_error(agent, reply,
1195                         ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) {
1196                 remove_agent = TRUE;
1197                 goto error;
1198         }
1199
1200         if (result != STK_AGENT_RESULT_OK) {
1201                 cb(result, FALSE, agent->user_data);
1202                 goto done;
1203         }
1204
1205         if (dbus_message_get_args(reply, NULL,
1206                                         DBUS_TYPE_BOOLEAN, &confirm,
1207                                         DBUS_TYPE_INVALID) == FALSE) {
1208                 ofono_error("Can't parse the reply to ConfirmOpenChannel()");
1209                 remove_agent = TRUE;
1210                 goto error;
1211         }
1212
1213         cb(result, confirm, agent->user_data);
1214
1215         CALLBACK_END();
1216 }
1217
1218 int stk_agent_confirm_open_channel(struct stk_agent *agent, const char *text,
1219                                         const struct stk_icon_id *icon,
1220                                         stk_agent_confirmation_cb cb,
1221                                         void *user_data,
1222                                         ofono_destroy_func destroy, int timeout)
1223 {
1224         DBusConnection *conn = ofono_dbus_get_connection();
1225
1226         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
1227                                                         OFONO_SIM_APP_INTERFACE,
1228                                                         "ConfirmOpenChannel");
1229         if (agent->msg == NULL)
1230                 return -ENOMEM;
1231
1232         dbus_message_append_args(agent->msg,
1233                                         DBUS_TYPE_STRING, &text,
1234                                         DBUS_TYPE_BYTE, &icon->id,
1235                                         DBUS_TYPE_INVALID);
1236
1237         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
1238                                                 timeout) == FALSE ||
1239                                                 agent->call == NULL)
1240                 return -EIO;
1241
1242         agent->user_cb = cb;
1243         agent->user_data = user_data;
1244         agent->user_destroy = destroy;
1245
1246         dbus_pending_call_set_notify(agent->call, confirm_open_channel_cb,
1247                                         agent, NULL);
1248
1249         return 0;
1250 }