d2d36214dd554ded6aa1ce9952b52a985389684e
[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_invalid_format(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 GDBusMethodTable ussd_methods[] = {
732         { "Initiate",           "s",    "sv",           ussd_initiate,
733                                         G_DBUS_METHOD_FLAG_ASYNC },
734         { "Respond",            "s",    "s",            ussd_respond,
735                                         G_DBUS_METHOD_FLAG_ASYNC },
736         { "Cancel",             "",     "",             ussd_cancel,
737                                         G_DBUS_METHOD_FLAG_ASYNC },
738         { "GetProperties",      "",     "a{sv}",        ussd_get_properties,
739                                         0 },
740         { }
741 };
742
743 static GDBusSignalTable ussd_signals[] = {
744         { "NotificationReceived",       "s" },
745         { "RequestReceived",            "s" },
746         { "PropertyChanged",            "sv" },
747         { }
748 };
749
750 int ofono_ussd_driver_register(const struct ofono_ussd_driver *d)
751 {
752         DBG("driver: %p, name: %s", d, d->name);
753
754         if (d->probe == NULL)
755                 return -EINVAL;
756
757         g_drivers = g_slist_prepend(g_drivers, (void *) d);
758
759         return 0;
760 }
761
762 void ofono_ussd_driver_unregister(const struct ofono_ussd_driver *d)
763 {
764         DBG("driver: %p, name: %s", d, d->name);
765
766         g_drivers = g_slist_remove(g_drivers, (void *) d);
767 }
768
769 static void ussd_unregister(struct ofono_atom *atom)
770 {
771         struct ofono_ussd *ussd = __ofono_atom_get_data(atom);
772         DBusConnection *conn = ofono_dbus_get_connection();
773         struct ofono_modem *modem = __ofono_atom_get_modem(atom);
774         const char *path = __ofono_atom_get_path(atom);
775
776         g_slist_foreach(ussd->ss_control_list, (GFunc) ssc_entry_destroy, NULL);
777         g_slist_free(ussd->ss_control_list);
778         ussd->ss_control_list = NULL;
779
780         g_slist_foreach(ussd->ss_passwd_list, (GFunc) ssc_entry_destroy, NULL);
781         g_slist_free(ussd->ss_passwd_list);
782         ussd->ss_passwd_list = NULL;
783
784         ofono_modem_remove_interface(modem,
785                                         OFONO_SUPPLEMENTARY_SERVICES_INTERFACE);
786         g_dbus_unregister_interface(conn, path,
787                                         OFONO_SUPPLEMENTARY_SERVICES_INTERFACE);
788 }
789
790 static void ussd_remove(struct ofono_atom *atom)
791 {
792         struct ofono_ussd *ussd = __ofono_atom_get_data(atom);
793
794         DBG("atom: %p", atom);
795
796         if (ussd == NULL)
797                 return;
798
799         if (ussd->driver && ussd->driver->remove)
800                 ussd->driver->remove(ussd);
801
802         g_free(ussd);
803 }
804
805 struct ofono_ussd *ofono_ussd_create(struct ofono_modem *modem,
806                                         unsigned int vendor,
807                                         const char *driver,
808                                         void *data)
809 {
810         struct ofono_ussd *ussd;
811         GSList *l;
812
813         if (driver == NULL)
814                 return NULL;
815
816         ussd = g_try_new0(struct ofono_ussd, 1);
817
818         if (ussd == NULL)
819                 return NULL;
820
821         ussd->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_USSD,
822                                                 ussd_remove, ussd);
823
824         for (l = g_drivers; l; l = l->next) {
825                 const struct ofono_ussd_driver *drv = l->data;
826
827                 if (g_strcmp0(drv->name, driver))
828                         continue;
829
830                 if (drv->probe(ussd, vendor, data) < 0)
831                         continue;
832
833                 ussd->driver = drv;
834                 break;
835         }
836
837         return ussd;
838 }
839
840 void ofono_ussd_register(struct ofono_ussd *ussd)
841 {
842         DBusConnection *conn = ofono_dbus_get_connection();
843         struct ofono_modem *modem = __ofono_atom_get_modem(ussd->atom);
844         const char *path = __ofono_atom_get_path(ussd->atom);
845
846         if (!g_dbus_register_interface(conn, path,
847                                         OFONO_SUPPLEMENTARY_SERVICES_INTERFACE,
848                                         ussd_methods, ussd_signals, NULL,
849                                         ussd, NULL)) {
850                 ofono_error("Could not create %s interface",
851                                 OFONO_SUPPLEMENTARY_SERVICES_INTERFACE);
852
853                 return;
854         }
855
856         ofono_modem_add_interface(modem,
857                                 OFONO_SUPPLEMENTARY_SERVICES_INTERFACE);
858
859         __ofono_atom_register(ussd->atom, ussd_unregister);
860 }
861
862 void ofono_ussd_remove(struct ofono_ussd *ussd)
863 {
864         __ofono_atom_free(ussd->atom);
865 }
866
867 void ofono_ussd_set_data(struct ofono_ussd *ussd, void *data)
868 {
869         ussd->driver_data = data;
870 }
871
872 void *ofono_ussd_get_data(struct ofono_ussd *ussd)
873 {
874         return ussd->driver_data;
875 }
876
877 static void ussd_request_callback(const struct ofono_error *error, void *data)
878 {
879         struct ofono_ussd *ussd = data;
880
881         if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
882                 ussd_request_finish(ussd, -EINVAL, 0, NULL, 0);
883         else
884                 ussd_change_state(ussd, USSD_STATE_ACTIVE);
885 }
886
887 int __ofono_ussd_initiate(struct ofono_ussd *ussd, int dcs,
888                                 const unsigned char *pdu, int len,
889                                 ofono_ussd_request_cb_t cb, void *user_data)
890 {
891         struct ussd_request *req;
892
893         if (ussd->driver->request == NULL)
894                 return -ENOSYS;
895
896         if (__ofono_ussd_is_busy(ussd))
897                 return -EBUSY;
898
899         req = g_try_new0(struct ussd_request, 1);
900         if (req == NULL)
901                 return -ENOMEM;
902
903         req->cb = cb;
904         req->user_data = user_data;
905
906         ussd->req = req;
907
908         ussd->driver->request(ussd, dcs, pdu, len, ussd_request_callback, ussd);
909
910         return 0;
911 }
912
913 void __ofono_ussd_initiate_cancel(struct ofono_ussd *ussd)
914 {
915         if (ussd->req == NULL || ussd->req->cb == NULL)
916                 return;
917
918         ussd->req->cb = NULL;
919 }