74888b2e187b0783b81a04d04355815fe04fcdaa
[profile/ivi/ofono.git] / src / ussd.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 <string.h>
28 #include <stdio.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 "util.h"
39
40 #define MAX_USSD_LENGTH 160
41
42 static GSList *g_drivers = NULL;
43
44 enum ussd_state {
45         USSD_STATE_IDLE = 0,
46         USSD_STATE_ACTIVE = 1,
47         USSD_STATE_USER_ACTION = 2,
48         USSD_STATE_RESPONSE_SENT,
49 };
50
51 struct ussd_request {
52         ofono_ussd_request_cb_t cb;
53         void *user_data;
54 };
55
56 struct ofono_ussd {
57         int state;
58         DBusMessage *pending;
59         DBusMessage *cancel;
60         int flags;
61         GSList *ss_control_list;
62         GSList *ss_passwd_list;
63         const struct ofono_ussd_driver *driver;
64         void *driver_data;
65         struct ofono_atom *atom;
66         struct ussd_request *req;
67 };
68
69 struct ssc_entry {
70         char *service;
71         void *cb;
72         void *user;
73         ofono_destroy_func destroy;
74 };
75
76 gboolean __ofono_ussd_is_busy(struct ofono_ussd *ussd)
77 {
78         if (ussd == NULL)
79                 return FALSE;
80
81         if (ussd->pending || ussd->state != USSD_STATE_IDLE || ussd->req)
82                 return TRUE;
83
84         return FALSE;
85 }
86
87 static struct ssc_entry *ssc_entry_create(const char *sc, void *cb, void *data,
88                                                 ofono_destroy_func destroy)
89 {
90         struct ssc_entry *r;
91
92         r = g_try_new0(struct ssc_entry, 1);
93
94         if (r == NULL)
95                 return r;
96
97         r->service = g_strdup(sc);
98         r->cb = cb;
99         r->user = data;
100         r->destroy = destroy;
101
102         return r;
103 }
104
105 static void ssc_entry_destroy(struct ssc_entry *ca)
106 {
107         if (ca->destroy)
108                 ca->destroy(ca->user);
109
110         g_free(ca->service);
111         g_free(ca);
112 }
113
114 static gint ssc_entry_find_by_service(gconstpointer a, gconstpointer b)
115 {
116         const struct ssc_entry *ca = a;
117
118         return strcmp(ca->service, b);
119 }
120
121 gboolean __ofono_ussd_ssc_register(struct ofono_ussd *ussd, const char *sc,
122                                         ofono_ussd_ssc_cb_t cb, void *data,
123                                         ofono_destroy_func destroy)
124 {
125         struct ssc_entry *entry;
126
127         if (ussd == NULL)
128                 return FALSE;
129
130         entry = ssc_entry_create(sc, cb, data, destroy);
131         if (entry == NULL)
132                 return FALSE;
133
134         ussd->ss_control_list = g_slist_prepend(ussd->ss_control_list, entry);
135
136         return TRUE;
137 }
138
139 void __ofono_ussd_ssc_unregister(struct ofono_ussd *ussd, const char *sc)
140 {
141         GSList *l;
142
143         if (ussd == NULL)
144                 return;
145
146         l = g_slist_find_custom(ussd->ss_control_list, sc,
147                                 ssc_entry_find_by_service);
148
149         if (l == NULL)
150                 return;
151
152         ssc_entry_destroy(l->data);
153         ussd->ss_control_list = g_slist_remove(ussd->ss_control_list, l->data);
154 }
155
156 gboolean __ofono_ussd_passwd_register(struct ofono_ussd *ussd, const char *sc,
157                                         ofono_ussd_passwd_cb_t cb, void *data,
158                                         ofono_destroy_func destroy)
159 {
160         struct ssc_entry *entry;
161
162         if (ussd == NULL)
163                 return FALSE;
164
165         entry = ssc_entry_create(sc, cb, data, destroy);
166         if (entry == NULL)
167                 return FALSE;
168
169         ussd->ss_passwd_list = g_slist_prepend(ussd->ss_passwd_list, entry);
170
171         return TRUE;
172 }
173
174 void __ofono_ussd_passwd_unregister(struct ofono_ussd *ussd, const char *sc)
175 {
176         GSList *l;
177
178         if (ussd == NULL)
179                 return;
180
181         l = g_slist_find_custom(ussd->ss_passwd_list, sc,
182                                 ssc_entry_find_by_service);
183
184         if (l == NULL)
185                 return;
186
187         ssc_entry_destroy(l->data);
188         ussd->ss_passwd_list = g_slist_remove(ussd->ss_passwd_list, l->data);
189 }
190
191 static gboolean recognized_passwd_change_string(struct ofono_ussd *ussd,
192                                                 int type, char *sc,
193                                                 char *sia, char *sib,
194                                                 char *sic, char *sid,
195                                                 char *dn, DBusMessage *msg)
196 {
197         GSList *l = ussd->ss_passwd_list;
198
199         switch (type) {
200         case SS_CONTROL_TYPE_ACTIVATION:
201         case SS_CONTROL_TYPE_REGISTRATION:
202                 break;
203
204         default:
205                 return FALSE;
206         }
207
208         if (strcmp(sc, "03") || strlen(dn))
209                 return FALSE;
210
211         /* If SIC & SID don't match, then we just bail out here */
212         if (strcmp(sic, sid)) {
213                 DBusConnection *conn = ofono_dbus_get_connection();
214                 DBusMessage *reply = __ofono_error_invalid_format(msg);
215                 g_dbus_send_message(conn, reply);
216                 return TRUE;
217         }
218
219         while ((l = g_slist_find_custom(l, sia,
220                         ssc_entry_find_by_service)) != NULL) {
221                 struct ssc_entry *entry = l->data;
222                 ofono_ussd_passwd_cb_t cb = entry->cb;
223
224                 if (cb(sia, sib, sic, msg, entry->user))
225                         return TRUE;
226
227                 l = l->next;
228         }
229
230         return FALSE;
231 }
232
233 static gboolean recognized_control_string(struct ofono_ussd *ussd,
234                                                 const char *ss_str,
235                                                 DBusMessage *msg)
236 {
237         char *str = g_strdup(ss_str);
238         char *sc, *sia, *sib, *sic, *sid, *dn;
239         int type;
240         gboolean ret = FALSE;
241
242         DBG("parsing control string");
243
244         if (parse_ss_control_string(str, &type, &sc,
245                                 &sia, &sib, &sic, &sid, &dn)) {
246                 GSList *l = ussd->ss_control_list;
247
248                 DBG("Got parse result: %d, %s, %s, %s, %s, %s, %s",
249                                 type, sc, sia, sib, sic, sid, dn);
250
251                 /*
252                  * A password change string needs to be treated separately
253                  * because it uses a fourth SI and is thus not a valid
254                  * control string.
255                  */
256                 if (recognized_passwd_change_string(ussd, type, sc,
257                                         sia, sib, sic, sid, dn, msg)) {
258                         ret = TRUE;
259                         goto out;
260                 }
261
262                 if (*sid != '\0')
263                         goto out;
264
265                 while ((l = g_slist_find_custom(l, sc,
266                                 ssc_entry_find_by_service)) != NULL) {
267                         struct ssc_entry *entry = l->data;
268                         ofono_ussd_ssc_cb_t cb = entry->cb;
269
270                         if (cb(type, sc, sia, sib, sic, dn, msg, entry->user)) {
271                                 ret = TRUE;
272                                 goto out;
273                         }
274
275                         l = l->next;
276                 }
277
278         }
279
280         /* TODO: Handle all strings that control voice calls */
281
282         /* TODO: Handle Multiple subscriber profile DN*59#SEND and *59#SEND */
283
284         /*
285          * Note: SIM PIN/PIN2 change and unblock and IMEI presentation
286          * procedures are not handled by the daemon since they are not followed
287          * by SEND and are not valid USSD requests.
288          */
289
290 out:
291         g_free(str);
292
293         return ret;
294 }
295
296 static const char *ussd_get_state_string(struct ofono_ussd *ussd)
297 {
298         switch (ussd->state) {
299         case USSD_STATE_IDLE:
300                 return "idle";
301         case USSD_STATE_ACTIVE:
302         case USSD_STATE_RESPONSE_SENT:
303                 return "active";
304         case USSD_STATE_USER_ACTION:
305                 return "user-response";
306         }
307
308         return "";
309 }
310
311 static void ussd_change_state(struct ofono_ussd *ussd, int state)
312 {
313         const char *value;
314         DBusConnection *conn = ofono_dbus_get_connection();
315         const char *path = __ofono_atom_get_path(ussd->atom);
316
317         if (state == ussd->state)
318                 return;
319
320         ussd->state = state;
321
322         value = ussd_get_state_string(ussd);
323         ofono_dbus_signal_property_changed(conn, path,
324                         OFONO_SUPPLEMENTARY_SERVICES_INTERFACE,
325                         "State", DBUS_TYPE_STRING, &value);
326 }
327
328 static void ussd_request_finish(struct ofono_ussd *ussd, int error, int dcs,
329                                 const unsigned char *pdu, int len)
330 {
331         struct ussd_request *req = ussd->req;
332
333         if (req && req->cb)
334                 req->cb(error, dcs, pdu, len, req->user_data);
335
336         g_free(req);
337         ussd->req = NULL;
338 }
339
340 static int ussd_status_to_failure_code(int status)
341 {
342         switch (status) {
343         case OFONO_USSD_STATUS_TIMED_OUT:
344                 return -ETIMEDOUT;
345         case OFONO_USSD_STATUS_NOT_SUPPORTED:
346                 return -ENOSYS;
347         }
348
349         return 0;
350 }
351
352 static char const *ussd_status_name(int status)
353 {
354         switch (status) {
355         case OFONO_USSD_STATUS_NOTIFY:
356                 return "NOTIFY";
357         case OFONO_USSD_STATUS_ACTION_REQUIRED:
358                 return "ACTION_REQUIRED";
359         case OFONO_USSD_STATUS_TERMINATED:
360                 return "TERMINATED";
361         case OFONO_USSD_STATUS_LOCAL_CLIENT_RESPONDED:
362                 return "LOCAL_CLIENT_RESPONDED";
363         case OFONO_USSD_STATUS_NOT_SUPPORTED:
364                 return "NOT_SUPPORTED";
365         case OFONO_USSD_STATUS_TIMED_OUT:
366                 return "TIMED_OUT";
367         }
368
369         return "????";
370 }
371
372 static const char *ussd_state_name(enum ussd_state state)
373 {
374         switch (state) {
375         case USSD_STATE_IDLE:
376                 return "IDLE";
377         case USSD_STATE_ACTIVE:
378                 return "ACTIVE";
379         case USSD_STATE_RESPONSE_SENT:
380                 return "RESPONSE_SENT";
381         case USSD_STATE_USER_ACTION:
382                 return "USER_ACTION";
383         }
384
385         return "????";
386 }
387
388
389 void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs,
390                         const unsigned char *data, int data_len)
391 {
392         DBusConnection *conn = ofono_dbus_get_connection();
393         const char *ussdstr = "USSD";
394         char *utf8_str = NULL;
395         const char *str;
396         const char sig[] = { DBUS_TYPE_STRING, 0 };
397         DBusMessage *reply;
398         DBusMessageIter iter;
399         DBusMessageIter variant;
400
401         DBG("status: %d %s, state: %d %s",
402                 status, ussd_status_name(status),
403                 ussd->state, ussd_state_name(ussd->state));
404
405         if (ussd->req &&
406                         (status == OFONO_USSD_STATUS_NOTIFY ||
407                         status == OFONO_USSD_STATUS_TERMINATED ||
408                         status == OFONO_USSD_STATUS_TIMED_OUT ||
409                         status == OFONO_USSD_STATUS_NOT_SUPPORTED)) {
410                 ussd_request_finish(ussd, ussd_status_to_failure_code(status),
411                                         dcs, data, data_len);
412
413                 ussd_change_state(ussd, USSD_STATE_IDLE);
414                 return;
415         }
416
417         if (status == OFONO_USSD_STATUS_NOT_SUPPORTED) {
418                 ussd_change_state(ussd, USSD_STATE_IDLE);
419
420                 if (ussd->pending == NULL)
421                         return;
422
423                 reply = __ofono_error_not_supported(ussd->pending);
424                 goto out;
425         }
426
427         if (status == OFONO_USSD_STATUS_TIMED_OUT) {
428                 ussd_change_state(ussd, USSD_STATE_IDLE);
429
430                 if (ussd->pending == NULL)
431                         return;
432
433                 reply = __ofono_error_timed_out(ussd->pending);
434                 goto out;
435         }
436
437         if (data && data_len > 0)
438                 utf8_str = ussd_decode(dcs, data_len, data);
439
440         str = utf8_str;
441
442         /* TODO: Rework this in the Agent framework */
443         if (ussd->state == USSD_STATE_ACTIVE) {
444
445                 reply = dbus_message_new_method_return(ussd->pending);
446
447                 if (str == NULL)
448                         str = "";
449
450                 dbus_message_iter_init_append(reply, &iter);
451
452                 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
453                                                 &ussdstr);
454
455                 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, sig,
456                                                         &variant);
457
458                 dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING,
459                                                 &str);
460
461                 dbus_message_iter_close_container(&iter, &variant);
462
463                 if (status == OFONO_USSD_STATUS_ACTION_REQUIRED)
464                         ussd_change_state(ussd, USSD_STATE_USER_ACTION);
465                 else
466                         ussd_change_state(ussd, USSD_STATE_IDLE);
467
468         } else if (ussd->state == USSD_STATE_RESPONSE_SENT) {
469                 reply = dbus_message_new_method_return(ussd->pending);
470
471                 if (str == NULL)
472                         str = "";
473
474                 dbus_message_append_args(reply, DBUS_TYPE_STRING, &str,
475                                                 DBUS_TYPE_INVALID);
476
477                 if (status == OFONO_USSD_STATUS_ACTION_REQUIRED)
478                         ussd_change_state(ussd, USSD_STATE_USER_ACTION);
479                 else
480                         ussd_change_state(ussd, USSD_STATE_IDLE);
481         } else if (ussd->state == USSD_STATE_IDLE) {
482                 const char *signal_name;
483                 const char *path = __ofono_atom_get_path(ussd->atom);
484                 int new_state;
485
486                 if (status == OFONO_USSD_STATUS_ACTION_REQUIRED) {
487                         new_state = USSD_STATE_USER_ACTION;
488                         signal_name = "RequestReceived";
489                 } else {
490                         new_state = USSD_STATE_IDLE;
491                         signal_name = "NotificationReceived";
492                 }
493
494                 if (str == NULL)
495                         str = "";
496
497                 g_dbus_emit_signal(conn, path,
498                         OFONO_SUPPLEMENTARY_SERVICES_INTERFACE, signal_name,
499                                 DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
500
501                 ussd_change_state(ussd, new_state);
502                 goto free;
503         } else {
504                 ofono_error("Received an unsolicited USSD but can't handle.");
505                 DBG("USSD is: status: %d, %s", status, str);
506
507                 goto free;
508         }
509
510 out:
511         g_dbus_send_message(conn, reply);
512
513         dbus_message_unref(ussd->pending);
514         ussd->pending = NULL;
515
516 free:
517         g_free(utf8_str);
518 }
519
520 static void ussd_callback(const struct ofono_error *error, void *data)
521 {
522         struct ofono_ussd *ussd = data;
523         DBusMessage *reply;
524
525         if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
526                 DBG("ussd request failed with error: %s",
527                                 telephony_error_to_str(error));
528
529         if (error->type == OFONO_ERROR_TYPE_NO_ERROR) {
530                 ussd_change_state(ussd, USSD_STATE_ACTIVE);
531                 return;
532         }
533
534         if (ussd->pending == NULL)
535                 return;
536
537         reply = __ofono_error_failed(ussd->pending);
538         __ofono_dbus_pending_reply(&ussd->pending, reply);
539 }
540
541 static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg,
542                                         void *data)
543 {
544         struct ofono_ussd *ussd = data;
545         struct ofono_modem *modem = __ofono_atom_get_modem(ussd->atom);
546         struct ofono_voicecall *vc;
547         gboolean call_in_progress;
548         const char *str;
549         int dcs = 0x0f;
550         unsigned char buf[160];
551         long num_packed;
552
553         if (__ofono_ussd_is_busy(ussd))
554                 return __ofono_error_busy(msg);
555
556         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
557                                         DBUS_TYPE_INVALID) == FALSE)
558                 return __ofono_error_invalid_args(msg);
559
560         if (strlen(str) == 0)
561                 return __ofono_error_invalid_format(msg);
562
563         DBG("checking if this is a recognized control string");
564         if (recognized_control_string(ussd, str, msg))
565                 return NULL;
566
567         vc = __ofono_atom_find(OFONO_ATOM_TYPE_VOICECALL, modem);
568         if (vc)
569                 call_in_progress = __ofono_voicecall_is_busy(vc,
570                                         OFONO_VOICECALL_INTERACTION_NONE);
571         else
572                 call_in_progress = FALSE;
573
574         DBG("No.., checking if this is a USSD string");
575         if (!valid_ussd_string(str, call_in_progress))
576                 return __ofono_error_not_recognized(msg);
577
578         if (!ussd_encode(str, &num_packed, buf))
579                 return __ofono_error_invalid_format(msg);
580
581         if (ussd->driver->request == NULL)
582                 return __ofono_error_not_implemented(msg);
583
584         DBG("OK, running USSD request");
585
586         ussd->pending = dbus_message_ref(msg);
587
588         ussd->driver->request(ussd, dcs, buf, num_packed, ussd_callback, ussd);
589
590         return NULL;
591 }
592
593 static void ussd_response_callback(const struct ofono_error *error, void *data)
594 {
595         struct ofono_ussd *ussd = data;
596         DBusMessage *reply;
597
598         if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
599                 DBG("ussd response failed with error: %s",
600                                 telephony_error_to_str(error));
601
602         if (error->type == OFONO_ERROR_TYPE_NO_ERROR) {
603                 ussd_change_state(ussd, USSD_STATE_RESPONSE_SENT);
604                 return;
605         }
606
607         if (ussd->pending == NULL)
608                 return;
609
610         reply = __ofono_error_failed(ussd->pending);
611         __ofono_dbus_pending_reply(&ussd->pending, reply);
612 }
613
614 static DBusMessage *ussd_respond(DBusConnection *conn, DBusMessage *msg,
615                                         void *data)
616 {
617         struct ofono_ussd *ussd = data;
618         const char *str;
619         int dcs = 0x0f;
620         unsigned char buf[160];
621         long num_packed;
622
623         if (ussd->pending)
624                 return __ofono_error_busy(msg);
625
626         if (ussd->state != USSD_STATE_USER_ACTION)
627                 return __ofono_error_not_active(msg);
628
629         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
630                                         DBUS_TYPE_INVALID) == FALSE)
631                 return __ofono_error_invalid_args(msg);
632
633         if (strlen(str) == 0)
634                 return __ofono_error_invalid_format(msg);
635
636         if (!ussd_encode(str, &num_packed, buf))
637                 return __ofono_error_invalid_format(msg);
638
639         if (ussd->driver->request == NULL)
640                 return __ofono_error_not_implemented(msg);
641
642         ussd->pending = dbus_message_ref(msg);
643
644         ussd->driver->request(ussd, dcs, buf, num_packed,
645                                 ussd_response_callback, ussd);
646
647         return NULL;
648 }
649
650 static void ussd_cancel_callback(const struct ofono_error *error, void *data)
651 {
652         struct ofono_ussd *ussd = data;
653         DBusMessage *reply;
654
655         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
656                 DBG("ussd cancel failed with error: %s",
657                                 telephony_error_to_str(error));
658
659                 reply = __ofono_error_failed(ussd->cancel);
660                 __ofono_dbus_pending_reply(&ussd->cancel, reply);
661
662                 return;
663         }
664
665         if (ussd->pending) {
666                 reply = __ofono_error_canceled(ussd->pending);
667                 __ofono_dbus_pending_reply(&ussd->pending, reply);
668         }
669
670         reply = dbus_message_new_method_return(ussd->cancel);
671         __ofono_dbus_pending_reply(&ussd->cancel, reply);
672
673         if (ussd->req)
674                 ussd_request_finish(ussd, -ECANCELED, 0, NULL, 0);
675
676         ussd_change_state(ussd, USSD_STATE_IDLE);
677 }
678
679 static DBusMessage *ussd_cancel(DBusConnection *conn, DBusMessage *msg,
680                                         void *data)
681 {
682         struct ofono_ussd *ussd = data;
683
684         if (ussd->state == USSD_STATE_IDLE)
685                 return __ofono_error_not_active(msg);
686
687         /* We have called Respond() but not returned from its callback yet */
688         if (ussd->state == USSD_STATE_USER_ACTION && ussd->pending)
689                 return __ofono_error_busy(msg);
690
691         if (ussd->cancel)
692                 return __ofono_error_busy(msg);
693
694         if (ussd->driver->cancel == NULL)
695                 return __ofono_error_not_implemented(msg);
696
697         ussd->cancel = dbus_message_ref(msg);
698
699         ussd->driver->cancel(ussd, ussd_cancel_callback, ussd);
700
701         return NULL;
702 }
703
704 static DBusMessage *ussd_get_properties(DBusConnection *conn,
705                                         DBusMessage *msg, void *data)
706 {
707         struct ofono_ussd *ussd = data;
708         DBusMessage *reply;
709         DBusMessageIter iter;
710         DBusMessageIter dict;
711         const char *value;
712
713         reply = dbus_message_new_method_return(msg);
714         if (reply == NULL)
715                 return NULL;
716
717         dbus_message_iter_init_append(reply, &iter);
718
719         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
720                                         OFONO_PROPERTIES_ARRAY_SIGNATURE,
721                                         &dict);
722
723         value = ussd_get_state_string(ussd);
724         ofono_dbus_dict_append(&dict, "State", DBUS_TYPE_STRING, &value);
725
726         dbus_message_iter_close_container(&iter, &dict);
727
728         return reply;
729 }
730
731 static const GDBusMethodTable ussd_methods[] = {
732         { GDBUS_ASYNC_METHOD("Initiate",
733                         GDBUS_ARGS({ "command", "s" }),
734                         GDBUS_ARGS({ "result_name", "s" }, { "value", "v" }),
735                         ussd_initiate) },
736         { GDBUS_ASYNC_METHOD("Respond",
737                         GDBUS_ARGS({ "reply", "s" }),
738                         GDBUS_ARGS({ "result", "s" }),
739                         ussd_respond) },
740         { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL, ussd_cancel) },
741         { GDBUS_METHOD("GetProperties",
742                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
743                         ussd_get_properties) },
744         { }
745 };
746
747 static const GDBusSignalTable ussd_signals[] = {
748         { GDBUS_SIGNAL("NotificationReceived",
749                                         GDBUS_ARGS({ "message", "s" })) },
750         { GDBUS_SIGNAL("RequestReceived",
751                                         GDBUS_ARGS({ "message", "s" })) },
752         { GDBUS_SIGNAL("PropertyChanged",
753                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
754         { }
755 };
756
757 int ofono_ussd_driver_register(const struct ofono_ussd_driver *d)
758 {
759         DBG("driver: %p, name: %s", d, d->name);
760
761         if (d->probe == NULL)
762                 return -EINVAL;
763
764         g_drivers = g_slist_prepend(g_drivers, (void *) d);
765
766         return 0;
767 }
768
769 void ofono_ussd_driver_unregister(const struct ofono_ussd_driver *d)
770 {
771         DBG("driver: %p, name: %s", d, d->name);
772
773         g_drivers = g_slist_remove(g_drivers, (void *) d);
774 }
775
776 static void ussd_unregister(struct ofono_atom *atom)
777 {
778         struct ofono_ussd *ussd = __ofono_atom_get_data(atom);
779         DBusConnection *conn = ofono_dbus_get_connection();
780         struct ofono_modem *modem = __ofono_atom_get_modem(atom);
781         const char *path = __ofono_atom_get_path(atom);
782
783         g_slist_foreach(ussd->ss_control_list, (GFunc) ssc_entry_destroy, NULL);
784         g_slist_free(ussd->ss_control_list);
785         ussd->ss_control_list = NULL;
786
787         g_slist_foreach(ussd->ss_passwd_list, (GFunc) ssc_entry_destroy, NULL);
788         g_slist_free(ussd->ss_passwd_list);
789         ussd->ss_passwd_list = NULL;
790
791         ofono_modem_remove_interface(modem,
792                                         OFONO_SUPPLEMENTARY_SERVICES_INTERFACE);
793         g_dbus_unregister_interface(conn, path,
794                                         OFONO_SUPPLEMENTARY_SERVICES_INTERFACE);
795 }
796
797 static void ussd_remove(struct ofono_atom *atom)
798 {
799         struct ofono_ussd *ussd = __ofono_atom_get_data(atom);
800
801         DBG("atom: %p", atom);
802
803         if (ussd == NULL)
804                 return;
805
806         if (ussd->driver && ussd->driver->remove)
807                 ussd->driver->remove(ussd);
808
809         g_free(ussd);
810 }
811
812 struct ofono_ussd *ofono_ussd_create(struct ofono_modem *modem,
813                                         unsigned int vendor,
814                                         const char *driver,
815                                         void *data)
816 {
817         struct ofono_ussd *ussd;
818         GSList *l;
819
820         if (driver == NULL)
821                 return NULL;
822
823         ussd = g_try_new0(struct ofono_ussd, 1);
824
825         if (ussd == NULL)
826                 return NULL;
827
828         ussd->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_USSD,
829                                                 ussd_remove, ussd);
830
831         for (l = g_drivers; l; l = l->next) {
832                 const struct ofono_ussd_driver *drv = l->data;
833
834                 if (g_strcmp0(drv->name, driver))
835                         continue;
836
837                 if (drv->probe(ussd, vendor, data) < 0)
838                         continue;
839
840                 ussd->driver = drv;
841                 break;
842         }
843
844         return ussd;
845 }
846
847 void ofono_ussd_register(struct ofono_ussd *ussd)
848 {
849         DBusConnection *conn = ofono_dbus_get_connection();
850         struct ofono_modem *modem = __ofono_atom_get_modem(ussd->atom);
851         const char *path = __ofono_atom_get_path(ussd->atom);
852
853         if (!g_dbus_register_interface(conn, path,
854                                         OFONO_SUPPLEMENTARY_SERVICES_INTERFACE,
855                                         ussd_methods, ussd_signals, NULL,
856                                         ussd, NULL)) {
857                 ofono_error("Could not create %s interface",
858                                 OFONO_SUPPLEMENTARY_SERVICES_INTERFACE);
859
860                 return;
861         }
862
863         ofono_modem_add_interface(modem,
864                                 OFONO_SUPPLEMENTARY_SERVICES_INTERFACE);
865
866         __ofono_atom_register(ussd->atom, ussd_unregister);
867 }
868
869 void ofono_ussd_remove(struct ofono_ussd *ussd)
870 {
871         __ofono_atom_free(ussd->atom);
872 }
873
874 void ofono_ussd_set_data(struct ofono_ussd *ussd, void *data)
875 {
876         ussd->driver_data = data;
877 }
878
879 void *ofono_ussd_get_data(struct ofono_ussd *ussd)
880 {
881         return ussd->driver_data;
882 }
883
884 static void ussd_request_callback(const struct ofono_error *error, void *data)
885 {
886         struct ofono_ussd *ussd = data;
887
888         if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
889                 ussd_request_finish(ussd, -EINVAL, 0, NULL, 0);
890         else
891                 ussd_change_state(ussd, USSD_STATE_ACTIVE);
892 }
893
894 int __ofono_ussd_initiate(struct ofono_ussd *ussd, int dcs,
895                                 const unsigned char *pdu, int len,
896                                 ofono_ussd_request_cb_t cb, void *user_data)
897 {
898         struct ussd_request *req;
899
900         if (ussd->driver->request == NULL)
901                 return -ENOSYS;
902
903         if (__ofono_ussd_is_busy(ussd))
904                 return -EBUSY;
905
906         req = g_try_new0(struct ussd_request, 1);
907         if (req == NULL)
908                 return -ENOMEM;
909
910         req->cb = cb;
911         req->user_data = user_data;
912
913         ussd->req = req;
914
915         ussd->driver->request(ussd, dcs, pdu, len, ussd_request_callback, ussd);
916
917         return 0;
918 }
919
920 void __ofono_ussd_initiate_cancel(struct ofono_ussd *ussd)
921 {
922         if (ussd->req == NULL || ussd->req->cb == NULL)
923                 return;
924
925         ussd->req->cb = NULL;
926 }