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