Upgrade ofono to 1.11 and merge to 2.0alpha
[profile/ivi/ofono.git] / src / message-waiting.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
29 #include <dbus/dbus.h>
30 #include <glib.h>
31 #include <gdbus.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34
35 #include "ofono.h"
36
37 #include "common.h"
38 #include "util.h"
39 #include "simutil.h"
40 #include "smsutil.h"
41
42 struct mailbox_state {
43         gboolean indication;
44         unsigned char message_count;
45 };
46
47 struct ofono_message_waiting {
48         struct mailbox_state messages[5];
49         unsigned char efmwis_length;
50         unsigned char efmbdn_length;
51         unsigned char efmbdn_record_id[5];
52         unsigned int efmbdn_watch;
53         unsigned char ef_cphs_mwis_length;
54         unsigned char ef_cphs_mbdn_length;
55         unsigned int ef_cphs_mbdn_watch;
56         gboolean mbdn_not_provided;
57         gboolean cphs_mbdn_not_provided;
58         struct ofono_phone_number mailbox_number[5];
59         struct ofono_sim *sim;
60         struct ofono_sim_context *sim_context;
61         struct ofono_atom *atom;
62 };
63
64 struct mbdn_set_request {
65         struct ofono_message_waiting *mw;
66         int mailbox;
67         struct ofono_phone_number number;
68         DBusMessage *msg;
69         gboolean cphs;
70 };
71
72 static const char *mw_message_waiting_property_name[5] = {
73         "VoicemailWaiting",
74 #if 0
75         "FaxWaiting",
76         "EmailWaiting",
77         "OtherWaiting",
78         "VideomailWaiting",
79 #endif
80 };
81
82 static const char *mw_message_count_property_name[5] = {
83         "VoicemailMessageCount",
84 #if 0
85         "FaxMessageCount",
86         "EmailMessageCount",
87         "OtherMessageCount",
88         "VideomailMessageCount",
89 #endif
90 };
91
92 static const char *mw_mailbox_property_name[5] = {
93         "VoicemailMailboxNumber",
94 #if 0
95         "FaxMailboxNumber",
96         "EmailMailboxNumber",
97         "OtherMailboxNumber",
98         "VideomailMailboxNumber",
99 #endif
100 };
101
102 static const int mw_mailbox_to_cphs_record[5] = {
103         1, /* Line 1 mailbox */
104         4, /* Fax mailbox */
105         0,
106         3, /* Data mailbox */
107         0,
108 };
109
110 static void mbdn_set_cb(int ok, void *data);
111
112 static DBusMessage *mw_get_properties(DBusConnection *conn,
113                                         DBusMessage *msg, void *data)
114 {
115         struct ofono_message_waiting *mw = data;
116         DBusMessage *reply;
117         DBusMessageIter iter;
118         DBusMessageIter dict;
119         int i;
120         dbus_bool_t indication;
121         unsigned char count;
122         const char *number;
123
124         reply = dbus_message_new_method_return(msg);
125         if (reply == NULL)
126                 return NULL;
127
128         dbus_message_iter_init_append(reply, &iter);
129
130         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
131                         OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict);
132
133         for (i = 0; i < 5; i++) {
134                 if (mw_message_waiting_property_name[i]) {
135                         indication = mw->messages[i].indication;
136
137                         ofono_dbus_dict_append(&dict,
138                                         mw_message_waiting_property_name[i],
139                                         DBUS_TYPE_BOOLEAN, &indication);
140                 }
141
142                 if (mw_message_count_property_name[i]) {
143                         count = mw->messages[i].message_count;
144
145                         ofono_dbus_dict_append(&dict,
146                                         mw_message_count_property_name[i],
147                                         DBUS_TYPE_BYTE, &count);
148                 }
149
150                 if (mw_mailbox_property_name[i]) {
151                         number = phone_number_to_string(&mw->mailbox_number[i]);
152
153                         ofono_dbus_dict_append(&dict,
154                                         mw_mailbox_property_name[i],
155                                         DBUS_TYPE_STRING, &number);
156                 }
157         }
158
159         dbus_message_iter_close_container(&iter, &dict);
160
161         return reply;
162 }
163
164 static void cphs_mbdn_sync_cb(int ok, void *data)
165 {
166         struct mbdn_set_request *req = data;
167
168         if (!ok)
169                 ofono_info("Failed to synchronize CPHS MBDN record");
170
171         g_free(req);
172 }
173
174 static DBusMessage *set_cphs_mbdn(struct ofono_message_waiting *mw,
175                                         gboolean sync,
176                                         int mailbox,
177                                         const char *number,
178                                         DBusMessage *msg)
179 {
180         struct mbdn_set_request *req;
181         unsigned char efmbdn[255];
182
183         if ((mw->ef_cphs_mbdn_length && !mw_mailbox_to_cphs_record[mailbox]) ||
184                         mw->cphs_mbdn_not_provided == TRUE) {
185                 if (msg)
186                         return __ofono_error_not_supported(msg);
187
188                 return NULL;
189         }
190
191         if (mw->ef_cphs_mbdn_length == 0) {
192                 if (msg)
193                         return __ofono_error_sim_not_ready(msg);
194
195                 return NULL;
196         }
197
198         req = g_new0(struct mbdn_set_request, 1);
199
200         req->mw = mw;
201         req->mailbox = mailbox;
202         string_to_phone_number(number, &req->number);
203         req->cphs = TRUE;
204
205         sim_adn_build(efmbdn, req->mw->ef_cphs_mbdn_length,
206                         &req->number, NULL);
207
208         if (ofono_sim_write(mw->sim_context, SIM_EF_CPHS_MBDN_FILEID,
209                         sync ? cphs_mbdn_sync_cb : mbdn_set_cb,
210                         OFONO_SIM_FILE_STRUCTURE_FIXED,
211                         mw_mailbox_to_cphs_record[mailbox],
212                         efmbdn, mw->ef_cphs_mbdn_length, req) == -1) {
213                 g_free(req);
214
215                 if (msg)
216                         return __ofono_error_failed(msg);
217         } else
218                 req->msg = msg ? dbus_message_ref(msg) : NULL;
219
220         return NULL;
221 }
222
223 static void mbdn_set_cb(int ok, void *data)
224 {
225         struct mbdn_set_request *req = data;
226         struct ofono_phone_number *old = &req->mw->mailbox_number[req->mailbox];
227         const char *property;
228         DBusMessage *reply = NULL;
229
230         if (!ok) {
231                 if (req->msg)
232                         reply = __ofono_error_failed(req->msg);
233
234                 goto out;
235         }
236
237         if (req->msg)
238                 reply = dbus_message_new_method_return(req->msg);
239
240         if (g_str_equal(req->number.number, old->number) &&
241                         req->number.type == old->type)
242                 goto out;
243
244         memcpy(old, &req->number, sizeof(struct ofono_phone_number));
245
246         property = mw_mailbox_property_name[req->mailbox];
247
248         if (property) {
249                 DBusConnection *conn = ofono_dbus_get_connection();
250                 const char *path = __ofono_atom_get_path(req->mw->atom);
251                 const char *number;
252
253                 number = phone_number_to_string(old);
254
255                 ofono_dbus_signal_property_changed(conn, path,
256                                                 OFONO_MESSAGE_WAITING_INTERFACE,
257                                                 property, DBUS_TYPE_STRING,
258                                                 &number);
259         }
260
261         /*
262          * Make a single attempt at keeping the CPHS version of the file
263          * in sync.
264          */
265         if (req->cphs == FALSE)
266                 set_cphs_mbdn(req->mw, TRUE, req->mailbox,
267                                 phone_number_to_string(&req->number), NULL);
268
269 out:
270         if (req->msg && reply)
271                 __ofono_dbus_pending_reply(&req->msg, reply);
272
273         g_free(req);
274 }
275
276 static DBusMessage *set_mbdn(struct ofono_message_waiting *mw, int mailbox,
277                         const char *number, DBusMessage *msg)
278 {
279         struct mbdn_set_request *req;
280         unsigned char efmbdn[255];
281
282         /*
283          * If we have no 3GPP EFmbdn on the card, maybe the
284          * CPHS version is available
285          */
286         if ((mw->efmbdn_length > 0 && mw->efmbdn_record_id[mailbox] == 0) ||
287                         mw->mbdn_not_provided == TRUE)
288                 return set_cphs_mbdn(mw, FALSE, mailbox, number, msg);
289
290         if (mw->efmbdn_length == 0) {
291                 if (msg)
292                         return __ofono_error_sim_not_ready(msg);
293
294                 return NULL;
295         }
296
297         req = g_new0(struct mbdn_set_request, 1);
298
299         req->mw = mw;
300         req->mailbox = mailbox;
301         string_to_phone_number(number, &req->number);
302         req->cphs = FALSE;
303
304         sim_adn_build(efmbdn, req->mw->efmbdn_length, &req->number, NULL);
305
306         if (ofono_sim_write(req->mw->sim_context, SIM_EFMBDN_FILEID,
307                                 mbdn_set_cb, OFONO_SIM_FILE_STRUCTURE_FIXED,
308                                 req->mw->efmbdn_record_id[mailbox],
309                                 efmbdn, req->mw->efmbdn_length, req) == -1) {
310                 g_free(req);
311
312                 if (msg)
313                         return __ofono_error_failed(msg);
314         } else
315                 req->msg = msg ? dbus_message_ref(msg) : NULL;
316
317         return NULL;
318 }
319
320 static DBusMessage *mw_set_property(DBusConnection *conn, DBusMessage *msg,
321                                         void *data)
322 {
323         struct ofono_message_waiting *mw = data;
324         DBusMessageIter iter;
325         DBusMessageIter var;
326         const char *name, *value;
327         int i;
328
329         if (!dbus_message_iter_init(msg, &iter))
330                 return __ofono_error_invalid_args(msg);
331
332         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
333                 return __ofono_error_invalid_args(msg);
334
335         dbus_message_iter_get_basic(&iter, &name);
336
337         for (i = 0; i < 5; i++)
338                 if (mw_mailbox_property_name[i] &&
339                                 !strcmp(name, mw_mailbox_property_name[i]))
340                         break;
341
342         if (i < 5) {
343                 const char *cur_number;
344
345                 dbus_message_iter_next(&iter);
346
347                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
348                         return __ofono_error_invalid_args(msg);
349
350                 dbus_message_iter_recurse(&iter, &var);
351
352                 if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
353                         return __ofono_error_invalid_args(msg);
354
355                 dbus_message_iter_get_basic(&var, &value);
356
357                 if (!valid_phone_number_format(value))
358                         return __ofono_error_invalid_format(msg);
359
360                 cur_number = phone_number_to_string(&mw->mailbox_number[i]);
361
362                 if (g_str_equal(cur_number, value))
363                         return dbus_message_new_method_return(msg);
364
365                 return set_mbdn(mw, i, value, msg);
366         }
367
368         return __ofono_error_invalid_args(msg);
369 }
370
371 static const GDBusMethodTable message_waiting_methods[] = {
372         { GDBUS_METHOD("GetProperties",
373                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
374                         mw_get_properties) },
375         { GDBUS_ASYNC_METHOD("SetProperty",
376                         GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
377                         NULL, mw_set_property) },
378         { }
379 };
380
381 static const GDBusSignalTable message_waiting_signals[] = {
382         { GDBUS_SIGNAL("PropertyChanged",
383                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
384         { }
385 };
386
387 static void update_indicator_and_emit(struct ofono_message_waiting *mw,
388                                         int mailbox,
389                                         struct mailbox_state *info)
390 {
391         dbus_bool_t indication;
392         unsigned char count;
393         DBusConnection *conn = ofono_dbus_get_connection();
394         const char *path = __ofono_atom_get_path(mw->atom);
395
396         if (mw->messages[mailbox].message_count == info->message_count &&
397                         mw->messages[mailbox].indication == info->indication)
398                 return;
399
400         memcpy(&mw->messages[mailbox], info, sizeof(struct mailbox_state));
401
402         indication = info->indication;
403         count = info->message_count;
404
405         if (mw_message_waiting_property_name[mailbox] == NULL)
406                 return;
407
408         ofono_dbus_signal_property_changed(conn, path,
409                                 OFONO_MESSAGE_WAITING_INTERFACE,
410                                 mw_message_waiting_property_name[mailbox],
411                                 DBUS_TYPE_BOOLEAN, &indication);
412
413         ofono_dbus_signal_property_changed(conn, path,
414                                 OFONO_MESSAGE_WAITING_INTERFACE,
415                                 mw_message_count_property_name[mailbox],
416                                 DBUS_TYPE_BYTE, &count);
417 }
418
419 static void mw_cphs_mwis_read_cb(int ok, int total_length, int record,
420                                         const unsigned char *data,
421                                         int record_length, void *userdata)
422 {
423         struct ofono_message_waiting *mw = userdata;
424         struct mailbox_state info;
425         unsigned char indication;
426
427         if (!ok || total_length < 1) {
428                 DBG("No CPHS MWIS on SIM");
429                 mw->ef_cphs_mwis_length = 0;
430                 return;
431         }
432
433         mw->ef_cphs_mwis_length = total_length;
434
435         if (mw->efmwis_length != 0)
436                 return;
437
438         /* Read Line 1 indication */
439         indication = data[0] & 0xf;
440         info.indication = (indication == 0xa);
441         info.message_count = 0;
442         update_indicator_and_emit(mw, 0, &info);
443
444         if (total_length == 1)
445                 return;
446
447         /* Read Fax indication */
448         indication = data[1] & 0xf;
449         info.indication = (indication == 0xa);
450         info.message_count = 0;
451         update_indicator_and_emit(mw, 1, &info);
452
453         /* Read Data indication, map to 'Other' */
454         indication = (data[1] >> 4) & 0xf;
455         info.indication = (indication == 0xa);
456         info.message_count = 0;
457         update_indicator_and_emit(mw, 3, &info);
458 }
459
460 static void mw_mwis_read_cb(int ok, int total_length, int record,
461                                 const unsigned char *data,
462                                 int record_length, void *userdata)
463 {
464         struct ofono_message_waiting *mw = userdata;
465         int i, status;
466         struct mailbox_state info;
467
468         if (!ok || record_length < 5) {
469                 ofono_error("Unable to read waiting messages numbers "
470                                 "from SIM");
471
472                 mw->efmwis_length = 0;
473
474                 return;
475         }
476
477         /* Handle only current identity (TODO: currently assumes first) */
478         if (record != 1)
479                 return;
480
481         status = data[0];
482         data++;
483
484         for (i = 0; i < 5 && i < record_length - 1; i++) {
485                 info.indication = (status >> i) & 1;
486                 info.message_count = info.indication ? data[0] : 0;
487
488                 update_indicator_and_emit(mw, i, &info);
489         }
490
491         mw->efmwis_length = record_length;
492 }
493
494 static void mw_cphs_mbdn_read_cb(int ok, int total_length, int record,
495                                 const unsigned char *data,
496                                 int record_length, void *userdata)
497 {
498         struct ofono_message_waiting *mw = userdata;
499         int i;
500         DBusConnection *conn = ofono_dbus_get_connection();
501         const char *value;
502
503         if (!ok || record_length < 14 || total_length < record_length) {
504                 ofono_error("Unable to read CPHS mailbox dialling numbers "
505                                 "from SIM");
506
507                 mw->ef_cphs_mbdn_length = 0;
508                 mw->cphs_mbdn_not_provided = TRUE;
509                 return;
510         }
511
512         for (i = 0; i < 5; i++)
513                 if (record == mw_mailbox_to_cphs_record[i])
514                         break;
515
516         if (i == 5)
517                 return;
518
519         mw->ef_cphs_mbdn_length = record_length;
520
521         if (mw->mbdn_not_provided != TRUE)
522                 return;
523
524         ofono_info("3GPP MBDN not provided, parsing CPHS..");
525
526         if (sim_adn_parse(data, record_length, &mw->mailbox_number[i], NULL) ==
527                         FALSE)
528                 mw->mailbox_number[i].number[0] = '\0';
529
530         if (mw_mailbox_property_name[i]) {
531                 const char *path = __ofono_atom_get_path(mw->atom);
532
533                 value = phone_number_to_string(&mw->mailbox_number[i]);
534
535                 ofono_dbus_signal_property_changed(conn, path,
536                                 OFONO_MESSAGE_WAITING_INTERFACE,
537                                 mw_mailbox_property_name[i],
538                                 DBUS_TYPE_STRING, &value);
539         }
540 }
541
542 static void mw_mbdn_read_cb(int ok, int total_length, int record,
543                                 const unsigned char *data,
544                                 int record_length, void *userdata)
545 {
546         struct ofono_message_waiting *mw = userdata;
547         int i;
548         DBusConnection *conn = ofono_dbus_get_connection();
549         const char *value;
550
551         if (!ok || record_length < 14 || total_length < record_length) {
552                 ofono_error("Unable to read mailbox dialling numbers "
553                                 "from SIM");
554
555                 mw->efmbdn_length = 0;
556                 mw->mbdn_not_provided = TRUE;
557                 return;
558         }
559
560         for (i = 0; i < 5; i++)
561                 if (record == mw->efmbdn_record_id[i])
562                         break;
563
564         if (i == 5)
565                 return;
566
567         if (sim_adn_parse(data, record_length, &mw->mailbox_number[i], NULL) ==
568                         FALSE)
569                 mw->mailbox_number[i].number[0] = '\0';
570
571         if (mw_mailbox_property_name[i]) {
572                 const char *path = __ofono_atom_get_path(mw->atom);
573
574                 value = phone_number_to_string(&mw->mailbox_number[i]);
575
576                 ofono_dbus_signal_property_changed(conn, path,
577                                 OFONO_MESSAGE_WAITING_INTERFACE,
578                                 mw_mailbox_property_name[i],
579                                 DBUS_TYPE_STRING, &value);
580         }
581
582         mw->efmbdn_length = record_length;
583 }
584
585 static void mw_mbdn_changed(int id, void *userdata)
586 {
587         struct ofono_message_waiting *mw = userdata;
588         int err;
589
590         mw->efmbdn_length = 0;
591         mw->mbdn_not_provided = FALSE;
592
593         err = ofono_sim_read(mw->sim_context, SIM_EFMBDN_FILEID,
594                                 OFONO_SIM_FILE_STRUCTURE_FIXED,
595                                 mw_mbdn_read_cb, mw);
596         if (err != 0)
597                 ofono_error("Unable to read EF-MBDN from SIM");
598 }
599
600 static void mw_cphs_mbdn_changed(int id, void *userdata)
601 {
602         struct ofono_message_waiting *mw = userdata;
603
604         mw->ef_cphs_mbdn_length = 0;
605         mw->cphs_mbdn_not_provided = FALSE;
606
607         ofono_sim_read(mw->sim_context, SIM_EF_CPHS_MBDN_FILEID,
608                         OFONO_SIM_FILE_STRUCTURE_FIXED,
609                         mw_cphs_mbdn_read_cb, mw);
610 }
611
612 const struct ofono_phone_number *__ofono_message_waiting_get_mbdn(
613                                         struct ofono_message_waiting *mw,
614                                         unsigned int index)
615 {
616         return &mw->mailbox_number[index];
617 }
618
619 static void mw_mbi_read_cb(int ok, int total_length, int record,
620                                 const unsigned char *data,
621                                 int record_length, void *userdata)
622 {
623         struct ofono_message_waiting *mw = userdata;
624         int i, err;
625
626         if (!ok || record_length < 4) {
627                 ofono_error("Unable to read mailbox identifies "
628                                 "from SIM");
629
630                 mw->efmbdn_length = 0;
631                 mw->mbdn_not_provided = TRUE;
632
633                 goto out;
634         }
635
636         /* Handle only current identity (TODO: currently assumes first) */
637         if (record != 1)
638                 return;
639
640         for (i = 0; i < 5 && i < record_length; i++)
641                 mw->efmbdn_record_id[i] = data[i];
642
643         err = ofono_sim_read(mw->sim_context, SIM_EFMBDN_FILEID,
644                                 OFONO_SIM_FILE_STRUCTURE_FIXED,
645                                 mw_mbdn_read_cb, mw);
646         mw->efmbdn_watch = ofono_sim_add_file_watch(mw->sim_context,
647                                                 SIM_EFMBDN_FILEID,
648                                                 mw_mbdn_changed, mw, NULL);
649
650         if (err != 0)
651                 ofono_error("Unable to read EF-MBDN from SIM");
652
653 out:
654         /*
655          * Mailbox numbers located in Byte 1, bits 6 & 5,
656          * Check for Activated & Allocated
657          */
658         if (__ofono_sim_cphs_service_available(mw->sim,
659                                         SIM_CPHS_SERVICE_MAILBOX_NUMBERS)) {
660                 ofono_sim_read(mw->sim_context, SIM_EF_CPHS_MBDN_FILEID,
661                                 OFONO_SIM_FILE_STRUCTURE_FIXED,
662                                 mw_cphs_mbdn_read_cb, mw);
663                 mw->ef_cphs_mbdn_watch = ofono_sim_add_file_watch(
664                                                 mw->sim_context,
665                                                 SIM_EF_CPHS_MBDN_FILEID,
666                                                 mw_cphs_mbdn_changed, mw, NULL);
667         }
668 }
669
670 static void mw_mwis_write_cb(int ok, void *userdata)
671 {
672         if (!ok)
673                 ofono_error("Writing new EF-MWIS failed");
674 }
675
676 static void mw_set_indicator(struct ofono_message_waiting *mw, int profile,
677                                 enum sms_mwi_type type,
678                                 gboolean present, unsigned char messages)
679 {
680         DBusConnection *conn = ofono_dbus_get_connection();
681         unsigned char efmwis[255];  /* Max record size */
682         int i;
683
684         if (mw == NULL)
685                 return;
686
687         /* Handle only current identity (TODO: currently assumes first) */
688         if (profile != 1)
689                 return;
690
691         if (mw->messages[type].indication == present &&
692                         mw->messages[type].message_count == messages)
693                 return;
694
695         if (mw->messages[type].indication != present) {
696                 dbus_bool_t indication;
697                 const char *path = __ofono_atom_get_path(mw->atom);
698
699                 indication = present;
700                 mw->messages[type].indication = present;
701
702                 if (mw_message_waiting_property_name[type])
703                         ofono_dbus_signal_property_changed(conn, path,
704                                         OFONO_MESSAGE_WAITING_INTERFACE,
705                                         mw_message_waiting_property_name[type],
706                                         DBUS_TYPE_BOOLEAN, &indication);
707         }
708
709         if (mw->messages[type].message_count != messages) {
710                 const char *path = __ofono_atom_get_path(mw->atom);
711
712                 mw->messages[type].message_count = messages;
713
714                 if (mw_message_waiting_property_name[type])
715                         ofono_dbus_signal_property_changed(conn, path,
716                                         OFONO_MESSAGE_WAITING_INTERFACE,
717                                         mw_message_count_property_name[type],
718                                         DBUS_TYPE_BYTE, &messages);
719         }
720
721         /* Writes MWI states and/or MBDN back to SIM */
722         if (mw->efmwis_length < 5) {
723                 if (mw->ef_cphs_mwis_length >= 1)
724                         goto try_cphs;
725
726                 ofono_error("Unable to update MWIS indicator");
727                 return;
728         }
729
730         /* Fill in numbers of messages in bytes 1 to X of EF-MWIS */
731         for (i = 0; i < 5 && i < mw->efmwis_length - 1; i++)
732                 efmwis[i + 1] = mw->messages[i].message_count;
733
734         /* Fill in indicator state bits in byte 0 */
735         for (i = 0; i < 5 && i < mw->efmwis_length - 1; i++)
736                 if (mw->messages[i].indication)
737                         efmwis[0] |= 1 << i;
738
739         if (ofono_sim_write(mw->sim_context, SIM_EFMWIS_FILEID,
740                                 mw_mwis_write_cb,
741                                 OFONO_SIM_FILE_STRUCTURE_FIXED, 1,
742                                 efmwis, mw->efmwis_length, mw) != 0) {
743                 ofono_error("Queuing a EF-MWI write to SIM failed");
744         }
745
746         if (mw->ef_cphs_mwis_length == 0)
747                 return;
748
749 try_cphs:
750         memset(efmwis, 0x55, 255);
751
752         efmwis[0] = mw->messages[0].indication ? 0xa : 0x5;
753
754         if (mw->ef_cphs_mwis_length > 1)
755                 efmwis[1] = mw->messages[1].indication ? 0xa : 0x5 |
756                         mw->messages[3].indication ? 0xa0 : 0x50;
757
758         if (ofono_sim_write(mw->sim_context, SIM_EF_CPHS_MWIS_FILEID,
759                                 mw_mwis_write_cb,
760                                 OFONO_SIM_FILE_STRUCTURE_TRANSPARENT, 0,
761                                 efmwis, mw->ef_cphs_mwis_length, mw) != 0)
762                 ofono_error("Queuing a EF-MWIS write to SIM failed (CPHS)");
763 }
764
765 static void handle_special_sms_iei(struct ofono_message_waiting *mw,
766                                         const guint8 *iei, gboolean *discard)
767 {
768         enum sms_mwi_type type;
769         int profile;
770         gboolean set;
771
772         /* Parse type & storage byte */
773         if (discard)
774                 *discard = (iei[0] & (1 << 7)) ? FALSE : TRUE;
775
776         type = iei[0] & 0x1f;
777         if (type > SMS_MWI_TYPE_OTHER) {
778                 if (type == (SMS_MWI_TYPE_OTHER | 4))
779                         type = SMS_MWI_TYPE_VIDEO;
780                 else
781                         /*
782                          * 23.040 9.2.3.24.2: "Terminals should be capable of
783                          * receiving any values in octet 1, even including
784                          * those marked as Reserved."  Treat Reserved as
785                          * "Other".
786                          */
787                         type = SMS_MWI_TYPE_OTHER;
788         }
789
790         set = iei[1] > 0 ? TRUE : FALSE;
791         profile = ((iei[0] >> 5) & 3) + 1;
792
793         mw_set_indicator(mw, profile, type, set, iei[1]);
794 }
795
796 static void handle_enhanced_voicemail_iei(struct ofono_message_waiting *mw,
797                                                 const guint8 *iei,
798                                                 gboolean *discard, int length)
799 {
800         int profile, n;
801         gboolean set;
802         struct sms_address mailbox_address;
803
804         if (length < 3)
805                 return;
806
807         /* ENHANCED_VOICE_MAIL_PDU_TYPE */
808         if (!(iei[0] & 1)) {
809                 /* 9.2.3.24.13.1 Enhanced Voice Mail Notification */
810
811                 /* MULTIPLE_SUBSCRIBER_PROFILE */
812                 profile = ((iei[0] >> 2) & 3) + 1;
813
814                 /* SM_STORAGE */
815                 if (discard)
816                         *discard = (iei[0] & (1 << 4)) ? FALSE : TRUE;
817
818                 /* VM_MAILBOX_ACCESS_ADDRESS */
819                 n = 0;
820                 if (!sms_decode_address_field(iei + 1, length - 1, &n,
821                                         FALSE, &mailbox_address))
822                         return;
823
824                 /* TODO: VM_MESSAGE_PRIORITY_INDICATION */
825
826                 /* Other parameters currently not supported */
827
828                 if (length < n + 3)
829                         return;
830
831                 set = iei[n + 1] > 0 ? TRUE : FALSE;
832                 mw_set_indicator(mw, profile, SMS_MWI_TYPE_VOICE,
833                                         set, iei[n + 1]);
834         } else {
835                 /* 9.2.3.24.13.2 Enhanced Voice Delete Confirmation */
836
837                 /* MULTIPLE_SUBSCRIBER_PROFILE */
838                 profile = ((iei[0] >> 2) & 3) + 1;
839
840                 /* SM_STORAGE */
841                 if (discard)
842                         *discard = (iei[0] & (1 << 4)) ? FALSE : TRUE;
843
844                 /* VM_MAILBOX_ACCESS_ADDRESS */
845                 n = 0;
846                 if (!sms_decode_address_field(iei + 1, length - 1, &n,
847                                         FALSE, &mailbox_address))
848                         return;
849
850                 /* Other parameters currently not supported */
851
852                 if (length < n + 3)
853                         return;
854
855                 set = iei[n + 1] > 0 ? TRUE : FALSE;
856                 mw_set_indicator(mw, profile, SMS_MWI_TYPE_VOICE,
857                                         set, iei[n + 1]);
858         }
859
860         if (mailbox_address.address[0] != '\0')
861                 set_mbdn(mw, SMS_MWI_TYPE_VOICE,
862                                 sms_address_to_string(&mailbox_address), NULL);
863 }
864
865 void __ofono_message_waiting_mwi(struct ofono_message_waiting *mw,
866                                         struct sms *sms, gboolean *out_discard)
867 {
868         gboolean active, discard;
869         enum sms_mwi_type type;
870         int profile = 1, iei_found = 0;
871
872         if (out_discard)
873                 *out_discard = FALSE;
874
875         /*
876          * Check MWI types in the order from highest priority to lowest
877          * because they must override one another.
878          */
879
880         if (sms->deliver.udhi) {
881                 guint8 evm_iei[140];
882                 struct sms_udh_iter iter;
883                 enum sms_iei iei;
884
885                 if (!sms_udh_iter_init(sms, &iter))
886                         return;
887
888                 while ((iei = sms_udh_iter_get_ie_type(&iter)) !=
889                                 SMS_IEI_INVALID) {
890                         switch (iei) {
891                         case SMS_IEI_ENHANCED_VOICE_MAIL_INFORMATION:
892                                 sms_udh_iter_get_ie_data(&iter, evm_iei);
893
894                                 handle_enhanced_voicemail_iei(mw, evm_iei,
895                                                 out_discard,
896                                                 sms_udh_iter_get_ie_length(
897                                                         &iter));
898                                 return;
899                         default:
900                                 break;
901                         }
902
903                         sms_udh_iter_next(&iter);
904                 }
905         }
906
907         if (sms->deliver.udhi) {
908                 guint8 special_iei[4];
909                 struct sms_udh_iter iter;
910                 enum sms_iei iei;
911
912                 if (!sms_udh_iter_init(sms, &iter))
913                         return;
914
915                 while ((iei = sms_udh_iter_get_ie_type(&iter)) !=
916                                 SMS_IEI_INVALID) {
917                         switch (iei) {
918                         case SMS_IEI_SPECIAL_MESSAGE_INDICATION:
919                                 if (sms_udh_iter_get_ie_length(&iter) != 2)
920                                         break;
921                                 sms_udh_iter_get_ie_data(&iter, special_iei);
922
923                                 handle_special_sms_iei(mw, special_iei,
924                                                 &discard);
925                                 if (out_discard)
926                                         *out_discard = *out_discard || discard;
927                                 iei_found = 1;
928                                 break;
929                         default:
930                                 break;
931                         }
932
933                         sms_udh_iter_next(&iter);
934                 }
935
936                 if (iei_found) {
937                         /*
938                          * 23.040 9.2.3.24.2 says "In the event of a
939                          * conflict between this setting and the setting
940                          * of the Data Coding Scheme (see 3GPP TS 23.038 [9])
941                          * then the message shall be stored if either the DCS
942                          * indicates this, or Octet 1 above indicates this."
943                          */
944                         if (sms_mwi_dcs_decode(sms->deliver.dcs, NULL,
945                                                 NULL, NULL, &discard)) {
946                                 if (out_discard)
947                                         *out_discard = *out_discard || discard;
948                         }
949
950                         return;
951                 }
952         }
953
954         if (sms_mwi_dcs_decode(sms->deliver.dcs, &type,
955                                 NULL, &active, out_discard)) {
956                 mw_set_indicator(mw, profile, type, active, 0);
957
958                 return;
959         }
960
961         if (sms->deliver.pid == SMS_PID_TYPE_RETURN_CALL)
962                 return;
963 }
964
965 static void message_waiting_unregister(struct ofono_atom *atom)
966 {
967         DBusConnection *conn = ofono_dbus_get_connection();
968         struct ofono_modem *modem = __ofono_atom_get_modem(atom);
969         const char *path = __ofono_atom_get_path(atom);
970         struct ofono_message_waiting *mw = __ofono_atom_get_data(atom);
971
972         if (mw->sim_context) {
973                 ofono_sim_context_free(mw->sim_context);
974                 mw->sim_context = NULL;
975         }
976
977         mw->sim = NULL;
978
979         g_dbus_unregister_interface(conn, path,
980                                         OFONO_MESSAGE_WAITING_INTERFACE);
981         ofono_modem_remove_interface(modem, OFONO_MESSAGE_WAITING_INTERFACE);
982 }
983
984 static void mw_mwis_changed(int id, void *userdata)
985 {
986         struct ofono_message_waiting *mw = userdata;
987
988         mw->efmwis_length = 0;
989
990         ofono_sim_read(mw->sim_context, SIM_EFMWIS_FILEID,
991                         OFONO_SIM_FILE_STRUCTURE_FIXED,
992                         mw_mwis_read_cb, mw);
993 }
994
995 static void mw_cphs_mwis_changed(int id, void *userdata)
996 {
997         struct ofono_message_waiting *mw = userdata;
998
999         mw->ef_cphs_mwis_length = 0;
1000
1001         ofono_sim_read(mw->sim_context, SIM_EF_CPHS_MWIS_FILEID,
1002                         OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
1003                         mw_cphs_mwis_read_cb, mw);
1004 }
1005
1006 static void mw_mbi_changed(int id, void *userdata)
1007 {
1008         struct ofono_message_waiting *mw = userdata;
1009
1010         mw->efmbdn_length = 0;
1011         mw->mbdn_not_provided = FALSE;
1012
1013         mw->ef_cphs_mbdn_length = 0;
1014         mw->cphs_mbdn_not_provided = FALSE;
1015
1016         ofono_sim_remove_file_watch(mw->sim_context, mw->efmbdn_watch);
1017         ofono_sim_remove_file_watch(mw->sim_context, mw->ef_cphs_mbdn_watch);
1018
1019         ofono_sim_read(mw->sim_context, SIM_EFMBI_FILEID,
1020                         OFONO_SIM_FILE_STRUCTURE_FIXED,
1021                         mw_mbi_read_cb, mw);
1022 }
1023
1024 void ofono_message_waiting_register(struct ofono_message_waiting *mw)
1025 {
1026         DBusConnection *conn;
1027         const char *path;
1028         struct ofono_modem *modem;
1029
1030         if (mw == NULL)
1031                 return;
1032
1033         conn = ofono_dbus_get_connection();
1034         modem = __ofono_atom_get_modem(mw->atom);
1035         path = __ofono_atom_get_path(mw->atom);
1036
1037         if (!g_dbus_register_interface(conn, path,
1038                                         OFONO_MESSAGE_WAITING_INTERFACE,
1039                                         message_waiting_methods,
1040                                         message_waiting_signals,
1041                                         NULL, mw, NULL)) {
1042                 ofono_error("Could not create %s interface",
1043                                 OFONO_MESSAGE_WAITING_INTERFACE);
1044                 return;
1045         }
1046
1047         ofono_modem_add_interface(modem, OFONO_MESSAGE_WAITING_INTERFACE);
1048
1049         mw->sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
1050         if (mw->sim) {
1051                 /* Assume that if sim atom exists, it is ready */
1052                 mw->sim_context = ofono_sim_context_create(mw->sim);
1053
1054                 /* Loads MWI states and MBDN from SIM */
1055                 ofono_sim_read(mw->sim_context, SIM_EFMWIS_FILEID,
1056                                 OFONO_SIM_FILE_STRUCTURE_FIXED,
1057                                 mw_mwis_read_cb, mw);
1058                 ofono_sim_read(mw->sim_context, SIM_EFMBI_FILEID,
1059                                 OFONO_SIM_FILE_STRUCTURE_FIXED,
1060                                 mw_mbi_read_cb, mw);
1061
1062                 /* Also read CPHS MWIS field */
1063                 ofono_sim_read(mw->sim_context, SIM_EF_CPHS_MWIS_FILEID,
1064                                 OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
1065                                 mw_cphs_mwis_read_cb, mw);
1066
1067                 /*
1068                  * The operator could send us SMS mwi updates, but let's be
1069                  * extra careful and track the file contents too.
1070                  */
1071                 ofono_sim_add_file_watch(mw->sim_context, SIM_EFMWIS_FILEID,
1072                                                 mw_mwis_changed, mw, NULL);
1073                 ofono_sim_add_file_watch(mw->sim_context,
1074                                                 SIM_EF_CPHS_MWIS_FILEID,
1075                                                 mw_cphs_mwis_changed, mw, NULL);
1076
1077                 ofono_sim_add_file_watch(mw->sim_context, SIM_EFMBI_FILEID,
1078                                                 mw_mbi_changed, mw, NULL);
1079         }
1080
1081         __ofono_atom_register(mw->atom, message_waiting_unregister);
1082 }
1083
1084 static void mw_remove(struct ofono_atom *atom)
1085 {
1086         struct ofono_message_waiting *mw = __ofono_atom_get_data(atom);
1087
1088         DBG("atom: %p", atom);
1089
1090         if (mw == NULL)
1091                 return;
1092
1093         g_free(mw);
1094 }
1095
1096 struct ofono_message_waiting *ofono_message_waiting_create(struct ofono_modem *modem)
1097 {
1098         struct ofono_message_waiting *mw;
1099
1100         mw = g_try_new0(struct ofono_message_waiting, 1);
1101
1102         if (mw == NULL)
1103                 return NULL;
1104
1105         mw->atom = __ofono_modem_add_atom(modem,
1106                                         OFONO_ATOM_TYPE_MESSAGE_WAITING,
1107                                         mw_remove, mw);
1108
1109         return mw;
1110 }
1111
1112 void ofono_message_waiting_remove(struct ofono_message_waiting *mw)
1113 {
1114         __ofono_atom_free(mw->atom);
1115 }