Move colr-status enum out of common.h
[platform/upstream/ofono.git] / src / call-settings.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2009  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 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.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 "ussd.h"
38
39 #define CALL_SETTINGS_FLAG_CACHED 0x1
40
41 static GSList *g_drivers = NULL;
42
43 /* 27.007 Section 7.7 */
44 enum clir_status {
45         CLIR_STATUS_NOT_PROVISIONED = 0,
46         CLIR_STATUS_PROVISIONED_PERMANENT,
47         CLIR_STATUS_UNKNOWN,
48         CLIR_STATUS_TEMPORARY_RESTRICTED,
49         CLIR_STATUS_TEMPORARY_ALLOWED
50 };
51
52 /* 27.007 Section 7.6 */
53 enum clip_status {
54         CLIP_STATUS_NOT_PROVISIONED = 0,
55         CLIP_STATUS_PROVISIONED,
56         CLIP_STATUS_UNKNOWN
57 };
58
59 /* 27.007 Section 7.8 */
60 enum colp_status {
61         COLP_STATUS_NOT_PROVISIONED = 0,
62         COLP_STATUS_PROVISIONED = 1,
63         COLP_STATUS_UNKNOWN = 2
64 };
65
66 /* This is not defined in 27.007, but presumably the same as CLIP/COLP */
67 enum colr_status {
68         COLR_STATUS_NOT_PROVISIONED = 0,
69         COLR_STATUS_PROVISIONED = 1,
70         COLR_STATUS_UNKNOWN = 2
71 };
72
73 enum call_setting_type {
74         CALL_SETTING_TYPE_CLIP = 0,
75         CALL_SETTING_TYPE_COLP,
76         CALL_SETTING_TYPE_COLR,
77         CALL_SETTING_TYPE_CLIR,
78         CALL_SETTING_TYPE_CW
79 };
80
81 struct ofono_call_settings {
82         int clir;
83         int colr;
84         int clip;
85         int colp;
86         int clir_setting;
87         int cw;
88         int flags;
89         DBusMessage *pending;
90         int ss_req_type;
91         int ss_req_cls;
92         enum call_setting_type ss_setting;
93         struct ofono_ussd *ussd;
94         unsigned int ussd_watch;
95         const struct ofono_call_settings_driver *driver;
96         void *driver_data;
97         struct ofono_atom *atom;
98 };
99
100 static const char *clip_status_to_string(int status)
101 {
102         switch (status) {
103         case CLIP_STATUS_NOT_PROVISIONED:
104                 return "disabled";
105         case CLIP_STATUS_PROVISIONED:
106                 return "enabled";
107         default:
108                 return "unknown";
109         }
110 }
111
112 static const char *colp_status_to_string(int status)
113 {
114         switch (status) {
115         case COLP_STATUS_NOT_PROVISIONED:
116                 return "disabled";
117         case COLP_STATUS_PROVISIONED:
118                 return "enabled";
119         default:
120                 return "unknown";
121         }
122 }
123
124 static const char *colr_status_to_string(int status)
125 {
126         switch (status) {
127         case COLR_STATUS_NOT_PROVISIONED:
128                 return "disabled";
129         case COLR_STATUS_PROVISIONED:
130                 return "enabled";
131         default:
132                 return "unknown";
133         }
134 }
135
136 static const char *hide_callerid_to_string(int status)
137 {
138         switch (status) {
139         case OFONO_CLIR_OPTION_DEFAULT:
140                 return "default";
141         case OFONO_CLIR_OPTION_INVOCATION:
142                 return "enabled";
143         case OFONO_CLIR_OPTION_SUPPRESSION:
144                 return "disabled";
145         default:
146                 return "default";
147         }
148 }
149
150 static const char *clir_status_to_string(int status)
151 {
152         switch (status) {
153         case CLIR_STATUS_NOT_PROVISIONED:
154                 return "disabled";
155         case CLIR_STATUS_PROVISIONED_PERMANENT:
156                 return "permanent";
157         case CLIR_STATUS_TEMPORARY_RESTRICTED:
158                 return "on";
159         case CLIR_STATUS_TEMPORARY_ALLOWED:
160                 return "off";
161         default:
162                 return "unknown";
163         }
164 }
165
166 static void set_clir_network(struct ofono_call_settings *cs, int clir)
167 {
168         DBusConnection *conn;
169         const char *path;
170         const char *str;
171
172         if (cs->clir == clir)
173                 return;
174
175         cs->clir = clir;
176
177         conn = ofono_dbus_get_connection();
178         path = __ofono_atom_get_path(cs->atom);
179
180         str = clir_status_to_string(clir);
181
182         ofono_dbus_signal_property_changed(conn, path,
183                                                 OFONO_CALL_SETTINGS_INTERFACE,
184                                                 "CallingLineRestriction",
185                                                 DBUS_TYPE_STRING, &str);
186 }
187
188 static void set_clir_override(struct ofono_call_settings *cs, int override)
189 {
190         DBusConnection *conn;
191         const char *path;
192         const char *str;
193
194         if (cs->clir_setting == override)
195                 return;
196
197         cs->clir_setting = override;
198
199         conn = ofono_dbus_get_connection();
200         path = __ofono_atom_get_path(cs->atom);
201
202         str = hide_callerid_to_string(override);
203
204         ofono_dbus_signal_property_changed(conn, path,
205                                                 OFONO_CALL_SETTINGS_INTERFACE,
206                                                 "HideCallerId",
207                                                 DBUS_TYPE_STRING, &str);
208 }
209
210 static void set_clip(struct ofono_call_settings *cs, int clip)
211 {
212         DBusConnection *conn;
213         const char *path;
214         const char *str;
215
216         if (cs->clip == clip)
217                 return;
218
219         cs->clip = clip;
220
221         conn = ofono_dbus_get_connection();
222         path = __ofono_atom_get_path(cs->atom);
223
224         str = clip_status_to_string(clip);
225
226         ofono_dbus_signal_property_changed(conn, path,
227                                                 OFONO_CALL_SETTINGS_INTERFACE,
228                                                 "CallingLinePresentation",
229                                                 DBUS_TYPE_STRING, &str);
230 }
231
232 static void set_colp(struct ofono_call_settings *cs, int colp)
233 {
234         DBusConnection *conn;
235         const char *path;
236         const char *str;
237
238         if (cs->colp == colp)
239                 return;
240
241         cs->colp = colp;
242
243         conn = ofono_dbus_get_connection();
244         path = __ofono_atom_get_path(cs->atom);
245
246         str = colp_status_to_string(colp);
247
248         ofono_dbus_signal_property_changed(conn, path,
249                                                 OFONO_CALL_SETTINGS_INTERFACE,
250                                                 "CalledLinePresentation",
251                                                 DBUS_TYPE_STRING, &str);
252 }
253
254 static void set_colr(struct ofono_call_settings *cs, int colr)
255 {
256         DBusConnection *conn;
257         const char *path;
258         const char *str;
259
260         if (cs->colr == colr)
261                 return;
262
263         cs->colr = colr;
264
265         conn = ofono_dbus_get_connection();
266         path = __ofono_atom_get_path(cs->atom);
267
268         str = colr_status_to_string(colr);
269
270         ofono_dbus_signal_property_changed(conn, path,
271                                                 OFONO_CALL_SETTINGS_INTERFACE,
272                                                 "CalledLineRestriction",
273                                                 DBUS_TYPE_STRING, &str);
274 }
275
276 static void set_cw(struct ofono_call_settings *cs, int new_cw, int mask)
277 {
278         DBusConnection *conn = ofono_dbus_get_connection();
279         const char *path = __ofono_atom_get_path(cs->atom);
280         char buf[64];
281         int j;
282         const char *value;
283
284         for (j = 1; j <= BEARER_CLASS_PAD; j = j << 1) {
285                 if ((j & mask) == 0)
286                         continue;
287
288                 if ((cs->cw & j) == (new_cw & j))
289                         continue;
290
291                 if (new_cw & j)
292                         value = "enabled";
293                 else
294                         value = "disabled";
295
296                 sprintf(buf, "%sCallWaiting", bearer_class_to_string(j));
297                 ofono_dbus_signal_property_changed(conn, path,
298                                                 OFONO_CALL_SETTINGS_INTERFACE,
299                                                 buf, DBUS_TYPE_STRING,
300                                                 &value);
301         }
302
303         cs->cw = new_cw;
304 }
305
306 static void property_append_cw_conditions(DBusMessageIter *dict,
307                                                 int conditions, int mask)
308 {
309         int i;
310         char prop[128];
311         const char *value;
312
313         for (i = 1; i <= BEARER_CLASS_PAD; i = i << 1) {
314                 if (!(mask & i))
315                         continue;
316
317                 sprintf(prop, "%sCallWaiting", bearer_class_to_string(i));
318
319                 if (conditions & i)
320                         value = "enabled";
321                 else
322                         value = "disabled";
323
324                 ofono_dbus_dict_append(dict, prop, DBUS_TYPE_STRING, &value);
325         }
326 }
327
328 static void generate_cw_ss_query_reply(struct ofono_call_settings *cs)
329 {
330         const char *sig = "(sa{sv})";
331         const char *ss_type = ss_control_type_to_string(cs->ss_req_type);
332         const char *context = "CallWaiting";
333         DBusMessageIter iter;
334         DBusMessageIter var;
335         DBusMessageIter vstruct;
336         DBusMessageIter dict;
337         DBusMessage *reply;
338
339         reply = dbus_message_new_method_return(cs->pending);
340
341         dbus_message_iter_init_append(reply, &iter);
342
343         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &context);
344
345         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, sig, &var);
346
347         dbus_message_iter_open_container(&var, DBUS_TYPE_STRUCT, NULL,
348                                                 &vstruct);
349
350         dbus_message_iter_append_basic(&vstruct, DBUS_TYPE_STRING,
351                                         &ss_type);
352
353         dbus_message_iter_open_container(&vstruct, DBUS_TYPE_ARRAY,
354                                         OFONO_PROPERTIES_ARRAY_SIGNATURE,
355                                         &dict);
356
357         property_append_cw_conditions(&dict, cs->cw, cs->ss_req_cls);
358
359         dbus_message_iter_close_container(&vstruct, &dict);
360
361         dbus_message_iter_close_container(&var, &vstruct);
362
363         dbus_message_iter_close_container(&iter, &var);
364
365         __ofono_dbus_pending_reply(&cs->pending, reply);
366 }
367
368 static void cw_ss_query_callback(const struct ofono_error *error, int status,
369                                         void *data)
370 {
371         struct ofono_call_settings *cs = data;
372
373         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
374                 ofono_debug("setting CW via SS failed");
375
376                 cs->flags &= ~CALL_SETTINGS_FLAG_CACHED;
377                 __ofono_dbus_pending_reply(&cs->pending,
378                                         __ofono_error_failed(cs->pending));
379
380                 return;
381         }
382
383         set_cw(cs, status, BEARER_CLASS_VOICE);
384
385         generate_cw_ss_query_reply(cs);
386 }
387
388 static void cw_ss_set_callback(const struct ofono_error *error, void *data)
389 {
390         struct ofono_call_settings *cs = data;
391
392         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
393                 ofono_debug("setting CW via SS failed");
394                 __ofono_dbus_pending_reply(&cs->pending,
395                                         __ofono_error_failed(cs->pending));
396
397                 return;
398         }
399
400         cs->driver->cw_query(cs, BEARER_CLASS_DEFAULT,
401                                 cw_ss_query_callback, cs);
402 }
403
404 static gboolean cw_ss_control(int type,
405                                 const char *sc, const char *sia,
406                                 const char *sib, const char *sic,
407                                 const char *dn, DBusMessage *msg, void *data)
408 {
409         struct ofono_call_settings *cs = data;
410         DBusConnection *conn = ofono_dbus_get_connection();
411         int cls = BEARER_CLASS_SS_DEFAULT;
412         DBusMessage *reply;
413
414         if (!cs)
415                 return FALSE;
416
417         if (strcmp(sc, "43"))
418                 return FALSE;
419
420         if (cs->pending) {
421                 reply = __ofono_error_busy(msg);
422                 goto error;
423         }
424
425         if (strlen(sib) || strlen(sib) || strlen(dn))
426                 goto bad_format;
427
428         if ((type == SS_CONTROL_TYPE_QUERY && !cs->driver->cw_query) ||
429                 (type != SS_CONTROL_TYPE_QUERY && !cs->driver->cw_set)) {
430                 reply = __ofono_error_not_implemented(msg);
431                 goto error;
432         }
433
434         if (strlen(sia) > 0) {
435                 long service_code;
436                 char *end;
437
438                 service_code = strtoul(sia, &end, 10);
439
440                 if (end == sia || *end != '\0')
441                         goto bad_format;
442
443                 cls = mmi_service_code_to_bearer_class(service_code);
444                 if (cls == 0)
445                         goto bad_format;
446         }
447
448         cs->ss_req_cls = cls;
449         cs->pending = dbus_message_ref(msg);
450
451         /* For the default case use the more readily accepted value */
452         if (cls == BEARER_CLASS_SS_DEFAULT)
453                 cls = BEARER_CLASS_DEFAULT;
454
455         switch (type) {
456         case SS_CONTROL_TYPE_REGISTRATION:
457         case SS_CONTROL_TYPE_ACTIVATION:
458                 cs->ss_req_type = SS_CONTROL_TYPE_ACTIVATION;
459                 cs->driver->cw_set(cs, 1, cls, cw_ss_set_callback, cs);
460                 break;
461
462         case SS_CONTROL_TYPE_QUERY:
463                 cs->ss_req_type = SS_CONTROL_TYPE_QUERY;
464                 /* Always query the entire set, SMS not applicable
465                  * according to 22.004 Appendix A, so CLASS_DEFAULT
466                  * is safe to use here
467                  */
468                 cs->driver->cw_query(cs, BEARER_CLASS_DEFAULT,
469                                         cw_ss_query_callback, cs);
470                 break;
471
472         case SS_CONTROL_TYPE_DEACTIVATION:
473         case SS_CONTROL_TYPE_ERASURE:
474                 cs->ss_req_type = SS_CONTROL_TYPE_DEACTIVATION;
475                 cs->driver->cw_set(cs, 0, cls, cw_ss_set_callback, cs);
476                 break;
477         }
478
479         return TRUE;
480
481 bad_format:
482         reply = __ofono_error_invalid_format(msg);
483 error:
484         g_dbus_send_message(conn, reply);
485         return TRUE;
486 }
487
488 static void generate_ss_query_reply(struct ofono_call_settings *cs,
489                                         const char *context, const char *value)
490 {
491         const char *sig = "(ss)";
492         const char *ss_type = ss_control_type_to_string(cs->ss_req_type);
493         DBusMessageIter iter;
494         DBusMessageIter var;
495         DBusMessageIter vstruct;
496         DBusMessage *reply;
497
498         reply = dbus_message_new_method_return(cs->pending);
499
500         dbus_message_iter_init_append(reply, &iter);
501
502         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &context);
503
504         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, sig, &var);
505
506         dbus_message_iter_open_container(&var, DBUS_TYPE_STRUCT, NULL,
507                                                 &vstruct);
508
509         dbus_message_iter_append_basic(&vstruct, DBUS_TYPE_STRING,
510                                         &ss_type);
511
512         dbus_message_iter_append_basic(&vstruct, DBUS_TYPE_STRING, &value);
513
514         dbus_message_iter_close_container(&var, &vstruct);
515
516         dbus_message_iter_close_container(&iter, &var);
517
518         __ofono_dbus_pending_reply(&cs->pending, reply);
519 }
520
521 static void clip_colp_colr_ss_query_cb(const struct ofono_error *error,
522                                         int status, void *data)
523 {
524         struct ofono_call_settings *cs = data;
525         const char *context;
526         const char *value;
527
528         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
529                 ofono_debug("Error occurred during ss control query");
530                 __ofono_dbus_pending_reply(&cs->pending,
531                                         __ofono_error_failed(cs->pending));
532
533                 return;
534         }
535
536         switch (cs->ss_setting) {
537         case CALL_SETTING_TYPE_CLIP:
538                 set_clip(cs, status);
539                 value = clip_status_to_string(status);
540                 context = "CallingLinePresentation";
541                 break;
542
543         case CALL_SETTING_TYPE_COLP:
544                 set_colp(cs, status);
545                 value = colp_status_to_string(status);
546                 context = "CalledLinePresentation";
547                 break;
548
549         case CALL_SETTING_TYPE_COLR:
550                 set_colr(cs, status);
551                 value = colr_status_to_string(status);
552                 context = "CallingLineRestriction";
553                 break;
554
555         default:
556                 __ofono_dbus_pending_reply(&cs->pending,
557                                 __ofono_error_failed(cs->pending));
558                 ofono_error("Unknown type during COLR/COLP/CLIP ss");
559                 return;
560         };
561
562         generate_ss_query_reply(cs, context, value);
563 }
564
565 static gboolean clip_colp_colr_ss(int type,
566                                 const char *sc, const char *sia,
567                                 const char *sib, const char *sic,
568                                 const char *dn, DBusMessage *msg, void *data)
569 {
570         struct ofono_call_settings *cs = data;
571         DBusConnection *conn = ofono_dbus_get_connection();
572         void (*query_op)(struct ofono_call_settings *cs,
573                                 ofono_call_settings_status_cb_t cb, void *data);
574
575         if (!cs)
576                 return FALSE;
577
578         if (cs->pending) {
579                 DBusMessage *reply = __ofono_error_busy(msg);
580                 g_dbus_send_message(conn, reply);
581
582                 return TRUE;
583         }
584
585         if (!strcmp(sc, "30")) {
586                 cs->ss_setting = CALL_SETTING_TYPE_CLIP;
587                 query_op = cs->driver->clip_query;
588         } else if (!strcmp(sc, "76")) {
589                 cs->ss_setting = CALL_SETTING_TYPE_COLP;
590                 query_op = cs->driver->colp_query;
591         } else if (!strcmp(sc, "77")) {
592                 cs->ss_setting = CALL_SETTING_TYPE_COLR;
593                 query_op = cs->driver->colr_query;
594         } else
595                 return FALSE;
596
597         if (type != SS_CONTROL_TYPE_QUERY || strlen(sia) || strlen(sib) ||
598                 strlen(sic) || strlen(dn)) {
599                 DBusMessage *reply = __ofono_error_invalid_format(msg);
600                 g_dbus_send_message(conn, reply);
601
602                 return TRUE;
603         }
604
605         if (!query_op) {
606                 DBusMessage *reply = __ofono_error_not_implemented(msg);
607                 g_dbus_send_message(conn, reply);
608
609                 return TRUE;
610         }
611
612         ofono_debug("Received CLIP/COLR/COLP query ss control");
613
614         cs->pending = dbus_message_ref(msg);
615
616         query_op(cs, clip_colp_colr_ss_query_cb, cs);
617
618         return TRUE;
619 }
620
621 static void clir_ss_query_callback(const struct ofono_error *error,
622                                         int override, int network, void *data)
623 {
624         struct ofono_call_settings *cs = data;
625         const char *value;
626
627         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
628                 ofono_debug("setting clir via SS failed");
629                 __ofono_dbus_pending_reply(&cs->pending,
630                                         __ofono_error_failed(cs->pending));
631
632                 return;
633         }
634
635         switch (network) {
636         case CLIR_STATUS_UNKNOWN:
637                 value = "uknown";
638                 break;
639
640         case CLIR_STATUS_PROVISIONED_PERMANENT:
641                 value = "enabled";
642                 break;
643
644         case CLIR_STATUS_NOT_PROVISIONED:
645                 value = "disabled";
646                 break;
647
648         case CLIR_STATUS_TEMPORARY_RESTRICTED:
649                 if (override == OFONO_CLIR_OPTION_SUPPRESSION)
650                         value = "enabled";
651                 else
652                         value = "disabled";
653                 break;
654
655         case CLIR_STATUS_TEMPORARY_ALLOWED:
656                 if (override == OFONO_CLIR_OPTION_INVOCATION)
657                         value = "enabled";
658                 else
659                         value = "disabled";
660                 break;
661         default:
662                 value = "unknown";
663         };
664
665         generate_ss_query_reply(cs, "CallingLineRestriction", value);
666
667         set_clir_network(cs, network);
668         set_clir_override(cs, override);
669 }
670
671 static void clir_ss_set_callback(const struct ofono_error *error, void *data)
672 {
673         struct ofono_call_settings *cs = data;
674
675         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
676                 ofono_debug("setting clir via SS failed");
677                 __ofono_dbus_pending_reply(&cs->pending,
678                                         __ofono_error_failed(cs->pending));
679
680                 return;
681         }
682
683         cs->driver->clir_query(cs, clir_ss_query_callback, cs);
684 }
685
686 static gboolean clir_ss_control(int type,
687                                 const char *sc, const char *sia,
688                                 const char *sib, const char *sic,
689                                 const char *dn, DBusMessage *msg, void *data)
690 {
691         struct ofono_call_settings *cs = data;
692         DBusConnection *conn = ofono_dbus_get_connection();
693
694         if (!cs)
695                 return FALSE;
696
697         if (strcmp(sc, "31"))
698                 return FALSE;
699
700         if (cs->pending) {
701                 DBusMessage *reply = __ofono_error_busy(msg);
702                 g_dbus_send_message(conn, reply);
703
704                 return TRUE;
705         }
706
707         /* This is the temporary form of CLIR, handled in voicecalls */
708         if (!strlen(sia) && !strlen(sib) & !strlen(sic) &&
709                 strlen(dn) && type != SS_CONTROL_TYPE_QUERY)
710                 return FALSE;
711
712         if (strlen(sia) || strlen(sib) || strlen(sic) || strlen(dn)) {
713                 DBusMessage *reply = __ofono_error_invalid_format(msg);
714                 g_dbus_send_message(conn, reply);
715
716                 return TRUE;
717         }
718
719         if ((type == SS_CONTROL_TYPE_QUERY && !cs->driver->clir_query) ||
720                 (type != SS_CONTROL_TYPE_QUERY && !cs->driver->clir_set)) {
721                 DBusMessage *reply = __ofono_error_not_implemented(msg);
722                 g_dbus_send_message(conn, reply);
723
724                 return TRUE;
725         }
726
727         cs->ss_setting = CALL_SETTING_TYPE_CLIR;
728         cs->pending = dbus_message_ref(msg);
729
730         switch (type) {
731         case SS_CONTROL_TYPE_REGISTRATION:
732         case SS_CONTROL_TYPE_ACTIVATION:
733                 cs->ss_req_type = SS_CONTROL_TYPE_ACTIVATION;
734                 cs->driver->clir_set(cs, OFONO_CLIR_OPTION_INVOCATION,
735                                         clir_ss_set_callback, cs);
736                 break;
737
738         case SS_CONTROL_TYPE_QUERY:
739                 cs->ss_req_type = SS_CONTROL_TYPE_QUERY;
740                 cs->driver->clir_query(cs, clir_ss_query_callback, cs);
741                 break;
742
743         case SS_CONTROL_TYPE_DEACTIVATION:
744         case SS_CONTROL_TYPE_ERASURE:
745                 cs->ss_req_type = SS_CONTROL_TYPE_DEACTIVATION;
746                 cs->driver->clir_set(cs, OFONO_CLIR_OPTION_SUPPRESSION,
747                                         clir_ss_set_callback, cs);
748                 break;
749         };
750
751         return TRUE;
752 }
753
754 static void cs_register_ss_controls(struct ofono_call_settings *cs)
755 {
756         __ofono_ussd_ssc_register(cs->ussd, "30", clip_colp_colr_ss, cs, NULL);
757         __ofono_ussd_ssc_register(cs->ussd, "31", clir_ss_control, cs, NULL);
758         __ofono_ussd_ssc_register(cs->ussd, "76", clip_colp_colr_ss, cs, NULL);
759
760         __ofono_ussd_ssc_register(cs->ussd, "43", cw_ss_control, cs, NULL);
761
762         if (cs->driver->colr_query)
763                 __ofono_ussd_ssc_register(cs->ussd, "77",
764                                                 clip_colp_colr_ss, cs, NULL);
765 }
766
767 static void cs_unregister_ss_controls(struct ofono_call_settings *cs)
768 {
769         __ofono_ussd_ssc_unregister(cs->ussd, "30");
770         __ofono_ussd_ssc_unregister(cs->ussd, "31");
771         __ofono_ussd_ssc_unregister(cs->ussd, "76");
772
773         __ofono_ussd_ssc_unregister(cs->ussd, "43");
774
775         if (cs->driver->colr_query)
776                 __ofono_ussd_ssc_unregister(cs->ussd, "77");
777 }
778
779 static DBusMessage *generate_get_properties_reply(struct ofono_call_settings *cs,
780                                                         DBusMessage *msg)
781 {
782         DBusMessage *reply;
783         DBusMessageIter iter;
784         DBusMessageIter dict;
785         const char *str;
786
787         reply = dbus_message_new_method_return(msg);
788
789         if (!reply)
790                 return NULL;
791
792         dbus_message_iter_init_append(reply, &iter);
793
794         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
795                                         OFONO_PROPERTIES_ARRAY_SIGNATURE,
796                                         &dict);
797
798         str = clip_status_to_string(cs->clip);
799         ofono_dbus_dict_append(&dict, "CallingLinePresentation",
800                                 DBUS_TYPE_STRING, &str);
801
802         str = colp_status_to_string(cs->colp);
803         ofono_dbus_dict_append(&dict, "CalledLinePresentation",
804                                 DBUS_TYPE_STRING, &str);
805
806         str = colr_status_to_string(cs->colr);
807         ofono_dbus_dict_append(&dict, "CalledLineRestriction",
808                                 DBUS_TYPE_STRING, &str);
809
810         str = clir_status_to_string(cs->clir);
811         ofono_dbus_dict_append(&dict, "CallingLineRestriction",
812                                 DBUS_TYPE_STRING, &str);
813
814         str = hide_callerid_to_string(cs->clir_setting);
815         ofono_dbus_dict_append(&dict, "HideCallerId", DBUS_TYPE_STRING, &str);
816
817         property_append_cw_conditions(&dict, cs->cw, BEARER_CLASS_VOICE);
818
819         dbus_message_iter_close_container(&iter, &dict);
820
821         return reply;
822 }
823
824 static void cs_clir_callback(const struct ofono_error *error,
825                                 int override_setting, int network_setting,
826                                 void *data)
827 {
828         struct ofono_call_settings *cs = data;
829
830         if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
831                 goto out;
832
833         set_clir_network(cs, network_setting);
834         set_clir_override(cs, override_setting);
835
836         cs->flags |= CALL_SETTINGS_FLAG_CACHED;
837
838 out:
839         if (cs->pending) {
840                 DBusMessage *reply = generate_get_properties_reply(cs,
841                                                                 cs->pending);
842                 __ofono_dbus_pending_reply(&cs->pending, reply);
843         }
844 }
845
846 static void query_clir(struct ofono_call_settings *cs)
847 {
848         if (!cs->driver->clir_query) {
849                 if (cs->pending) {
850                         DBusMessage *reply =
851                                 generate_get_properties_reply(cs,
852                                                                 cs->pending);
853                         __ofono_dbus_pending_reply(&cs->pending, reply);
854                 }
855
856                 return;
857         }
858
859         cs->driver->clir_query(cs, cs_clir_callback, cs);
860 }
861
862 static void cs_clip_callback(const struct ofono_error *error,
863                                 int state, void *data)
864 {
865         struct ofono_call_settings *cs = data;
866
867         if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
868                 set_clip(cs, state);
869
870         query_clir(cs);
871 }
872
873 static void query_clip(struct ofono_call_settings *cs)
874 {
875         if (!cs->driver->clip_query) {
876                 query_clir(cs);
877                 return;
878         }
879
880         cs->driver->clip_query(cs, cs_clip_callback, cs);
881 }
882
883 static void cs_colp_callback(const struct ofono_error *error,
884                                 int state, void *data)
885 {
886         struct ofono_call_settings *cs = data;
887
888         if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
889                 set_colp(cs, state);
890
891         query_clip(cs);
892 }
893
894 static void query_colp(struct ofono_call_settings *cs)
895 {
896         if (!cs->driver->colp_query) {
897                 query_clip(cs);
898                 return;
899         }
900
901         cs->driver->colp_query(cs, cs_colp_callback, cs);
902 }
903
904 static void cs_colr_callback(const struct ofono_error *error,
905                                 int state, void *data)
906 {
907         struct ofono_call_settings *cs = data;
908
909         if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
910                 set_colr(cs, state);
911
912         query_colp(cs);
913 }
914
915 static void query_colr(struct ofono_call_settings *cs)
916 {
917         if (!cs->driver->colr_query) {
918                 query_colp(cs);
919                 return;
920         }
921
922         cs->driver->colr_query(cs, cs_colr_callback, cs);
923 }
924
925 static void cs_cw_callback(const struct ofono_error *error, int status,
926                                 void *data)
927 {
928         struct ofono_call_settings *cs = data;
929
930         if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
931                 set_cw(cs, status, BEARER_CLASS_VOICE);
932
933         query_colr(cs);
934 }
935
936 static void query_cw(struct ofono_call_settings *cs)
937 {
938         if (!cs->driver->cw_query) {
939                 query_colr(cs);
940                 return;
941         }
942
943         cs->driver->cw_query(cs, BEARER_CLASS_DEFAULT, cs_cw_callback, cs);
944 }
945
946 static DBusMessage *cs_get_properties(DBusConnection *conn, DBusMessage *msg,
947                                         void *data)
948 {
949         struct ofono_call_settings *cs = data;
950
951         if (cs->pending)
952                 return __ofono_error_busy(msg);
953
954         if (cs->flags & CALL_SETTINGS_FLAG_CACHED)
955                 return generate_get_properties_reply(cs, msg);
956
957         /* Query the settings and report back */
958         cs->pending = dbus_message_ref(msg);
959
960         query_cw(cs);
961
962         return NULL;
963 }
964
965 static void clir_set_query_callback(const struct ofono_error *error,
966                                         int override_setting,
967                                         int network_setting, void *data)
968 {
969         struct ofono_call_settings *cs = data;
970         DBusMessage *reply;
971
972         if (!cs->pending)
973                 return;
974
975         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
976                 ofono_error("set clir successful, but the query was not");
977
978                 cs->flags &= ~CALL_SETTINGS_FLAG_CACHED;
979
980                 reply = __ofono_error_failed(cs->pending);
981                 __ofono_dbus_pending_reply(&cs->pending, reply);
982                 return;
983         }
984
985         reply = dbus_message_new_method_return(cs->pending);
986         __ofono_dbus_pending_reply(&cs->pending, reply);
987
988         set_clir_override(cs, override_setting);
989         set_clir_network(cs, network_setting);
990 }
991
992 static void clir_set_callback(const struct ofono_error *error, void *data)
993 {
994         struct ofono_call_settings *cs = data;
995
996         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
997                 ofono_debug("setting clir failed");
998                 __ofono_dbus_pending_reply(&cs->pending,
999                                         __ofono_error_failed(cs->pending));
1000
1001                 return;
1002         }
1003
1004         /* Assume that if we have clir_set, we have clir_query */
1005         cs->driver->clir_query(cs, clir_set_query_callback, cs);
1006 }
1007
1008 static DBusMessage *set_clir(DBusMessage *msg, struct ofono_call_settings *cs,
1009                                 const char *setting)
1010 {
1011         int clir = -1;
1012
1013         if (cs->driver->clir_set == NULL)
1014                 return __ofono_error_not_implemented(msg);
1015
1016         if (!strcmp(setting, "default"))
1017                 clir = 0;
1018         else if (!strcmp(setting, "enabled"))
1019                 clir = 1;
1020         else if (!strcmp(setting, "disabled"))
1021                 clir = 2;
1022
1023         if (clir == -1)
1024                 return __ofono_error_invalid_format(msg);
1025
1026         cs->pending = dbus_message_ref(msg);
1027
1028         cs->driver->clir_set(cs, clir, clir_set_callback, cs);
1029
1030         return NULL;
1031 }
1032
1033 static void cw_set_query_callback(const struct ofono_error *error, int status,
1034                                 void *data)
1035 {
1036         struct ofono_call_settings *cs = data;
1037
1038         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
1039                 ofono_error("CW set succeeded, but query failed!");
1040
1041                 cs->flags &= ~CALL_SETTINGS_FLAG_CACHED;
1042
1043                 __ofono_dbus_pending_reply(&cs->pending,
1044                                         __ofono_error_failed(cs->pending));
1045                 return;
1046         }
1047
1048         __ofono_dbus_pending_reply(&cs->pending,
1049                                 dbus_message_new_method_return(cs->pending));
1050
1051         set_cw(cs, status, BEARER_CLASS_VOICE);
1052 }
1053
1054 static void cw_set_callback(const struct ofono_error *error, void *data)
1055 {
1056         struct ofono_call_settings *cs = data;
1057
1058         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
1059                 ofono_debug("Error occurred during CW set");
1060
1061                 __ofono_dbus_pending_reply(&cs->pending,
1062                                         __ofono_error_failed(cs->pending));
1063
1064                 return;
1065         }
1066
1067         cs->driver->cw_query(cs, BEARER_CLASS_DEFAULT,
1068                                 cw_set_query_callback, cs);
1069 }
1070
1071 static DBusMessage *set_cw_req(DBusMessage *msg, struct ofono_call_settings *cs,
1072                                 const char *setting, int cls)
1073 {
1074         int cw;
1075
1076         if (cs->driver->cw_set == NULL)
1077                 return __ofono_error_not_implemented(msg);
1078
1079         if (!strcmp(setting, "enabled"))
1080                 cw = 1;
1081         else if (!strcmp(setting, "disabled"))
1082                 cw = 0;
1083         else
1084                 return __ofono_error_invalid_format(msg);
1085
1086         cs->pending = dbus_message_ref(msg);
1087
1088         cs->driver->cw_set(cs, cw, cls, cw_set_callback, cs);
1089
1090         return NULL;
1091 }
1092
1093 static gboolean is_cw_property(const char *property, int mask, int *out_cls)
1094 {
1095         int i;
1096         int len;
1097         const char *prefix;
1098
1099         for (i = 1; i <= BEARER_CLASS_PAD; i = i << 1) {
1100                 if ((i & mask) == 0)
1101                         continue;
1102
1103                 prefix = bearer_class_to_string(i);
1104
1105                 len = strlen(prefix);
1106
1107                 if (strncmp(property, prefix, len))
1108                         continue;
1109
1110                 if (!strcmp(property+len, "CallWaiting")) {
1111                         *out_cls = i;
1112                         return TRUE;
1113                 }
1114         }
1115
1116         return FALSE;
1117 }
1118
1119 static DBusMessage *cs_set_property(DBusConnection *conn, DBusMessage *msg,
1120                                         void *data)
1121 {
1122         struct ofono_call_settings *cs = data;
1123         DBusMessageIter iter;
1124         DBusMessageIter var;
1125         const char *property;
1126         int cls;
1127
1128         if (cs->pending)
1129                 return __ofono_error_busy(msg);
1130
1131         if (!dbus_message_iter_init(msg, &iter))
1132                 return __ofono_error_invalid_args(msg);
1133
1134         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1135                 return __ofono_error_invalid_args(msg);
1136
1137         dbus_message_iter_get_basic(&iter, &property);
1138         dbus_message_iter_next(&iter);
1139
1140         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1141                 return __ofono_error_invalid_args(msg);
1142
1143         dbus_message_iter_recurse(&iter, &var);
1144
1145         if (!strcmp(property, "HideCallerId")) {
1146                 const char *setting;
1147
1148                 if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
1149                         return __ofono_error_invalid_args(msg);
1150
1151                 dbus_message_iter_get_basic(&var, &setting);
1152
1153                 return set_clir(msg, cs, setting);
1154         } else if (is_cw_property(property, BEARER_CLASS_VOICE, &cls)) {
1155                 const char *setting;
1156
1157                 if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
1158                         return __ofono_error_invalid_args(msg);
1159
1160                 dbus_message_iter_get_basic(&var, &setting);
1161
1162                 return set_cw_req(msg, cs, setting, cls);
1163         }
1164
1165         return __ofono_error_invalid_args(msg);
1166 }
1167
1168 static GDBusMethodTable cs_methods[] = {
1169         { "GetProperties",      "",     "a{sv}",        cs_get_properties,
1170                                                         G_DBUS_METHOD_FLAG_ASYNC },
1171         { "SetProperty",        "sv",   "",             cs_set_property,
1172                                                         G_DBUS_METHOD_FLAG_ASYNC },
1173         { }
1174 };
1175
1176 static GDBusSignalTable cs_signals[] = {
1177         { "PropertyChanged",    "sv" },
1178         { }
1179 };
1180
1181 int ofono_call_settings_driver_register(const struct ofono_call_settings_driver *d)
1182 {
1183         DBG("driver: %p, name: %s", d, d->name);
1184
1185         if (d->probe == NULL)
1186                 return -EINVAL;
1187
1188         g_drivers = g_slist_prepend(g_drivers, (void *)d);
1189
1190         return 0;
1191 }
1192
1193 void ofono_call_settings_driver_unregister(const struct ofono_call_settings_driver *d)
1194 {
1195         DBG("driver: %p, name: %s", d, d->name);
1196
1197         g_drivers = g_slist_remove(g_drivers, (void *)d);
1198 }
1199
1200 static void call_settings_unregister(struct ofono_atom *atom)
1201 {
1202         struct ofono_call_settings *cs = __ofono_atom_get_data(atom);
1203         const char *path = __ofono_atom_get_path(cs->atom);
1204         DBusConnection *conn = ofono_dbus_get_connection();
1205         struct ofono_modem *modem = __ofono_atom_get_modem(cs->atom);
1206
1207         ofono_modem_remove_interface(modem, OFONO_CALL_SETTINGS_INTERFACE);
1208         g_dbus_unregister_interface(conn, path, OFONO_CALL_SETTINGS_INTERFACE);
1209
1210         if (cs->ussd)
1211                 cs_unregister_ss_controls(cs);
1212
1213         if (cs->ussd_watch)
1214                 __ofono_modem_remove_atom_watch(modem, cs->ussd_watch);
1215 }
1216
1217 static void call_settings_remove(struct ofono_atom *atom)
1218 {
1219         struct ofono_call_settings *cs = __ofono_atom_get_data(atom);
1220
1221         DBG("atom: %p", atom);
1222
1223         if (cs == NULL)
1224                 return;
1225
1226         if (cs->driver && cs->driver->remove)
1227                 cs->driver->remove(cs);
1228
1229         g_free(cs);
1230 }
1231
1232 struct ofono_call_settings *ofono_call_settings_create(struct ofono_modem *modem,
1233                                                         const char *driver,
1234                                                         void *data)
1235 {
1236         struct ofono_call_settings *cs;
1237         GSList *l;
1238
1239         if (driver == NULL)
1240                 return NULL;
1241
1242         cs = g_try_new0(struct ofono_call_settings, 1);
1243
1244         if (cs == NULL)
1245                 return NULL;
1246
1247         /* Set all the settings to unknown state */
1248         cs->clip = 2;
1249         cs->clir = 2;
1250         cs->colp = 2;
1251         cs->colr = 2;
1252         cs->driver_data = data;
1253         cs->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_CALL_SETTINGS,
1254                                                 call_settings_remove, cs);
1255
1256         for (l = g_drivers; l; l = l->next) {
1257                 const struct ofono_call_settings_driver *drv = l->data;
1258
1259                 if (g_strcmp0(drv->name, driver))
1260                         continue;
1261
1262                 if (drv->probe(cs) < 0)
1263                         continue;
1264
1265                 cs->driver = drv;
1266                 break;
1267         }
1268
1269         return cs;
1270 }
1271
1272 static void ussd_watch(struct ofono_atom *atom,
1273                         enum ofono_atom_watch_condition cond, void *data)
1274 {
1275         struct ofono_call_settings *cs = data;
1276
1277         if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
1278                 cs->ussd = NULL;
1279                 return;
1280         }
1281
1282         cs->ussd = __ofono_atom_get_data(atom);
1283         cs_register_ss_controls(cs);
1284 }
1285
1286 void ofono_call_settings_register(struct ofono_call_settings *cs)
1287 {
1288         DBusConnection *conn = ofono_dbus_get_connection();
1289         const char *path = __ofono_atom_get_path(cs->atom);
1290         struct ofono_modem *modem = __ofono_atom_get_modem(cs->atom);
1291         struct ofono_atom *ussd_atom;
1292
1293         if (!g_dbus_register_interface(conn, path,
1294                                         OFONO_CALL_SETTINGS_INTERFACE,
1295                                         cs_methods, cs_signals, NULL, cs,
1296                                         NULL)) {
1297                 ofono_error("Could not create %s interface",
1298                                 OFONO_CALL_SETTINGS_INTERFACE);
1299
1300                 return;
1301         }
1302
1303         ofono_modem_add_interface(modem, OFONO_CALL_SETTINGS_INTERFACE);
1304
1305         cs->ussd_watch = __ofono_modem_add_atom_watch(modem,
1306                                         OFONO_ATOM_TYPE_USSD,
1307                                         ussd_watch, cs, NULL);
1308
1309         ussd_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_USSD);
1310
1311         if (ussd_atom && __ofono_atom_get_registered(ussd_atom))
1312                 ussd_watch(ussd_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED,
1313                                 cs);
1314
1315         __ofono_atom_register(cs->atom, call_settings_unregister);
1316 }
1317
1318 void ofono_call_settings_remove(struct ofono_call_settings *cs)
1319 {
1320         __ofono_atom_free(cs->atom);
1321 }
1322
1323 void ofono_call_settings_set_data(struct ofono_call_settings *cs, void *data)
1324 {
1325         cs->driver_data = data;
1326 }
1327
1328 void *ofono_call_settings_get_data(struct ofono_call_settings *cs)
1329 {
1330         return cs->driver_data;
1331 }