sim: Reset additional state info
[platform/upstream/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 static void get_key_cb(DBusPendingCall *call, void *data)
588 {
589         struct stk_agent *agent = data;
590         stk_agent_string_cb cb = agent->user_cb;
591         DBusMessage *reply = dbus_pending_call_steal_reply(call);
592         enum stk_agent_result result;
593         gboolean remove_agent;
594         char *key;
595
596         if (check_error(agent, reply,
597                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
598                         &result) == -EINVAL) {
599                 remove_agent = TRUE;
600                 goto error;
601         }
602
603         if (result != STK_AGENT_RESULT_OK) {
604                 cb(result, NULL, agent->user_data);
605                 goto done;
606         }
607
608         if (dbus_message_get_args(reply, NULL,
609                                         DBUS_TYPE_STRING, &key,
610                                         DBUS_TYPE_INVALID) == FALSE ||
611                         g_utf8_strlen(key, 10) != 1) {
612                 ofono_error("Can't parse the reply to GetKey()");
613                 remove_agent = TRUE;
614                 goto error;
615         }
616
617         cb(result, key, agent->user_data);
618
619         CALLBACK_END();
620 }
621
622 int stk_agent_request_key(struct stk_agent *agent, const char *text,
623                                 const struct stk_icon_id *icon,
624                                 ofono_bool_t unicode_charset,
625                                 stk_agent_string_cb cb, void *user_data,
626                                 ofono_destroy_func destroy, int timeout)
627 {
628         DBusConnection *conn = ofono_dbus_get_connection();
629
630         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
631                                                         OFONO_SIM_APP_INTERFACE,
632                                                         "RequestKey");
633         if (agent->msg == NULL)
634                 return -ENOMEM;
635
636         dbus_message_append_args(agent->msg,
637                                         DBUS_TYPE_STRING, &text,
638                                         DBUS_TYPE_BYTE, &icon->id,
639                                         DBUS_TYPE_INVALID);
640
641         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
642                                                 timeout) == FALSE ||
643                         agent->call == NULL)
644                 return -EIO;
645
646         agent->user_cb = cb;
647         agent->user_data = user_data;
648         agent->user_destroy = destroy;
649
650         dbus_pending_call_set_notify(agent->call, get_key_cb, agent, NULL);
651
652         return 0;
653 }
654
655 static void get_digits_cb(DBusPendingCall *call, void *data)
656 {
657         struct stk_agent *agent = data;
658         stk_agent_string_cb cb = agent->user_cb;
659         DBusMessage *reply = dbus_pending_call_steal_reply(call);
660         enum stk_agent_result result;
661         gboolean remove_agent;
662         char *string;
663
664         if (check_error(agent, reply,
665                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
666                         &result) == -EINVAL) {
667                 remove_agent = TRUE;
668                 goto error;
669         }
670
671         if (result != STK_AGENT_RESULT_OK) {
672                 cb(result, NULL, agent->user_data);
673                 goto done;
674         }
675
676         if (dbus_message_get_args(reply, NULL,
677                                         DBUS_TYPE_STRING, &string,
678                                         DBUS_TYPE_INVALID) == FALSE) {
679                 ofono_error("Can't parse the reply to GetDigits()");
680                 remove_agent = TRUE;
681                 goto error;
682         }
683
684         cb(result, string, agent->user_data);
685
686         CALLBACK_END();
687 }
688
689 int stk_agent_request_digits(struct stk_agent *agent, const char *text,
690                                 const struct stk_icon_id *icon,
691                                 const char *default_text,
692                                 int min, int max, ofono_bool_t hidden,
693                                 stk_agent_string_cb cb, void *user_data,
694                                 ofono_destroy_func destroy, int timeout)
695 {
696         DBusConnection *conn = ofono_dbus_get_connection();
697         uint8_t min_val = min;
698         uint8_t max_val = max;
699         dbus_bool_t hidden_val = hidden;
700
701         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
702                                                         OFONO_SIM_APP_INTERFACE,
703                                                         "RequestDigits");
704         if (agent->msg == NULL)
705                 return -ENOMEM;
706
707         if (default_text == NULL)
708                 default_text = "";
709
710         dbus_message_append_args(agent->msg,
711                                         DBUS_TYPE_STRING, &text,
712                                         DBUS_TYPE_BYTE, &icon->id,
713                                         DBUS_TYPE_STRING, &default_text,
714                                         DBUS_TYPE_BYTE, &min_val,
715                                         DBUS_TYPE_BYTE, &max_val,
716                                         DBUS_TYPE_BOOLEAN, &hidden_val,
717                                         DBUS_TYPE_INVALID);
718
719         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
720                                                 timeout) == FALSE ||
721                         agent->call == NULL)
722                 return -EIO;
723
724         agent->user_cb = cb;
725         agent->user_data = user_data;
726         agent->user_destroy = destroy;
727
728         dbus_pending_call_set_notify(agent->call, get_digits_cb, agent, NULL);
729
730         return 0;
731 }
732
733 static void get_input_cb(DBusPendingCall *call, void *data)
734 {
735         struct stk_agent *agent = data;
736         stk_agent_string_cb cb = agent->user_cb;
737         DBusMessage *reply = dbus_pending_call_steal_reply(call);
738         enum stk_agent_result result;
739         gboolean remove_agent;
740         char *string;
741
742         if (check_error(agent, reply,
743                         ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE,
744                         &result) == -EINVAL) {
745                 remove_agent = TRUE;
746                 goto error;
747         }
748
749         if (result != STK_AGENT_RESULT_OK) {
750                 cb(result, NULL, agent->user_data);
751                 goto done;
752         }
753
754         if (dbus_message_get_args(reply, NULL,
755                                         DBUS_TYPE_STRING, &string,
756                                         DBUS_TYPE_INVALID) == FALSE) {
757                 ofono_error("Can't parse the reply to GetInput()");
758                 remove_agent = TRUE;
759                 goto error;
760         }
761
762         cb(result, string, agent->user_data);
763
764         CALLBACK_END();
765 }
766
767 int stk_agent_request_input(struct stk_agent *agent, const char *text,
768                                 const struct stk_icon_id *icon,
769                                 const char *default_text,
770                                 ofono_bool_t unicode_charset, int min, int max,
771                                 ofono_bool_t hidden, stk_agent_string_cb cb,
772                                 void *user_data, ofono_destroy_func destroy,
773                                 int timeout)
774 {
775         DBusConnection *conn = ofono_dbus_get_connection();
776         uint8_t min_val = min;
777         uint8_t max_val = max;
778         dbus_bool_t hidden_val = hidden;
779
780         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
781                                                         OFONO_SIM_APP_INTERFACE,
782                                                         "RequestInput");
783         if (agent->msg == NULL)
784                 return -ENOMEM;
785
786         if (default_text == NULL)
787                 default_text = "";
788
789         dbus_message_append_args(agent->msg,
790                                         DBUS_TYPE_STRING, &text,
791                                         DBUS_TYPE_BYTE, &icon->id,
792                                         DBUS_TYPE_STRING, &default_text,
793                                         DBUS_TYPE_BYTE, &min_val,
794                                         DBUS_TYPE_BYTE, &max_val,
795                                         DBUS_TYPE_BOOLEAN, &hidden_val,
796                                         DBUS_TYPE_INVALID);
797
798         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
799                                                 timeout) == FALSE ||
800                         agent->call == NULL)
801                 return -EIO;
802
803         agent->user_cb = cb;
804         agent->user_data = user_data;
805         agent->user_destroy = destroy;
806
807         dbus_pending_call_set_notify(agent->call, get_input_cb, agent, NULL);
808
809         return 0;
810 }
811
812 static void confirm_call_cb(DBusPendingCall *call, void *data)
813 {
814         struct stk_agent *agent = data;
815         stk_agent_confirmation_cb cb = agent->user_cb;
816         DBusMessage *reply = dbus_pending_call_steal_reply(call);
817         enum stk_agent_result result;
818         gboolean remove_agent;
819         dbus_bool_t confirm;
820
821         if (check_error(agent, reply,
822                         ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) {
823                 remove_agent = TRUE;
824                 goto error;
825         }
826
827         if (result != STK_AGENT_RESULT_OK) {
828                 cb(result, FALSE, agent->user_data);
829                 goto done;
830         }
831
832         if (dbus_message_get_args(reply, NULL,
833                                         DBUS_TYPE_BOOLEAN, &confirm,
834                                         DBUS_TYPE_INVALID) == FALSE) {
835                 ofono_error("Can't parse the reply to ConfirmCallSetup()");
836                 remove_agent = TRUE;
837                 goto error;
838         }
839
840         cb(result, confirm, agent->user_data);
841
842         CALLBACK_END();
843 }
844
845 int stk_agent_confirm_call(struct stk_agent *agent, const char *text,
846                                 const struct stk_icon_id *icon,
847                                 stk_agent_confirmation_cb cb,
848                                 void *user_data, ofono_destroy_func destroy,
849                                 int timeout)
850 {
851         DBusConnection *conn = ofono_dbus_get_connection();
852
853         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
854                                                         OFONO_SIM_APP_INTERFACE,
855                                                         "ConfirmCallSetup");
856         if (agent->msg == NULL)
857                 return -ENOMEM;
858
859         dbus_message_append_args(agent->msg,
860                                         DBUS_TYPE_STRING, &text,
861                                         DBUS_TYPE_BYTE, &icon->id,
862                                         DBUS_TYPE_INVALID);
863
864         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
865                                                 timeout) == FALSE ||
866                         agent->call == NULL)
867                 return -EIO;
868
869         agent->user_cb = cb;
870         agent->user_data = user_data;
871         agent->user_destroy = destroy;
872
873         dbus_pending_call_set_notify(agent->call, confirm_call_cb, agent, NULL);
874
875         return 0;
876 }
877
878 static void play_tone_cb(DBusPendingCall *call, void *data)
879 {
880         struct stk_agent *agent = data;
881         stk_agent_tone_cb cb = agent->user_cb;
882         DBusMessage *reply = dbus_pending_call_steal_reply(call);
883         enum stk_agent_result result;
884         gboolean remove_agent;
885
886         if (check_error(agent, reply,
887                         ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) {
888                 remove_agent = TRUE;
889                 goto error;
890         }
891
892         if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) {
893                 ofono_error("Can't parse the reply to PlayTone()");
894                 remove_agent = TRUE;
895                 goto error;
896         }
897
898         cb(result, agent->user_data);
899         goto done;
900
901         CALLBACK_END();
902 }
903
904 int stk_agent_play_tone(struct stk_agent *agent, const char *text,
905                         const struct stk_icon_id *icon, ofono_bool_t vibrate,
906                         const char *tone, stk_agent_tone_cb cb, void *user_data,
907                         ofono_destroy_func destroy, int timeout)
908 {
909         DBusConnection *conn = ofono_dbus_get_connection();
910
911         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
912                                                         OFONO_SIM_APP_INTERFACE,
913                                                         "PlayTone");
914         if (agent->msg == NULL)
915                 return -ENOMEM;
916
917         dbus_message_append_args(agent->msg,
918                                         DBUS_TYPE_STRING, &tone,
919                                         DBUS_TYPE_STRING, &text,
920                                         DBUS_TYPE_BYTE, &icon->id,
921                                         DBUS_TYPE_INVALID);
922
923         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
924                                                 timeout) == FALSE ||
925                         agent->call == NULL)
926                 return -EIO;
927
928         agent->user_cb = cb;
929         agent->user_data = user_data;
930         agent->user_destroy = destroy;
931
932         dbus_pending_call_set_notify(agent->call, play_tone_cb,
933                                         agent, NULL);
934
935         return 0;
936 }
937
938 int stk_agent_loop_tone(struct stk_agent *agent, const char *text,
939                         const struct stk_icon_id *icon, ofono_bool_t vibrate,
940                         const char *tone, stk_agent_tone_cb cb, void *user_data,
941                         ofono_destroy_func destroy, int timeout)
942 {
943         DBusConnection *conn = ofono_dbus_get_connection();
944
945         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
946                                                         OFONO_SIM_APP_INTERFACE,
947                                                         "LoopTone");
948         if (agent->msg == NULL)
949                 return -ENOMEM;
950
951         dbus_message_append_args(agent->msg,
952                                         DBUS_TYPE_STRING, &tone,
953                                         DBUS_TYPE_STRING, &text,
954                                         DBUS_TYPE_BYTE, &icon->id,
955                                         DBUS_TYPE_INVALID);
956
957         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
958                                                 timeout) == FALSE ||
959                         agent->call == NULL)
960                 return -EIO;
961
962         agent->user_cb = cb;
963         agent->user_data = user_data;
964         agent->user_destroy = destroy;
965
966         dbus_pending_call_set_notify(agent->call, play_tone_cb,
967                                         agent, NULL);
968
969         return 0;
970 }
971
972 static void action_info_cb(DBusPendingCall *call, void *data)
973 {
974         struct stk_agent *agent = data;
975         DBusMessage *reply = dbus_pending_call_steal_reply(call);
976         enum stk_agent_result result;
977         gboolean remove_agent;
978
979         if (check_error(agent, reply, 0, &result) == -EINVAL) {
980                 remove_agent = TRUE;
981                 goto error;
982         }
983
984         if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) {
985                 ofono_error("Can't parse the reply to DisplayActionInfo()");
986                 remove_agent = TRUE;
987                 goto error;
988         }
989
990         goto done;
991
992         CALLBACK_END();
993 }
994
995 int stk_agent_display_action_info(struct stk_agent *agent, const char *text,
996                                         const struct stk_icon_id *icon)
997 {
998         DBusConnection *conn = ofono_dbus_get_connection();
999
1000         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
1001                                                 OFONO_SIM_APP_INTERFACE,
1002                                                 "DisplayActionInformation");
1003         if (agent->msg == NULL)
1004                 return -ENOMEM;
1005
1006         dbus_message_append_args(agent->msg,
1007                                         DBUS_TYPE_STRING, &text,
1008                                         DBUS_TYPE_BYTE, &icon->id,
1009                                         DBUS_TYPE_INVALID);
1010
1011         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
1012                                         DBUS_TIMEOUT_INFINITE) == FALSE ||
1013                         agent->call == NULL)
1014                 return -EIO;
1015
1016         dbus_pending_call_set_notify(agent->call, action_info_cb, agent, NULL);
1017
1018         return 0;
1019 }
1020
1021 static void confirm_launch_browser_cb(DBusPendingCall *call, void *data)
1022 {
1023         struct stk_agent *agent = data;
1024         stk_agent_confirmation_cb cb = agent->user_cb;
1025         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1026         enum stk_agent_result result;
1027         gboolean remove_agent;
1028         dbus_bool_t confirm;
1029
1030         if (check_error(agent, reply, 0, &result) == -EINVAL) {
1031                 remove_agent = TRUE;
1032                 cb(STK_AGENT_RESULT_TERMINATE, FALSE, agent->user_data);
1033                 goto error;
1034         }
1035
1036         if (result != STK_AGENT_RESULT_OK) {
1037                 cb(result, FALSE, agent->user_data);
1038                 goto done;
1039         }
1040
1041         if (dbus_message_get_args(reply, NULL,
1042                                         DBUS_TYPE_BOOLEAN, &confirm,
1043                                         DBUS_TYPE_INVALID) == FALSE) {
1044                 ofono_error("Can't parse the reply to ConfirmLaunchBrowser()");
1045                 remove_agent = TRUE;
1046                 goto error;
1047         }
1048
1049         cb(result, confirm, agent->user_data);
1050
1051         CALLBACK_END();
1052 }
1053
1054 int stk_agent_confirm_launch_browser(struct stk_agent *agent, const char *text,
1055                                         unsigned char icon_id, const char *url,
1056                                         stk_agent_confirmation_cb cb,
1057                                         void *user_data,
1058                                         ofono_destroy_func destroy, int timeout)
1059 {
1060         DBusConnection *conn = ofono_dbus_get_connection();
1061
1062         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
1063                                                         OFONO_SIM_APP_INTERFACE,
1064                                                         "ConfirmLaunchBrowser");
1065         if (agent->msg == NULL)
1066                 return -ENOMEM;
1067
1068         if (url == NULL)
1069                 url = "";
1070
1071         dbus_message_append_args(agent->msg,
1072                                         DBUS_TYPE_STRING, &text,
1073                                         DBUS_TYPE_BYTE, &icon_id,
1074                                         DBUS_TYPE_STRING, &url,
1075                                         DBUS_TYPE_INVALID);
1076
1077         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
1078                                                 timeout) == FALSE ||
1079                                                 agent->call == NULL)
1080                 return -EIO;
1081
1082         agent->user_cb = cb;
1083         agent->user_data = user_data;
1084         agent->user_destroy = destroy;
1085
1086         dbus_pending_call_set_notify(agent->call, confirm_launch_browser_cb,
1087                                         agent, NULL);
1088
1089         return 0;
1090 }
1091
1092 static void display_action_cb(DBusPendingCall *call, void *data)
1093 {
1094         struct stk_agent *agent = data;
1095         stk_agent_display_action_cb cb = agent->user_cb;
1096         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1097         enum stk_agent_result result;
1098         gboolean remove_agent;
1099
1100         if (check_error(agent, reply,
1101                         ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) {
1102                 remove_agent = TRUE;
1103                 goto error;
1104         }
1105
1106         if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) {
1107                 ofono_error("Can't parse the reply to DisplayAction()");
1108                 remove_agent = TRUE;
1109                 goto error;
1110         }
1111
1112         cb(result, agent->user_data);
1113         goto done;
1114
1115         CALLBACK_END();
1116 }
1117
1118 int stk_agent_display_action(struct stk_agent *agent,
1119                                         const char *text,
1120                                         const struct stk_icon_id *icon,
1121                                         stk_agent_display_action_cb cb,
1122                                         void *user_data,
1123                                         ofono_destroy_func destroy)
1124 {
1125         DBusConnection *conn = ofono_dbus_get_connection();
1126
1127         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
1128                                                 OFONO_SIM_APP_INTERFACE,
1129                                                 "DisplayAction");
1130         if (agent->msg == NULL)
1131                 return -ENOMEM;
1132
1133         dbus_message_append_args(agent->msg,
1134                                         DBUS_TYPE_STRING, &text,
1135                                         DBUS_TYPE_BYTE, &icon->id,
1136                                         DBUS_TYPE_INVALID);
1137
1138         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
1139                                         DBUS_TIMEOUT_INFINITE) == FALSE ||
1140                         agent->call == NULL)
1141                 return -EIO;
1142
1143         agent->user_cb = cb;
1144         agent->user_data = user_data;
1145         agent->user_destroy = destroy;
1146
1147         dbus_pending_call_set_notify(agent->call, display_action_cb,
1148                                         agent, NULL);
1149
1150         return 0;
1151 }
1152
1153 static void confirm_open_channel_cb(DBusPendingCall *call, void *data)
1154 {
1155         struct stk_agent *agent = data;
1156         stk_agent_confirmation_cb cb = agent->user_cb;
1157         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1158         enum stk_agent_result result;
1159         gboolean remove_agent;
1160         dbus_bool_t confirm;
1161
1162         if (check_error(agent, reply,
1163                         ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) {
1164                 remove_agent = TRUE;
1165                 goto error;
1166         }
1167
1168         if (result != STK_AGENT_RESULT_OK) {
1169                 cb(result, FALSE, agent->user_data);
1170                 goto done;
1171         }
1172
1173         if (dbus_message_get_args(reply, NULL,
1174                                         DBUS_TYPE_BOOLEAN, &confirm,
1175                                         DBUS_TYPE_INVALID) == FALSE) {
1176                 ofono_error("Can't parse the reply to ConfirmOpenChannel()");
1177                 remove_agent = TRUE;
1178                 goto error;
1179         }
1180
1181         cb(result, confirm, agent->user_data);
1182
1183         CALLBACK_END();
1184 }
1185
1186 int stk_agent_confirm_open_channel(struct stk_agent *agent, const char *text,
1187                                         const struct stk_icon_id *icon,
1188                                         stk_agent_confirmation_cb cb,
1189                                         void *user_data,
1190                                         ofono_destroy_func destroy, int timeout)
1191 {
1192         DBusConnection *conn = ofono_dbus_get_connection();
1193
1194         agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
1195                                                         OFONO_SIM_APP_INTERFACE,
1196                                                         "ConfirmOpenChannel");
1197         if (agent->msg == NULL)
1198                 return -ENOMEM;
1199
1200         dbus_message_append_args(agent->msg,
1201                                         DBUS_TYPE_STRING, &text,
1202                                         DBUS_TYPE_BYTE, &icon->id,
1203                                         DBUS_TYPE_INVALID);
1204
1205         if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call,
1206                                                 timeout) == FALSE ||
1207                                                 agent->call == NULL)
1208                 return -EIO;
1209
1210         agent->user_cb = cb;
1211         agent->user_data = user_data;
1212         agent->user_destroy = destroy;
1213
1214         dbus_pending_call_set_notify(agent->call, confirm_open_channel_cb,
1215                                         agent, NULL);
1216
1217         return 0;
1218 }