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