call-forwarding: Make cf_cond_find more readable
[platform/upstream/ofono.git] / src / call-forwarding.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 #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 "simutil.h"
38
39 #define CALL_FORWARDING_FLAG_CACHED     0x1
40 #define CALL_FORWARDING_FLAG_CPHS_CFF   0x2
41
42 /* According to 27.007 Spec */
43 #define DEFAULT_NO_REPLY_TIMEOUT 20
44
45 #define is_cfu_enabled(_cf)                             \
46 ({                                                      \
47         cf_find_unconditional(_cf) ? TRUE : FALSE;      \
48 })
49
50 enum call_forwarding_type {
51         CALL_FORWARDING_TYPE_UNCONDITIONAL =    0,
52         CALL_FORWARDING_TYPE_BUSY =             1,
53         CALL_FORWARDING_TYPE_NO_REPLY =         2,
54         CALL_FORWARDING_TYPE_NOT_REACHABLE =    3,
55         CALL_FORWARDING_TYPE_ALL =              4,
56         CALL_FORWARDING_TYPE_ALL_CONDITIONAL =  5
57 };
58
59 struct ofono_call_forwarding {
60         GSList *cf_conditions[4];
61         int flags;
62         DBusMessage *pending;
63         int query_next;
64         int query_end;
65         struct cf_ss_request *ss_req;
66         struct ofono_sim *sim;
67         struct ofono_sim_context *sim_context;
68         unsigned char cfis_record_id;
69         struct ofono_ussd *ussd;
70         unsigned int ussd_watch;
71         const struct ofono_call_forwarding_driver *driver;
72         void *driver_data;
73         struct ofono_atom *atom;
74 };
75
76 struct cf_ss_request {
77         int ss_type;
78         int cf_type;
79         int cls;
80         GSList *cf_list[4];
81 };
82
83 static GSList *g_drivers = NULL;
84
85 static void get_query_next_cf_cond(struct ofono_call_forwarding *cf);
86 static void set_query_next_cf_cond(struct ofono_call_forwarding *cf);
87 static void ss_set_query_next_cf_cond(struct ofono_call_forwarding *cf);
88
89 static gint cf_cond_compare(gconstpointer a, gconstpointer b)
90 {
91         const struct ofono_call_forwarding_condition *ca = a;
92         const struct ofono_call_forwarding_condition *cb = b;
93
94         return ca->cls - cb->cls;
95 }
96
97 static struct ofono_call_forwarding_condition *cf_cond_find(GSList *l, int cls)
98 {
99         struct ofono_call_forwarding_condition *c;
100
101         for (; l; l = l->next) {
102                 c = l->data;
103
104                 if (c->cls == cls)
105                         return c;
106         }
107
108         return NULL;
109 }
110
111 static int cf_find_timeout(GSList *cf_list, int cls)
112 {
113         struct ofono_call_forwarding_condition *c;
114
115         c = cf_cond_find(cf_list, cls);
116
117         if (c == NULL)
118                 return DEFAULT_NO_REPLY_TIMEOUT;
119
120         return c->time;
121 }
122
123 static void cf_cond_list_print(GSList *list)
124 {
125         GSList *l;
126         struct ofono_call_forwarding_condition *cond;
127
128         for (l = list; l; l = l->next) {
129                 cond = l->data;
130
131                 DBG("CF Condition status: %d, class: %d, number: %s,"
132                         " number_type: %d, time: %d",
133                         cond->status, cond->cls, cond->phone_number.number,
134                         cond->phone_number.type, cond->time);
135         }
136 }
137
138 static GSList *cf_cond_list_create(int total,
139                         const struct ofono_call_forwarding_condition *list)
140 {
141         GSList *l = NULL;
142         int i;
143         int j;
144         struct ofono_call_forwarding_condition *cond;
145
146         /*
147          * Specification is not really clear how the results are reported,
148          * so assume both multiple list items & compound values of class
149          * are possible
150          */
151         for (i = 0; i < total; i++) {
152                 for (j = 1; j <= BEARER_CLASS_PAD; j = j << 1) {
153                         if (!(list[i].cls & j))
154                                 continue;
155
156                         if (list[i].status == 0)
157                                 continue;
158
159                         cond = g_try_new0(
160                                 struct ofono_call_forwarding_condition, 1);
161                         if (cond == NULL)
162                                 continue;
163
164                         memcpy(cond, &list[i],
165                                 sizeof(struct ofono_call_forwarding_condition));
166                         cond->cls = j;
167
168                         l = g_slist_insert_sorted(l, cond, cf_cond_compare);
169                 }
170         }
171
172         return l;
173 }
174
175 static inline void cf_clear_all(struct ofono_call_forwarding *cf)
176 {
177         int i;
178
179         for (i = 0; i < 4; i++) {
180                 g_slist_free_full(cf->cf_conditions[i], g_free);
181                 cf->cf_conditions[i] = NULL;
182         }
183 }
184
185 static const char *cf_type_lut[] = {
186         "Unconditional",
187         "Busy",
188         "NoReply",
189         "NotReachable",
190         "All",
191         "AllConditional"
192 };
193
194 static void sim_cfis_update_cb(int ok, void *data)
195 {
196         if (!ok)
197                 ofono_info("Failed to update EFcfis");
198 }
199
200 static void sim_cphs_cff_update_cb(int ok, void *data)
201 {
202         if (!ok)
203                 ofono_info("Failed to update EFcphs-cff");
204 }
205
206 static struct ofono_call_forwarding_condition *cf_find_unconditional(
207                                         struct ofono_call_forwarding *cf)
208 {
209         GSList *l = cf->cf_conditions[CALL_FORWARDING_TYPE_UNCONDITIONAL];
210         struct ofono_call_forwarding_condition *cond;
211
212         /*
213          * For now we only support Voice, although Fax & all Data
214          * basic services are applicable as well.
215          */
216         for (; l; l = l->next) {
217                 cond = l->data;
218
219                 if (cond->cls > BEARER_CLASS_VOICE)
220                         continue;
221
222                 return cond;
223         }
224
225         return NULL;
226 }
227
228 static void sim_set_cf_indicator(struct ofono_call_forwarding *cf)
229 {
230         struct ofono_call_forwarding_condition *cfu_voice =
231                                                 cf_find_unconditional(cf);
232
233         if (cf->cfis_record_id) {
234                 unsigned char data[16];
235                 int number_len;
236
237                 memset(data, 0xff, sizeof(data));
238
239                 /* Profile Identifier */
240                 data[0] = 0x01;
241
242                 if (cfu_voice) {
243                         number_len = strlen(cfu_voice->phone_number.number);
244
245                         /* CFU indicator Status - Voice */
246                         data[1] = 0x01;
247                         number_len = (number_len + 1) / 2;
248                         data[2] = number_len + 1;
249                         data[3] = cfu_voice->phone_number.type;
250
251                         sim_encode_bcd_number(cfu_voice->phone_number.number,
252                                                 data + 4);
253                 } else {
254                         data[1] = 0x00;
255                         data[2] = 1;
256                         data[3] = 128;
257                 }
258
259                 ofono_sim_write(cf->sim_context, SIM_EFCFIS_FILEID,
260                                         sim_cfis_update_cb,
261                                         OFONO_SIM_FILE_STRUCTURE_FIXED,
262                                         cf->cfis_record_id, data,
263                                         sizeof(data), cf);
264                 return;
265         }
266
267         if (cf->flags & CALL_FORWARDING_FLAG_CPHS_CFF) {
268                 unsigned char cff_voice = cfu_voice ? 0x0A : 0x05;
269
270                 ofono_sim_write(cf->sim_context, SIM_EF_CPHS_CFF_FILEID,
271                                         sim_cphs_cff_update_cb,
272                                         OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
273                                         0, &cff_voice, sizeof(cff_voice), cf);
274         }
275 }
276
277 static void set_new_cond_list(struct ofono_call_forwarding *cf,
278                                 int type, GSList *list)
279 {
280         GSList *old = cf->cf_conditions[type];
281         DBusConnection *conn = ofono_dbus_get_connection();
282         const char *path = __ofono_atom_get_path(cf->atom);
283         GSList *l;
284         GSList *o;
285         struct ofono_call_forwarding_condition *lc;
286         struct ofono_call_forwarding_condition *oc;
287         const char *number;
288         dbus_uint16_t timeout;
289         char attr[64];
290         char tattr[64];
291         gboolean update_sim = FALSE;
292         gboolean old_cfu;
293         gboolean new_cfu;
294
295         if ((cf->flags & CALL_FORWARDING_FLAG_CPHS_CFF) ||
296                         cf->cfis_record_id > 0)
297                 old_cfu = is_cfu_enabled(cf);
298         else
299                 old_cfu = FALSE;
300
301         for (l = list; l; l = l->next) {
302                 lc = l->data;
303
304                 /*
305                  * New condition lists might have attributes we don't care about
306                  * triggered by e.g. ss control magic strings just skip them
307                  * here.  For now we only support Voice, although Fax & all Data
308                  * basic services are applicable as well.
309                  */
310                 if (lc->cls > BEARER_CLASS_VOICE)
311                         continue;
312
313                 timeout = lc->time;
314                 number = phone_number_to_string(&lc->phone_number);
315
316                 snprintf(attr, sizeof(attr), "%s%s",
317                         bearer_class_to_string(lc->cls), cf_type_lut[type]);
318
319                 if (type == CALL_FORWARDING_TYPE_NO_REPLY)
320                         snprintf(tattr, sizeof(tattr), "%sTimeout", attr);
321
322                 oc = cf_cond_find(old, lc->cls);
323                 if (oc) { /* On the old list, must be active */
324                         if (oc->phone_number.type != lc->phone_number.type ||
325                                 strcmp(oc->phone_number.number,
326                                         lc->phone_number.number)) {
327                                 ofono_dbus_signal_property_changed(conn, path,
328                                                 OFONO_CALL_FORWARDING_INTERFACE,
329                                                 attr, DBUS_TYPE_STRING,
330                                                 &number);
331
332                                 if (type == CALL_FORWARDING_TYPE_UNCONDITIONAL)
333                                         update_sim = TRUE;
334                         }
335
336                         if (type == CALL_FORWARDING_TYPE_NO_REPLY &&
337                                         oc->time != lc->time)
338                                 ofono_dbus_signal_property_changed(conn, path,
339                                                 OFONO_CALL_FORWARDING_INTERFACE,
340                                                 tattr, DBUS_TYPE_UINT16,
341                                                 &timeout);
342
343                         /* Remove from the old list */
344                         old = g_slist_remove(old, oc);
345                         g_free(oc);
346                 } else {
347                         number = phone_number_to_string(&lc->phone_number);
348
349                         ofono_dbus_signal_property_changed(conn, path,
350                                                 OFONO_CALL_FORWARDING_INTERFACE,
351                                                 attr, DBUS_TYPE_STRING,
352                                                 &number);
353
354                         if (type == CALL_FORWARDING_TYPE_UNCONDITIONAL)
355                                 update_sim = TRUE;
356
357                         if (type == CALL_FORWARDING_TYPE_NO_REPLY &&
358                                         lc->time != DEFAULT_NO_REPLY_TIMEOUT)
359                                 ofono_dbus_signal_property_changed(conn, path,
360                                                 OFONO_CALL_FORWARDING_INTERFACE,
361                                                 tattr, DBUS_TYPE_UINT16,
362                                                 &timeout);
363                 }
364         }
365
366         timeout = DEFAULT_NO_REPLY_TIMEOUT;
367         number = "";
368
369         for (o = old; o; o = o->next) {
370                 oc = o->data;
371
372                 /*
373                  * For now we only support Voice, although Fax & all Data
374                  * basic services are applicable as well.
375                  */
376                 if (oc->cls > BEARER_CLASS_VOICE)
377                         continue;
378
379                 snprintf(attr, sizeof(attr), "%s%s",
380                         bearer_class_to_string(oc->cls), cf_type_lut[type]);
381
382                 if (type == CALL_FORWARDING_TYPE_NO_REPLY)
383                         snprintf(tattr, sizeof(tattr), "%sTimeout", attr);
384
385                 ofono_dbus_signal_property_changed(conn, path,
386                                         OFONO_CALL_FORWARDING_INTERFACE, attr,
387                                         DBUS_TYPE_STRING, &number);
388
389                 if (type == CALL_FORWARDING_TYPE_UNCONDITIONAL)
390                         update_sim = TRUE;
391
392                 if (type == CALL_FORWARDING_TYPE_NO_REPLY &&
393                                 oc->time != DEFAULT_NO_REPLY_TIMEOUT)
394                         ofono_dbus_signal_property_changed(conn, path,
395                                                 OFONO_CALL_FORWARDING_INTERFACE,
396                                                 tattr, DBUS_TYPE_UINT16,
397                                                 &timeout);
398         }
399
400         g_slist_free_full(old, g_free);
401         cf->cf_conditions[type] = list;
402
403         if (update_sim == TRUE)
404                 sim_set_cf_indicator(cf);
405
406         if ((cf->flags & CALL_FORWARDING_FLAG_CPHS_CFF) ||
407                         cf->cfis_record_id > 0)
408                 new_cfu = is_cfu_enabled(cf);
409         else
410                 new_cfu = FALSE;
411
412         if (new_cfu != old_cfu) {
413                 ofono_bool_t status = new_cfu;
414                 int i;
415
416                 /*
417                  * Emit signals to mask/unmask conditional cfs on cfu change
418                  */
419                 for (i = 0; i < 4; i++) {
420                         if (i == CALL_FORWARDING_TYPE_UNCONDITIONAL)
421                                 continue;
422
423                         lc = cf_cond_find(cf->cf_conditions[i],
424                                                 BEARER_CLASS_VOICE);
425                         if (lc == NULL)
426                                 continue;
427
428                         if (new_cfu)
429                                 number = "";
430                         else
431                                 number = phone_number_to_string(
432                                                         &lc->phone_number);
433
434                         ofono_dbus_signal_property_changed(conn, path,
435                                                 OFONO_CALL_FORWARDING_INTERFACE,
436                                                 cf_type_lut[i],
437                                                 DBUS_TYPE_STRING, &number);
438                 }
439
440                 ofono_dbus_signal_property_changed(conn, path,
441                                         OFONO_CALL_FORWARDING_INTERFACE,
442                                         "ForwardingFlagOnSim",
443                                         DBUS_TYPE_BOOLEAN, &status);
444         }
445 }
446
447 static inline void property_append_cf_condition(DBusMessageIter *dict, int cls,
448                                                 const char *postfix,
449                                                 const char *value,
450                                                 dbus_uint16_t timeout)
451 {
452         char attr[64];
453         char tattr[64];
454         int addt = !strcmp(postfix, "NoReply");
455
456         snprintf(attr, sizeof(attr), "%s%s",
457                         bearer_class_to_string(cls), postfix);
458
459         if (addt)
460                 snprintf(tattr, sizeof(tattr), "%s%sTimeout",
461                                 bearer_class_to_string(cls), postfix);
462
463         ofono_dbus_dict_append(dict, attr, DBUS_TYPE_STRING, &value);
464
465         if (addt)
466                 ofono_dbus_dict_append(dict, tattr, DBUS_TYPE_UINT16, &timeout);
467 }
468
469 static void property_append_cf_conditions(DBusMessageIter *dict,
470                                                 GSList *cf_list, int mask,
471                                                 const char *postfix)
472 {
473         GSList *l;
474         int i;
475         struct ofono_call_forwarding_condition *cf;
476         const char *number;
477
478         for (i = 1, l = cf_list; i <= BEARER_CLASS_PAD; i = i << 1) {
479                 if (!(mask & i))
480                         continue;
481
482                 while (l && (cf = l->data) && (cf->cls < i))
483                                 l = l->next;
484
485                 if (l == NULL || cf->cls != i) {
486                         property_append_cf_condition(dict, i, postfix, "",
487                                                 DEFAULT_NO_REPLY_TIMEOUT);
488                         continue;
489                 }
490
491                 number = phone_number_to_string(&cf->phone_number);
492
493                 property_append_cf_condition(dict, i, postfix, number,
494                                                 cf->time);
495         }
496 }
497
498 static DBusMessage *cf_get_properties_reply(DBusMessage *msg,
499                                         struct ofono_call_forwarding *cf)
500 {
501         DBusMessage *reply;
502         DBusMessageIter iter;
503         DBusMessageIter dict;
504         int i;
505         dbus_bool_t status;
506         gboolean cfu_enabled;
507         GSList *cf_list;
508
509         reply = dbus_message_new_method_return(msg);
510         if (reply == NULL)
511                 return NULL;
512
513         dbus_message_iter_init_append(reply, &iter);
514
515         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
516                                         OFONO_PROPERTIES_ARRAY_SIGNATURE,
517                                                 &dict);
518
519         cfu_enabled = is_cfu_enabled(cf);
520
521         for (i = 0; i < 4; i++) {
522                 /*
523                  * Report conditional cfs as empty when CFU is active
524                  */
525                 if (cfu_enabled && (i != CALL_FORWARDING_TYPE_UNCONDITIONAL))
526                         cf_list = NULL;
527                 else
528                         cf_list = cf->cf_conditions[i];
529
530                 property_append_cf_conditions(&dict, cf_list,
531                                                 BEARER_CLASS_VOICE,
532                                                 cf_type_lut[i]);
533         }
534
535         if ((cf->flags & CALL_FORWARDING_FLAG_CPHS_CFF) ||
536                         cf->cfis_record_id > 0)
537                 status = cfu_enabled;
538         else
539                 status = FALSE;
540
541         ofono_dbus_dict_append(&dict, "ForwardingFlagOnSim", DBUS_TYPE_BOOLEAN,
542                                         &status);
543
544         dbus_message_iter_close_container(&iter, &dict);
545
546         return reply;
547 }
548
549 static void get_query_cf_callback(const struct ofono_error *error, int total,
550                         const struct ofono_call_forwarding_condition *list,
551                         void *data)
552 {
553         struct ofono_call_forwarding *cf = data;
554
555         if (error->type == OFONO_ERROR_TYPE_NO_ERROR) {
556                 GSList *l = cf_cond_list_create(total, list);
557
558                 set_new_cond_list(cf, cf->query_next, l);
559
560                 DBG("%s conditions:", cf_type_lut[cf->query_next]);
561
562                 cf_cond_list_print(l);
563
564                 if (cf->query_next == CALL_FORWARDING_TYPE_NOT_REACHABLE)
565                         cf->flags |= CALL_FORWARDING_FLAG_CACHED;
566         }
567
568         if (cf->query_next == CALL_FORWARDING_TYPE_NOT_REACHABLE) {
569                 DBusMessage *reply = cf_get_properties_reply(cf->pending, cf);
570                 __ofono_dbus_pending_reply(&cf->pending, reply);
571                 return;
572         }
573
574         cf->query_next++;
575         get_query_next_cf_cond(cf);
576 }
577
578 static inline void get_query_next_cf_cond(struct ofono_call_forwarding *cf)
579 {
580         cf->driver->query(cf, cf->query_next, BEARER_CLASS_DEFAULT,
581                                 get_query_cf_callback, cf);
582 }
583
584 static DBusMessage *cf_get_properties(DBusConnection *conn, DBusMessage *msg,
585                                         void *data)
586 {
587         struct ofono_call_forwarding *cf = data;
588         struct ofono_modem *modem = __ofono_atom_get_modem(cf->atom);
589
590         if ((cf->flags & CALL_FORWARDING_FLAG_CACHED) ||
591                         ofono_modem_get_online(modem) == FALSE)
592                 return cf_get_properties_reply(msg, cf);
593
594         if (cf->driver->query == NULL)
595                 return __ofono_error_not_implemented(msg);
596
597         if (__ofono_call_forwarding_is_busy(cf) ||
598                         __ofono_ussd_is_busy(cf->ussd))
599                 return __ofono_error_busy(msg);
600
601         cf->pending = dbus_message_ref(msg);
602         cf->query_next = 0;
603
604         get_query_next_cf_cond(cf);
605
606         return NULL;
607 }
608
609 static gboolean cf_condition_enabled_property(struct ofono_call_forwarding *cf,
610                         const char *property, int *out_type, int *out_cls)
611 {
612         int i;
613         int j;
614         int len;
615         const char *prefix;
616
617         for (i = 1; i <= BEARER_CLASS_VOICE; i = i << 1) {
618                 prefix = bearer_class_to_string(i);
619
620                 len = strlen(prefix);
621
622                 if (strncmp(property, prefix, len))
623                         continue;
624
625                 /*
626                  * We check the 4 call forwarding types, e.g.
627                  * unconditional, busy, no reply, not reachable
628                  */
629                 for (j = 0; j < 4; j++)
630                         if (!strcmp(property+len, cf_type_lut[j])) {
631                                 *out_type = j;
632                                 *out_cls = i;
633                                 return TRUE;
634                         }
635         }
636
637         return FALSE;
638 }
639
640 static gboolean cf_condition_timeout_property(const char *property,
641                                                 int *out_cls)
642 {
643         int i;
644         int len;
645         const char *prefix;
646
647         for (i = 1; i <= BEARER_CLASS_VOICE; i = i << 1) {
648                 prefix = bearer_class_to_string(i);
649
650                 len = strlen(prefix);
651
652                 if (strncmp(property, prefix, len))
653                         continue;
654
655                 if (!strcmp(property+len, "NoReplyTimeout")) {
656                         *out_cls = i;
657                         return TRUE;
658                 }
659         }
660
661         return FALSE;
662 }
663
664 static void set_query_cf_callback(const struct ofono_error *error, int total,
665                         const struct ofono_call_forwarding_condition *list,
666                         void *data)
667 {
668         struct ofono_call_forwarding *cf = data;
669         GSList *l;
670         DBusMessage *reply;
671
672         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
673                 ofono_error("Setting succeeded, but query failed");
674                 cf->flags &= ~CALL_FORWARDING_FLAG_CACHED;
675                 reply = __ofono_error_failed(cf->pending);
676                 __ofono_dbus_pending_reply(&cf->pending, reply);
677                 return;
678         }
679
680         if (cf->query_next == cf->query_end) {
681                 reply = dbus_message_new_method_return(cf->pending);
682                 __ofono_dbus_pending_reply(&cf->pending, reply);
683         }
684
685         l = cf_cond_list_create(total, list);
686         set_new_cond_list(cf, cf->query_next, l);
687
688         DBG("%s conditions:", cf_type_lut[cf->query_next]);
689         cf_cond_list_print(l);
690
691         if (cf->query_next != cf->query_end) {
692                 cf->query_next++;
693                 set_query_next_cf_cond(cf);
694         }
695 }
696
697 static void set_query_next_cf_cond(struct ofono_call_forwarding *cf)
698 {
699         cf->driver->query(cf, cf->query_next, BEARER_CLASS_DEFAULT,
700                                 set_query_cf_callback, cf);
701 }
702
703 static void set_property_callback(const struct ofono_error *error, void *data)
704 {
705         struct ofono_call_forwarding *cf = data;
706
707         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
708                 DBG("Error occurred during set/erasure");
709                 __ofono_dbus_pending_reply(&cf->pending,
710                                         __ofono_error_failed(cf->pending));
711                 return;
712         }
713
714         /* Successfully set, query the entire set just in case */
715         set_query_next_cf_cond(cf);
716 }
717
718 static DBusMessage *set_property_request(struct ofono_call_forwarding *cf,
719                                                 DBusMessage *msg,
720                                                 int type, int cls,
721                                                 struct ofono_phone_number *ph,
722                                                 int timeout)
723 {
724         if (ph->number[0] != '\0' && cf->driver->registration == NULL)
725                 return __ofono_error_not_implemented(msg);
726
727         if (ph->number[0] == '\0' && cf->driver->erasure == NULL)
728                 return __ofono_error_not_implemented(msg);
729
730         cf->pending = dbus_message_ref(msg);
731         cf->query_next = type;
732         cf->query_end = type;
733
734         DBG("Farming off request, will be erasure: %d", ph->number[0] == '\0');
735
736         if (ph->number[0] != '\0')
737                 cf->driver->registration(cf, type, cls, ph, timeout,
738                                         set_property_callback, cf);
739         else
740                 cf->driver->erasure(cf, type, cls, set_property_callback, cf);
741
742         return NULL;
743 }
744
745 static DBusMessage *cf_set_property(DBusConnection *conn, DBusMessage *msg,
746                                         void *data)
747 {
748         struct ofono_call_forwarding *cf = data;
749         struct ofono_modem *modem = __ofono_atom_get_modem(cf->atom);
750         DBusMessageIter iter;
751         DBusMessageIter var;
752         const char *property;
753         int cls;
754         int type;
755
756         if (ofono_modem_get_online(modem) == FALSE)
757                 return __ofono_error_not_available(msg);
758
759         if (__ofono_call_forwarding_is_busy(cf) ||
760                         __ofono_ussd_is_busy(cf->ussd))
761                 return __ofono_error_busy(msg);
762
763         if (!dbus_message_iter_init(msg, &iter))
764                 return __ofono_error_invalid_args(msg);
765
766         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
767                 return __ofono_error_invalid_args(msg);
768
769         dbus_message_iter_get_basic(&iter, &property);
770         dbus_message_iter_next(&iter);
771
772         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
773                 return __ofono_error_invalid_args(msg);
774
775         dbus_message_iter_recurse(&iter, &var);
776
777         if (cf_condition_timeout_property(property, &cls)) {
778                 dbus_uint16_t timeout;
779                 struct ofono_call_forwarding_condition *c;
780
781                 type = CALL_FORWARDING_TYPE_NO_REPLY;
782
783                 if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_UINT16)
784                         return __ofono_error_invalid_args(msg);
785
786                 dbus_message_iter_get_basic(&var, &timeout);
787
788                 if (timeout < 1 || timeout > 30)
789                         return __ofono_error_invalid_format(msg);
790
791
792                 c = cf_cond_find(cf->cf_conditions[type], cls);
793                 if (c == NULL)
794                         return __ofono_error_failed(msg);
795
796                 return set_property_request(cf, msg, type, cls,
797                                                 &c->phone_number, timeout);
798         } else if (cf_condition_enabled_property(cf, property, &type, &cls)) {
799                 struct ofono_phone_number ph;
800                 const char *number;
801                 int timeout;
802
803                 ph.number[0] = '\0';
804                 ph.type = 129;
805
806                 if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
807                         return __ofono_error_invalid_args(msg);
808
809                 dbus_message_iter_get_basic(&var, &number);
810
811                 if (strlen(number) > 0 && !valid_phone_number_format(number))
812                         return __ofono_error_invalid_format(msg);
813
814                 /*
815                  * Don't set conditional cfs when cfu is active
816                  */
817                 if (type != CALL_FORWARDING_TYPE_UNCONDITIONAL &&
818                                 number[0] != '\0' && is_cfu_enabled(cf))
819                         return __ofono_error_not_available(msg);
820
821                 if (number[0] != '\0')
822                         string_to_phone_number(number, &ph);
823
824                 timeout = cf_find_timeout(cf->cf_conditions[type], cls);
825
826                 return set_property_request(cf, msg, type, cls, &ph,
827                                                 timeout);
828         }
829
830         return __ofono_error_invalid_args(msg);
831 }
832
833 static void disable_conditional_callback(const struct ofono_error *error,
834                                                 void *data)
835 {
836         struct ofono_call_forwarding *cf = data;
837
838         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
839                 DBG("Error occurred during conditional erasure");
840
841                 __ofono_dbus_pending_reply(&cf->pending,
842                                         __ofono_error_failed(cf->pending));
843                 return;
844         }
845
846         /* Query the three conditional cf types */
847         cf->query_next = CALL_FORWARDING_TYPE_BUSY;
848         cf->query_end = CALL_FORWARDING_TYPE_NOT_REACHABLE;
849         set_query_next_cf_cond(cf);
850 }
851
852 static void disable_all_callback(const struct ofono_error *error, void *data)
853 {
854         struct ofono_call_forwarding *cf = data;
855
856         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
857                 DBG("Error occurred during erasure of all");
858
859                 __ofono_dbus_pending_reply(&cf->pending,
860                                         __ofono_error_failed(cf->pending));
861                 return;
862         }
863
864         /* Query all cf types */
865         cf->query_next = CALL_FORWARDING_TYPE_UNCONDITIONAL;
866         cf->query_end = CALL_FORWARDING_TYPE_NOT_REACHABLE;
867         set_query_next_cf_cond(cf);
868 }
869
870 static DBusMessage *cf_disable_all(DBusConnection *conn, DBusMessage *msg,
871                                         void *data)
872 {
873         struct ofono_call_forwarding *cf = data;
874         const char *strtype;
875         int type;
876
877         if (cf->driver->erasure == NULL)
878                 return __ofono_error_not_implemented(msg);
879
880         if (__ofono_call_forwarding_is_busy(cf) ||
881                         __ofono_ussd_is_busy(cf->ussd))
882                 return __ofono_error_busy(msg);
883
884         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &strtype,
885                                         DBUS_TYPE_INVALID) == FALSE)
886                 return __ofono_error_invalid_args(msg);
887
888         if (!strcmp(strtype, "all") || !strcmp(strtype, ""))
889                 type = CALL_FORWARDING_TYPE_ALL;
890         else if (!strcmp(strtype, "conditional"))
891                 type = CALL_FORWARDING_TYPE_ALL_CONDITIONAL;
892         else
893                 return __ofono_error_invalid_format(msg);
894
895         cf->pending = dbus_message_ref(msg);
896
897         if (type == CALL_FORWARDING_TYPE_ALL)
898                 cf->driver->erasure(cf, type, BEARER_CLASS_DEFAULT,
899                                         disable_all_callback, cf);
900         else
901                 cf->driver->erasure(cf, type, BEARER_CLASS_DEFAULT,
902                                         disable_conditional_callback, cf);
903
904         return NULL;
905 }
906
907 static GDBusMethodTable cf_methods[] = {
908         { "GetProperties",      "",     "a{sv}",        cf_get_properties,
909                                                 G_DBUS_METHOD_FLAG_ASYNC },
910         { "SetProperty",        "sv",   "",             cf_set_property,
911                                                 G_DBUS_METHOD_FLAG_ASYNC },
912         { "DisableAll",         "s",    "",             cf_disable_all,
913                                                 G_DBUS_METHOD_FLAG_ASYNC },
914         { }
915 };
916
917 static GDBusSignalTable cf_signals[] = {
918         { "PropertyChanged",    "sv" },
919         { }
920 };
921
922 static DBusMessage *cf_ss_control_reply(struct ofono_call_forwarding *cf,
923                                         struct cf_ss_request *req)
924 {
925         const char *context = "CallForwarding";
926         const char *sig = "(ssa{sv})";
927         const char *ss_type = ss_control_type_to_string(req->ss_type);
928         const char *cf_type = cf_type_lut[req->cf_type];
929         DBusMessageIter iter;
930         DBusMessageIter variant;
931         DBusMessageIter vstruct;
932         DBusMessageIter dict;
933         DBusMessage *reply;
934
935         reply = dbus_message_new_method_return(cf->pending);
936
937         dbus_message_iter_init_append(reply, &iter);
938
939         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &context);
940
941         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, sig,
942                                                 &variant);
943
944         dbus_message_iter_open_container(&variant, DBUS_TYPE_STRUCT, NULL,
945                                                 &vstruct);
946
947         dbus_message_iter_append_basic(&vstruct, DBUS_TYPE_STRING,
948                                         &ss_type);
949
950         dbus_message_iter_append_basic(&vstruct, DBUS_TYPE_STRING,
951                                         &cf_type);
952
953         dbus_message_iter_open_container(&vstruct, DBUS_TYPE_ARRAY,
954                                 OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict);
955
956         if (req->cf_type == CALL_FORWARDING_TYPE_UNCONDITIONAL ||
957                 req->cf_type == CALL_FORWARDING_TYPE_ALL)
958                 property_append_cf_conditions(&dict,
959                         req->cf_list[CALL_FORWARDING_TYPE_UNCONDITIONAL],
960                         req->cls,
961                         cf_type_lut[CALL_FORWARDING_TYPE_UNCONDITIONAL]);
962
963         if (req->cf_type == CALL_FORWARDING_TYPE_NO_REPLY ||
964                 req->cf_type == CALL_FORWARDING_TYPE_ALL ||
965                 req->cf_type == CALL_FORWARDING_TYPE_ALL_CONDITIONAL)
966                 property_append_cf_conditions(&dict,
967                         req->cf_list[CALL_FORWARDING_TYPE_NO_REPLY],
968                         req->cls, cf_type_lut[CALL_FORWARDING_TYPE_NO_REPLY]);
969
970         if (req->cf_type == CALL_FORWARDING_TYPE_NOT_REACHABLE ||
971                 req->cf_type == CALL_FORWARDING_TYPE_ALL ||
972                 req->cf_type == CALL_FORWARDING_TYPE_ALL_CONDITIONAL)
973                 property_append_cf_conditions(&dict,
974                         req->cf_list[CALL_FORWARDING_TYPE_NOT_REACHABLE],
975                         req->cls,
976                         cf_type_lut[CALL_FORWARDING_TYPE_NOT_REACHABLE]);
977
978         if (req->cf_type == CALL_FORWARDING_TYPE_BUSY ||
979                 req->cf_type == CALL_FORWARDING_TYPE_ALL ||
980                 req->cf_type == CALL_FORWARDING_TYPE_ALL_CONDITIONAL)
981                 property_append_cf_conditions(&dict,
982                         req->cf_list[CALL_FORWARDING_TYPE_BUSY],
983                         req->cls, cf_type_lut[CALL_FORWARDING_TYPE_BUSY]);
984
985         dbus_message_iter_close_container(&vstruct, &dict);
986
987         dbus_message_iter_close_container(&variant, &vstruct);
988
989         dbus_message_iter_close_container(&iter, &variant);
990
991         return reply;
992 }
993
994 static void ss_set_query_cf_callback(const struct ofono_error *error, int total,
995                         const struct ofono_call_forwarding_condition *list,
996                         void *data)
997 {
998         struct ofono_call_forwarding *cf = data;
999         GSList *l;
1000         DBusMessage *reply;
1001
1002         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
1003                 ofono_error("Setting succeeded, but query failed");
1004                 cf->flags &= ~CALL_FORWARDING_FLAG_CACHED;
1005                 reply = __ofono_error_failed(cf->pending);
1006                 __ofono_dbus_pending_reply(&cf->pending, reply);
1007                 return;
1008         }
1009
1010         l = cf_cond_list_create(total, list);
1011         DBG("%s conditions:", cf_type_lut[cf->query_next]);
1012         cf_cond_list_print(l);
1013
1014         cf->ss_req->cf_list[cf->query_next] = l;
1015
1016         if (cf->query_next == cf->query_end) {
1017                 reply = cf_ss_control_reply(cf, cf->ss_req);
1018                 __ofono_dbus_pending_reply(&cf->pending, reply);
1019                 g_free(cf->ss_req);
1020                 cf->ss_req = NULL;
1021         }
1022
1023         set_new_cond_list(cf, cf->query_next, l);
1024
1025         if (cf->query_next != cf->query_end) {
1026                 cf->query_next++;
1027                 ss_set_query_next_cf_cond(cf);
1028         }
1029 }
1030
1031 static void ss_set_query_next_cf_cond(struct ofono_call_forwarding *cf)
1032 {
1033         cf->driver->query(cf, cf->query_next, BEARER_CLASS_DEFAULT,
1034                         ss_set_query_cf_callback, cf);
1035 }
1036
1037 static void cf_ss_control_callback(const struct ofono_error *error, void *data)
1038 {
1039         struct ofono_call_forwarding *cf = data;
1040
1041         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
1042                 DBG("Error occurred during cf ss control set/erasure");
1043
1044                 __ofono_dbus_pending_reply(&cf->pending,
1045                                         __ofono_error_failed(cf->pending));
1046                 g_free(cf->ss_req);
1047                 cf->ss_req = NULL;
1048                 return;
1049         }
1050
1051         ss_set_query_next_cf_cond(cf);
1052 }
1053
1054 static gboolean cf_ss_control(int type, const char *sc,
1055                                 const char *sia, const char *sib,
1056                                 const char *sic, const char *dn,
1057                                 DBusMessage *msg, void *data)
1058 {
1059         struct ofono_call_forwarding *cf = data;
1060         DBusConnection *conn = ofono_dbus_get_connection();
1061         int cls = BEARER_CLASS_SS_DEFAULT;
1062         int timeout = DEFAULT_NO_REPLY_TIMEOUT;
1063         int cf_type;
1064         DBusMessage *reply;
1065         struct ofono_phone_number ph;
1066         void *operation = NULL;
1067
1068         /* Before we do anything, make sure we're actually initialized */
1069         if (cf == NULL)
1070                 return FALSE;
1071
1072         if (__ofono_call_forwarding_is_busy(cf)) {
1073                 reply = __ofono_error_busy(msg);
1074                 g_dbus_send_message(conn, reply);
1075
1076                 return TRUE;
1077         }
1078
1079         DBG("Received call forwarding ss control request");
1080
1081         DBG("type: %d, sc: %s, sia: %s, sib: %s, sic: %s, dn: %s",
1082                 type, sc, sia, sib, sic, dn);
1083
1084         if (!strcmp(sc, "21"))
1085                 cf_type = CALL_FORWARDING_TYPE_UNCONDITIONAL;
1086         else if (!strcmp(sc, "67"))
1087                 cf_type = CALL_FORWARDING_TYPE_BUSY;
1088         else if (!strcmp(sc, "61"))
1089                 cf_type = CALL_FORWARDING_TYPE_NO_REPLY;
1090         else if (!strcmp(sc, "62"))
1091                 cf_type = CALL_FORWARDING_TYPE_NOT_REACHABLE;
1092         else if (!strcmp(sc, "002"))
1093                 cf_type = CALL_FORWARDING_TYPE_ALL;
1094         else if (!strcmp(sc, "004"))
1095                 cf_type = CALL_FORWARDING_TYPE_ALL_CONDITIONAL;
1096         else
1097                 return FALSE;
1098
1099         if (strlen(sia) &&
1100                         (type == SS_CONTROL_TYPE_QUERY ||
1101                                 type == SS_CONTROL_TYPE_ERASURE ||
1102                                 type == SS_CONTROL_TYPE_DEACTIVATION))
1103                 goto error;
1104
1105         /*
1106          * Activation / Registration is figured context specific according to
1107          * 22.030 Section 6.5.2 "The UE shall determine from the context
1108          * whether, an entry of a single *, activation or registration
1109          * was intended."
1110          */
1111         if (type == SS_CONTROL_TYPE_ACTIVATION && strlen(sia) > 0)
1112                 type = SS_CONTROL_TYPE_REGISTRATION;
1113
1114         if (type == SS_CONTROL_TYPE_REGISTRATION &&
1115                         !valid_phone_number_format(sia))
1116                 goto error;
1117
1118         if (strlen(sib) > 0) {
1119                 long service_code;
1120                 char *end;
1121
1122                 service_code = strtoul(sib, &end, 10);
1123
1124                 if (end == sib || *end != '\0')
1125                         goto error;
1126
1127                 cls = mmi_service_code_to_bearer_class(service_code);
1128
1129                 if (cls == 0)
1130                         goto error;
1131         }
1132
1133         if (strlen(sic) > 0) {
1134                 char *end;
1135
1136                 if  (type != SS_CONTROL_TYPE_REGISTRATION)
1137                         goto error;
1138
1139                 if (cf_type != CALL_FORWARDING_TYPE_ALL &&
1140                         cf_type != CALL_FORWARDING_TYPE_ALL_CONDITIONAL &&
1141                         cf_type != CALL_FORWARDING_TYPE_NO_REPLY)
1142                         goto error;
1143
1144                 timeout = strtoul(sic, &end, 10);
1145
1146                 if (end == sic || *end != '\0')
1147                         goto error;
1148
1149                 if (timeout < 1 || timeout > 30)
1150                         goto error;
1151         }
1152
1153         switch (type) {
1154         case SS_CONTROL_TYPE_REGISTRATION:
1155                 operation = cf->driver->registration;
1156                 break;
1157         case SS_CONTROL_TYPE_ACTIVATION:
1158                 operation = cf->driver->activation;
1159                 break;
1160         case SS_CONTROL_TYPE_DEACTIVATION:
1161                 operation = cf->driver->deactivation;
1162                 break;
1163         case SS_CONTROL_TYPE_ERASURE:
1164                 operation = cf->driver->erasure;
1165                 break;
1166         case SS_CONTROL_TYPE_QUERY:
1167                 operation = cf->driver->query;
1168                 break;
1169         }
1170
1171         if (operation == NULL) {
1172                 reply = __ofono_error_not_implemented(msg);
1173                 g_dbus_send_message(conn, reply);
1174
1175                 return TRUE;
1176         }
1177
1178         cf->ss_req = g_try_new0(struct cf_ss_request, 1);
1179
1180         if (cf->ss_req == NULL) {
1181                 reply = __ofono_error_failed(msg);
1182                 g_dbus_send_message(conn, reply);
1183
1184                 return TRUE;
1185         }
1186
1187         cf->ss_req->ss_type = type;
1188         cf->ss_req->cf_type = cf_type;
1189         cf->ss_req->cls = cls;
1190
1191         cf->pending = dbus_message_ref(msg);
1192
1193         switch (cf->ss_req->cf_type) {
1194         case CALL_FORWARDING_TYPE_ALL:
1195                 cf->query_next = CALL_FORWARDING_TYPE_UNCONDITIONAL;
1196                 cf->query_end = CALL_FORWARDING_TYPE_NOT_REACHABLE;
1197                 break;
1198         case CALL_FORWARDING_TYPE_ALL_CONDITIONAL:
1199                 cf->query_next = CALL_FORWARDING_TYPE_BUSY;
1200                 cf->query_end = CALL_FORWARDING_TYPE_NOT_REACHABLE;
1201                 break;
1202         default:
1203                 cf->query_next = cf->ss_req->cf_type;
1204                 cf->query_end = cf->ss_req->cf_type;
1205                 break;
1206         }
1207
1208         /*
1209          * Some modems don't understand all classes very well, particularly
1210          * the older models.  So if the bearer class is the default, we
1211          * just use the more commonly understood value of 7 since BEARER_SMS
1212          * is not applicable to CallForwarding conditions according to 22.004
1213          * Annex A
1214          */
1215         if (cls == BEARER_CLASS_SS_DEFAULT)
1216                 cls = BEARER_CLASS_DEFAULT;
1217
1218         switch (cf->ss_req->ss_type) {
1219         case SS_CONTROL_TYPE_REGISTRATION:
1220                 string_to_phone_number(sia, &ph);
1221                 cf->driver->registration(cf, cf_type, cls, &ph, timeout,
1222                                         cf_ss_control_callback, cf);
1223                 break;
1224         case SS_CONTROL_TYPE_ACTIVATION:
1225                 cf->driver->activation(cf, cf_type, cls, cf_ss_control_callback,
1226                                         cf);
1227                 break;
1228         case SS_CONTROL_TYPE_DEACTIVATION:
1229                 cf->driver->deactivation(cf, cf_type, cls,
1230                                         cf_ss_control_callback, cf);
1231                 break;
1232         case SS_CONTROL_TYPE_ERASURE:
1233                 cf->driver->erasure(cf, cf_type, cls, cf_ss_control_callback,
1234                                         cf);
1235                 break;
1236         case SS_CONTROL_TYPE_QUERY:
1237                 ss_set_query_next_cf_cond(cf);
1238                 break;
1239         }
1240
1241         return TRUE;
1242
1243 error:
1244         reply = __ofono_error_invalid_format(msg);
1245         g_dbus_send_message(conn, reply);
1246         return TRUE;
1247 }
1248
1249 static void cf_register_ss_controls(struct ofono_call_forwarding *cf)
1250 {
1251         __ofono_ussd_ssc_register(cf->ussd, "21", cf_ss_control, cf, NULL);
1252         __ofono_ussd_ssc_register(cf->ussd, "67", cf_ss_control, cf, NULL);
1253         __ofono_ussd_ssc_register(cf->ussd, "61", cf_ss_control, cf, NULL);
1254         __ofono_ussd_ssc_register(cf->ussd, "62", cf_ss_control, cf, NULL);
1255
1256         __ofono_ussd_ssc_register(cf->ussd, "002", cf_ss_control, cf, NULL);
1257         __ofono_ussd_ssc_register(cf->ussd, "004", cf_ss_control, cf, NULL);
1258 }
1259
1260 static void cf_unregister_ss_controls(struct ofono_call_forwarding *cf)
1261 {
1262         __ofono_ussd_ssc_unregister(cf->ussd, "21");
1263         __ofono_ussd_ssc_unregister(cf->ussd, "67");
1264         __ofono_ussd_ssc_unregister(cf->ussd, "61");
1265         __ofono_ussd_ssc_unregister(cf->ussd, "62");
1266
1267         __ofono_ussd_ssc_unregister(cf->ussd, "002");
1268         __ofono_ussd_ssc_unregister(cf->ussd, "004");
1269 }
1270
1271 gboolean __ofono_call_forwarding_is_busy(struct ofono_call_forwarding *cf)
1272 {
1273         return cf->pending ? TRUE : FALSE;
1274 }
1275
1276 static void sim_cfis_read_cb(int ok, int total_length, int record,
1277                         const unsigned char *data,
1278                         int record_length, void *userdata)
1279 {
1280         struct ofono_call_forwarding *cf = userdata;
1281         DBusConnection *conn = ofono_dbus_get_connection();
1282         const char *path = __ofono_atom_get_path(cf->atom);
1283
1284         if (!ok || record_length < 16 || total_length < record_length) {
1285                 cf->cfis_record_id = 0;
1286                 return;
1287         }
1288
1289         /*
1290          * Multiple Subscriber Profile number which can have values 1-4.
1291          * Profile id 1 is assumed as the current profile.
1292          */
1293         if (data[0] != 1)
1294                 return;
1295
1296         cf->cfis_record_id = record;
1297
1298         if (cf->flags & CALL_FORWARDING_FLAG_CACHED)
1299                 return;
1300
1301         /*
1302          * For now we only support Voice, although Fax & all Data
1303          * basic services are applicable as well.
1304          */
1305         if (data[1] & 0x01) {
1306                 int ton_npi;
1307                 int number_len;
1308                 const char *number;
1309                 char attr[64];
1310                 struct ofono_call_forwarding_condition *cond;
1311                 dbus_bool_t status;
1312
1313                 number_len = data[2];
1314                 ton_npi = data[3];
1315
1316                 if (number_len > 11 || ton_npi == 0xff)
1317                         return;
1318
1319                 cond = g_try_new0(struct ofono_call_forwarding_condition, 1);
1320                 if (cond == NULL)
1321                         return;
1322
1323                 status = TRUE;
1324                 cond->status = TRUE;
1325                 cond->cls = BEARER_CLASS_VOICE;
1326                 cond->time = 0;
1327                 cond->phone_number.type = ton_npi;
1328
1329                 sim_extract_bcd_number(data + 4, number_len - 1,
1330                                         cond->phone_number.number);
1331                 number = phone_number_to_string(&cond->phone_number);
1332
1333                 snprintf(attr, sizeof(attr), "%s%s",
1334                         bearer_class_to_string(BEARER_CLASS_VOICE),
1335                         cf_type_lut[CALL_FORWARDING_TYPE_UNCONDITIONAL]);
1336
1337                 cf->cf_conditions[CALL_FORWARDING_TYPE_UNCONDITIONAL] =
1338                                                 g_slist_append(NULL, cond);
1339
1340                 ofono_dbus_signal_property_changed(conn, path,
1341                                         OFONO_CALL_FORWARDING_INTERFACE,
1342                                         attr, DBUS_TYPE_STRING, &number);
1343
1344                 ofono_dbus_signal_property_changed(conn, path,
1345                                         OFONO_CALL_FORWARDING_INTERFACE,
1346                                         "ForwardingFlagOnSim",
1347                                         DBUS_TYPE_BOOLEAN, &status);
1348         }
1349 }
1350
1351 static void sim_cphs_cff_read_cb(int ok, int total_length, int record,
1352                                 const unsigned char *data,
1353                                 int record_length, void *userdata)
1354 {
1355         struct ofono_call_forwarding *cf = userdata;
1356         DBusConnection *conn = ofono_dbus_get_connection();
1357         const char *path = __ofono_atom_get_path(cf->atom);
1358         dbus_bool_t cfu_voice;
1359
1360         if (!ok || total_length < 1)
1361                 return;
1362
1363         cf->flags |= CALL_FORWARDING_FLAG_CPHS_CFF;
1364
1365         if (cf->flags & CALL_FORWARDING_FLAG_CACHED)
1366                 return;
1367
1368         /*
1369          * For now we only support Voice, although Fax & all Data
1370          * basic services are applicable as well.
1371          */
1372         if ((data[0] & 0xf) != 0xA)
1373                 return;
1374
1375         cfu_voice = TRUE;
1376
1377         ofono_dbus_signal_property_changed(conn, path,
1378                                         OFONO_CALL_FORWARDING_INTERFACE,
1379                                         "ForwardingFlagOnSim",
1380                                         DBUS_TYPE_BOOLEAN, &cfu_voice);
1381 }
1382
1383 static void call_forwarding_unregister(struct ofono_atom *atom)
1384 {
1385         struct ofono_call_forwarding *cf = __ofono_atom_get_data(atom);
1386         const char *path = __ofono_atom_get_path(cf->atom);
1387         DBusConnection *conn = ofono_dbus_get_connection();
1388         struct ofono_modem *modem = __ofono_atom_get_modem(cf->atom);
1389
1390         ofono_modem_remove_interface(modem, OFONO_CALL_FORWARDING_INTERFACE);
1391         g_dbus_unregister_interface(conn, path,
1392                                         OFONO_CALL_FORWARDING_INTERFACE);
1393
1394         if (cf->sim_context) {
1395                 ofono_sim_context_free(cf->sim_context);
1396                 cf->sim_context = NULL;
1397         }
1398
1399         if (cf->ussd)
1400                 cf_unregister_ss_controls(cf);
1401
1402         if (cf->ussd_watch)
1403                 __ofono_modem_remove_atom_watch(modem, cf->ussd_watch);
1404
1405         cf->flags = 0;
1406 }
1407
1408 static void sim_cfis_changed(int id, void *userdata)
1409 {
1410         struct ofono_call_forwarding *cf = userdata;
1411
1412         if (!(cf->flags & CALL_FORWARDING_FLAG_CACHED))
1413                 return;
1414
1415         /*
1416          * If the values are cached it's because at least one client
1417          * requested them and we need to notify them about this
1418          * change.  However the authoritative source of current
1419          * Call-Forwarding settings is the network operator and the
1420          * query can take a noticeable amount of time.  Instead of
1421          * sending PropertyChanged, we reregister the Call Forwarding
1422          * atom.  The client will invoke GetProperties only if it
1423          * is still interested.
1424          */
1425         call_forwarding_unregister(cf->atom);
1426         ofono_call_forwarding_register(cf);
1427 }
1428
1429 static void sim_read_cf_indicator(struct ofono_call_forwarding *cf)
1430 {
1431         if (__ofono_sim_service_available(cf->sim,
1432                         SIM_UST_SERVICE_CFIS,
1433                         SIM_SST_SERVICE_CFIS) == TRUE) {
1434                 ofono_sim_read(cf->sim_context, SIM_EFCFIS_FILEID,
1435                                 OFONO_SIM_FILE_STRUCTURE_FIXED,
1436                                 sim_cfis_read_cb, cf);
1437                 ofono_sim_add_file_watch(cf->sim_context, SIM_EFCFIS_FILEID,
1438                                                 sim_cfis_changed, cf, NULL);
1439         } else {
1440                 ofono_sim_read(cf->sim_context, SIM_EF_CPHS_CFF_FILEID,
1441                                 OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
1442                                 sim_cphs_cff_read_cb, cf);
1443                 ofono_sim_add_file_watch(cf->sim_context,
1444                                                 SIM_EF_CPHS_CFF_FILEID,
1445                                                 sim_cfis_changed, cf, NULL);
1446         }
1447 }
1448
1449 int ofono_call_forwarding_driver_register(
1450                                 const struct ofono_call_forwarding_driver *d)
1451 {
1452         DBG("driver: %p, name: %s", d, d->name);
1453
1454         if (d->probe == NULL)
1455                 return -EINVAL;
1456
1457         g_drivers = g_slist_prepend(g_drivers, (void *) d);
1458
1459         return 0;
1460 }
1461
1462 void ofono_call_forwarding_driver_unregister(
1463                                 const struct ofono_call_forwarding_driver *d)
1464 {
1465         DBG("driver: %p, name: %s", d, d->name);
1466
1467         g_drivers = g_slist_remove(g_drivers, (void *) d);
1468 }
1469
1470 static void call_forwarding_remove(struct ofono_atom *atom)
1471 {
1472         struct ofono_call_forwarding *cf = __ofono_atom_get_data(atom);
1473
1474         DBG("atom: %p", atom);
1475
1476         if (cf == NULL)
1477                 return;
1478
1479         if (cf->driver && cf->driver->remove)
1480                 cf->driver->remove(cf);
1481
1482         cf_clear_all(cf);
1483
1484         g_free(cf);
1485 }
1486
1487 struct ofono_call_forwarding *ofono_call_forwarding_create(
1488                                                 struct ofono_modem *modem,
1489                                                 unsigned int vendor,
1490                                                 const char *driver, void *data)
1491 {
1492         struct ofono_call_forwarding *cf;
1493         GSList *l;
1494
1495         if (driver == NULL)
1496                 return NULL;
1497
1498         cf = g_try_new0(struct ofono_call_forwarding, 1);
1499
1500         if (cf == NULL)
1501                 return NULL;
1502
1503         cf->atom = __ofono_modem_add_atom(modem,
1504                                                 OFONO_ATOM_TYPE_CALL_FORWARDING,
1505                                                 call_forwarding_remove, cf);
1506         for (l = g_drivers; l; l = l->next) {
1507                 const struct ofono_call_forwarding_driver *drv = l->data;
1508
1509                 if (g_strcmp0(drv->name, driver))
1510                         continue;
1511
1512                 if (drv->probe(cf, vendor, data) < 0)
1513                         continue;
1514
1515                 cf->driver = drv;
1516                 break;
1517         }
1518
1519         return cf;
1520 }
1521
1522 static void ussd_watch(struct ofono_atom *atom,
1523                         enum ofono_atom_watch_condition cond, void *data)
1524 {
1525         struct ofono_call_forwarding *cf = data;
1526
1527         if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
1528                 cf->ussd = NULL;
1529                 return;
1530         }
1531
1532         cf->ussd = __ofono_atom_get_data(atom);
1533         cf_register_ss_controls(cf);
1534 }
1535
1536 void ofono_call_forwarding_register(struct ofono_call_forwarding *cf)
1537 {
1538         DBusConnection *conn = ofono_dbus_get_connection();
1539         const char *path = __ofono_atom_get_path(cf->atom);
1540         struct ofono_modem *modem = __ofono_atom_get_modem(cf->atom);
1541
1542         if (!g_dbus_register_interface(conn, path,
1543                                         OFONO_CALL_FORWARDING_INTERFACE,
1544                                         cf_methods, cf_signals, NULL, cf,
1545                                         NULL)) {
1546                 ofono_error("Could not create %s interface",
1547                                 OFONO_CALL_FORWARDING_INTERFACE);
1548
1549                 return;
1550         }
1551
1552         ofono_modem_add_interface(modem, OFONO_CALL_FORWARDING_INTERFACE);
1553
1554         cf->sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
1555         if (cf->sim) {
1556                 cf->sim_context = ofono_sim_context_create(cf->sim);
1557                 sim_read_cf_indicator(cf);
1558         }
1559
1560         cf->ussd_watch = __ofono_modem_add_atom_watch(modem,
1561                                         OFONO_ATOM_TYPE_USSD,
1562                                         ussd_watch, cf, NULL);
1563
1564         __ofono_atom_register(cf->atom, call_forwarding_unregister);
1565 }
1566
1567 void ofono_call_forwarding_remove(struct ofono_call_forwarding *cf)
1568 {
1569         __ofono_atom_free(cf->atom);
1570 }
1571
1572 void ofono_call_forwarding_set_data(struct ofono_call_forwarding *cf,
1573                                                                 void *data)
1574 {
1575         cf->driver_data = data;
1576 }
1577
1578 void *ofono_call_forwarding_get_data(struct ofono_call_forwarding *cf)
1579 {
1580         return cf->driver_data;
1581 }