3 * oFono - Open Source Telephony
5 * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
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.
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.
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
29 #include <dbus/dbus.h>
33 #include <sys/types.h>
42 struct mailbox_state {
44 unsigned char message_count;
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;
64 struct mbdn_set_request {
65 struct ofono_message_waiting *mw;
67 struct ofono_phone_number number;
72 static const char *mw_message_waiting_property_name[5] = {
82 static const char *mw_message_count_property_name[5] = {
83 "VoicemailMessageCount",
88 "VideomailMessageCount",
92 static const char *mw_mailbox_property_name[5] = {
93 "VoicemailMailboxNumber",
98 "VideomailMailboxNumber",
102 static const int mw_mailbox_to_cphs_record[5] = {
103 1, /* Line 1 mailbox */
106 3, /* Data mailbox */
110 static void mbdn_set_cb(int ok, void *data);
112 static DBusMessage *mw_get_properties(DBusConnection *conn,
113 DBusMessage *msg, void *data)
115 struct ofono_message_waiting *mw = data;
117 DBusMessageIter iter;
118 DBusMessageIter dict;
120 dbus_bool_t indication;
124 reply = dbus_message_new_method_return(msg);
128 dbus_message_iter_init_append(reply, &iter);
130 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
131 OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict);
133 for (i = 0; i < 5; i++) {
134 if (mw_message_waiting_property_name[i]) {
135 indication = mw->messages[i].indication;
137 ofono_dbus_dict_append(&dict,
138 mw_message_waiting_property_name[i],
139 DBUS_TYPE_BOOLEAN, &indication);
142 if (mw_message_count_property_name[i]) {
143 count = mw->messages[i].message_count;
145 ofono_dbus_dict_append(&dict,
146 mw_message_count_property_name[i],
147 DBUS_TYPE_BYTE, &count);
150 if (mw_mailbox_property_name[i]) {
151 number = phone_number_to_string(&mw->mailbox_number[i]);
153 ofono_dbus_dict_append(&dict,
154 mw_mailbox_property_name[i],
155 DBUS_TYPE_STRING, &number);
159 dbus_message_iter_close_container(&iter, &dict);
164 static void cphs_mbdn_sync_cb(int ok, void *data)
166 struct mbdn_set_request *req = data;
169 ofono_info("Failed to synchronize CPHS MBDN record");
174 static DBusMessage *set_cphs_mbdn(struct ofono_message_waiting *mw,
180 struct mbdn_set_request *req;
181 unsigned char efmbdn[255];
183 if ((mw->ef_cphs_mbdn_length && !mw_mailbox_to_cphs_record[mailbox]) ||
184 mw->cphs_mbdn_not_provided == TRUE) {
186 return __ofono_error_not_supported(msg);
191 if (mw->ef_cphs_mbdn_length == 0) {
193 return __ofono_error_sim_not_ready(msg);
198 req = g_new0(struct mbdn_set_request, 1);
201 req->mailbox = mailbox;
202 string_to_phone_number(number, &req->number);
205 sim_adn_build(efmbdn, req->mw->ef_cphs_mbdn_length,
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) {
216 return __ofono_error_failed(msg);
218 req->msg = msg ? dbus_message_ref(msg) : NULL;
223 static void mbdn_set_cb(int ok, void *data)
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;
232 reply = __ofono_error_failed(req->msg);
238 reply = dbus_message_new_method_return(req->msg);
240 if (g_str_equal(req->number.number, old->number) &&
241 req->number.type == old->type)
244 memcpy(old, &req->number, sizeof(struct ofono_phone_number));
246 property = mw_mailbox_property_name[req->mailbox];
249 DBusConnection *conn = ofono_dbus_get_connection();
250 const char *path = __ofono_atom_get_path(req->mw->atom);
253 number = phone_number_to_string(old);
255 ofono_dbus_signal_property_changed(conn, path,
256 OFONO_MESSAGE_WAITING_INTERFACE,
257 property, DBUS_TYPE_STRING,
262 * Make a single attempt at keeping the CPHS version of the file
265 if (req->cphs == FALSE)
266 set_cphs_mbdn(req->mw, TRUE, req->mailbox,
267 phone_number_to_string(&req->number), NULL);
270 if (req->msg && reply)
271 __ofono_dbus_pending_reply(&req->msg, reply);
276 static DBusMessage *set_mbdn(struct ofono_message_waiting *mw, int mailbox,
277 const char *number, DBusMessage *msg)
279 struct mbdn_set_request *req;
280 unsigned char efmbdn[255];
283 * If we have no 3GPP EFmbdn on the card, maybe the
284 * CPHS version is available
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);
290 if (mw->efmbdn_length == 0) {
292 return __ofono_error_sim_not_ready(msg);
297 req = g_new0(struct mbdn_set_request, 1);
300 req->mailbox = mailbox;
301 string_to_phone_number(number, &req->number);
304 sim_adn_build(efmbdn, req->mw->efmbdn_length, &req->number, NULL);
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) {
313 return __ofono_error_failed(msg);
315 req->msg = msg ? dbus_message_ref(msg) : NULL;
320 static DBusMessage *mw_set_property(DBusConnection *conn, DBusMessage *msg,
323 struct ofono_message_waiting *mw = data;
324 DBusMessageIter iter;
326 const char *name, *value;
329 if (!dbus_message_iter_init(msg, &iter))
330 return __ofono_error_invalid_args(msg);
332 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
333 return __ofono_error_invalid_args(msg);
335 dbus_message_iter_get_basic(&iter, &name);
337 for (i = 0; i < 5; i++)
338 if (mw_mailbox_property_name[i] &&
339 !strcmp(name, mw_mailbox_property_name[i]))
343 const char *cur_number;
345 dbus_message_iter_next(&iter);
347 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
348 return __ofono_error_invalid_args(msg);
350 dbus_message_iter_recurse(&iter, &var);
352 if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
353 return __ofono_error_invalid_args(msg);
355 dbus_message_iter_get_basic(&var, &value);
357 if (!valid_phone_number_format(value))
358 return __ofono_error_invalid_format(msg);
360 cur_number = phone_number_to_string(&mw->mailbox_number[i]);
362 if (g_str_equal(cur_number, value))
363 return dbus_message_new_method_return(msg);
365 return set_mbdn(mw, i, value, msg);
368 return __ofono_error_invalid_args(msg);
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) },
381 static const GDBusSignalTable message_waiting_signals[] = {
382 { GDBUS_SIGNAL("PropertyChanged",
383 GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
387 static void update_indicator_and_emit(struct ofono_message_waiting *mw,
389 struct mailbox_state *info)
391 dbus_bool_t indication;
393 DBusConnection *conn = ofono_dbus_get_connection();
394 const char *path = __ofono_atom_get_path(mw->atom);
396 if (mw->messages[mailbox].message_count == info->message_count &&
397 mw->messages[mailbox].indication == info->indication)
400 memcpy(&mw->messages[mailbox], info, sizeof(struct mailbox_state));
402 indication = info->indication;
403 count = info->message_count;
405 if (mw_message_waiting_property_name[mailbox] == NULL)
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);
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);
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)
423 struct ofono_message_waiting *mw = userdata;
424 struct mailbox_state info;
425 unsigned char indication;
427 if (!ok || total_length < 1) {
428 DBG("No CPHS MWIS on SIM");
429 mw->ef_cphs_mwis_length = 0;
433 mw->ef_cphs_mwis_length = total_length;
435 if (mw->efmwis_length != 0)
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);
444 if (total_length == 1)
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);
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);
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)
464 struct ofono_message_waiting *mw = userdata;
466 struct mailbox_state info;
468 if (!ok || record_length < 5) {
469 ofono_error("Unable to read waiting messages numbers "
472 mw->efmwis_length = 0;
477 /* Handle only current identity (TODO: currently assumes first) */
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;
488 update_indicator_and_emit(mw, i, &info);
491 mw->efmwis_length = record_length;
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)
498 struct ofono_message_waiting *mw = userdata;
500 DBusConnection *conn = ofono_dbus_get_connection();
503 if (!ok || record_length < 14 || total_length < record_length) {
504 ofono_error("Unable to read CPHS mailbox dialling numbers "
507 mw->ef_cphs_mbdn_length = 0;
508 mw->cphs_mbdn_not_provided = TRUE;
512 for (i = 0; i < 5; i++)
513 if (record == mw_mailbox_to_cphs_record[i])
519 mw->ef_cphs_mbdn_length = record_length;
521 if (mw->mbdn_not_provided != TRUE)
524 ofono_info("3GPP MBDN not provided, parsing CPHS..");
526 if (sim_adn_parse(data, record_length, &mw->mailbox_number[i], NULL) ==
528 mw->mailbox_number[i].number[0] = '\0';
530 if (mw_mailbox_property_name[i]) {
531 const char *path = __ofono_atom_get_path(mw->atom);
533 value = phone_number_to_string(&mw->mailbox_number[i]);
535 ofono_dbus_signal_property_changed(conn, path,
536 OFONO_MESSAGE_WAITING_INTERFACE,
537 mw_mailbox_property_name[i],
538 DBUS_TYPE_STRING, &value);
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)
546 struct ofono_message_waiting *mw = userdata;
548 DBusConnection *conn = ofono_dbus_get_connection();
551 if (!ok || record_length < 14 || total_length < record_length) {
552 ofono_error("Unable to read mailbox dialling numbers "
555 mw->efmbdn_length = 0;
556 mw->mbdn_not_provided = TRUE;
560 for (i = 0; i < 5; i++)
561 if (record == mw->efmbdn_record_id[i])
567 if (sim_adn_parse(data, record_length, &mw->mailbox_number[i], NULL) ==
569 mw->mailbox_number[i].number[0] = '\0';
571 if (mw_mailbox_property_name[i]) {
572 const char *path = __ofono_atom_get_path(mw->atom);
574 value = phone_number_to_string(&mw->mailbox_number[i]);
576 ofono_dbus_signal_property_changed(conn, path,
577 OFONO_MESSAGE_WAITING_INTERFACE,
578 mw_mailbox_property_name[i],
579 DBUS_TYPE_STRING, &value);
582 mw->efmbdn_length = record_length;
585 static void mw_mbdn_changed(int id, void *userdata)
587 struct ofono_message_waiting *mw = userdata;
590 mw->efmbdn_length = 0;
591 mw->mbdn_not_provided = FALSE;
593 err = ofono_sim_read(mw->sim_context, SIM_EFMBDN_FILEID,
594 OFONO_SIM_FILE_STRUCTURE_FIXED,
595 mw_mbdn_read_cb, mw);
597 ofono_error("Unable to read EF-MBDN from SIM");
600 static void mw_cphs_mbdn_changed(int id, void *userdata)
602 struct ofono_message_waiting *mw = userdata;
604 mw->ef_cphs_mbdn_length = 0;
605 mw->cphs_mbdn_not_provided = FALSE;
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);
612 const struct ofono_phone_number *__ofono_message_waiting_get_mbdn(
613 struct ofono_message_waiting *mw,
616 return &mw->mailbox_number[index];
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)
623 struct ofono_message_waiting *mw = userdata;
626 if (!ok || record_length < 4) {
627 ofono_error("Unable to read mailbox identifies "
630 mw->efmbdn_length = 0;
631 mw->mbdn_not_provided = TRUE;
636 /* Handle only current identity (TODO: currently assumes first) */
640 for (i = 0; i < 5 && i < record_length; i++)
641 mw->efmbdn_record_id[i] = data[i];
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,
648 mw_mbdn_changed, mw, NULL);
651 ofono_error("Unable to read EF-MBDN from SIM");
655 * Mailbox numbers located in Byte 1, bits 6 & 5,
656 * Check for Activated & Allocated
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(
665 SIM_EF_CPHS_MBDN_FILEID,
666 mw_cphs_mbdn_changed, mw, NULL);
670 static void mw_mwis_write_cb(int ok, void *userdata)
673 ofono_error("Writing new EF-MWIS failed");
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)
680 DBusConnection *conn = ofono_dbus_get_connection();
681 unsigned char efmwis[255]; /* Max record size */
687 /* Handle only current identity (TODO: currently assumes first) */
691 if (mw->messages[type].indication == present &&
692 mw->messages[type].message_count == messages)
695 if (mw->messages[type].indication != present) {
696 dbus_bool_t indication;
697 const char *path = __ofono_atom_get_path(mw->atom);
699 indication = present;
700 mw->messages[type].indication = present;
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);
709 if (mw->messages[type].message_count != messages) {
710 const char *path = __ofono_atom_get_path(mw->atom);
712 mw->messages[type].message_count = messages;
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);
721 /* Writes MWI states and/or MBDN back to SIM */
722 if (mw->efmwis_length < 5) {
723 if (mw->ef_cphs_mwis_length >= 1)
726 ofono_error("Unable to update MWIS indicator");
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;
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)
739 if (ofono_sim_write(mw->sim_context, SIM_EFMWIS_FILEID,
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");
746 if (mw->ef_cphs_mwis_length == 0)
750 memset(efmwis, 0x55, 255);
752 efmwis[0] = mw->messages[0].indication ? 0xa : 0x5;
754 if (mw->ef_cphs_mwis_length > 1)
755 efmwis[1] = mw->messages[1].indication ? 0xa : 0x5 |
756 mw->messages[3].indication ? 0xa0 : 0x50;
758 if (ofono_sim_write(mw->sim_context, SIM_EF_CPHS_MWIS_FILEID,
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)");
765 static void handle_special_sms_iei(struct ofono_message_waiting *mw,
766 const guint8 *iei, gboolean *discard)
768 enum sms_mwi_type type;
772 /* Parse type & storage byte */
774 *discard = (iei[0] & (1 << 7)) ? FALSE : TRUE;
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;
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
787 type = SMS_MWI_TYPE_OTHER;
790 set = iei[1] > 0 ? TRUE : FALSE;
791 profile = ((iei[0] >> 5) & 3) + 1;
793 mw_set_indicator(mw, profile, type, set, iei[1]);
796 static void handle_enhanced_voicemail_iei(struct ofono_message_waiting *mw,
798 gboolean *discard, int length)
802 struct sms_address mailbox_address;
807 /* ENHANCED_VOICE_MAIL_PDU_TYPE */
809 /* 9.2.3.24.13.1 Enhanced Voice Mail Notification */
811 /* MULTIPLE_SUBSCRIBER_PROFILE */
812 profile = ((iei[0] >> 2) & 3) + 1;
816 *discard = (iei[0] & (1 << 4)) ? FALSE : TRUE;
818 /* VM_MAILBOX_ACCESS_ADDRESS */
820 if (!sms_decode_address_field(iei + 1, length - 1, &n,
821 FALSE, &mailbox_address))
824 /* TODO: VM_MESSAGE_PRIORITY_INDICATION */
826 /* Other parameters currently not supported */
831 set = iei[n + 1] > 0 ? TRUE : FALSE;
832 mw_set_indicator(mw, profile, SMS_MWI_TYPE_VOICE,
835 /* 9.2.3.24.13.2 Enhanced Voice Delete Confirmation */
837 /* MULTIPLE_SUBSCRIBER_PROFILE */
838 profile = ((iei[0] >> 2) & 3) + 1;
842 *discard = (iei[0] & (1 << 4)) ? FALSE : TRUE;
844 /* VM_MAILBOX_ACCESS_ADDRESS */
846 if (!sms_decode_address_field(iei + 1, length - 1, &n,
847 FALSE, &mailbox_address))
850 /* Other parameters currently not supported */
855 set = iei[n + 1] > 0 ? TRUE : FALSE;
856 mw_set_indicator(mw, profile, SMS_MWI_TYPE_VOICE,
860 if (mailbox_address.address[0] != '\0')
861 set_mbdn(mw, SMS_MWI_TYPE_VOICE,
862 sms_address_to_string(&mailbox_address), NULL);
865 void __ofono_message_waiting_mwi(struct ofono_message_waiting *mw,
866 struct sms *sms, gboolean *out_discard)
868 gboolean active, discard;
869 enum sms_mwi_type type;
870 int profile = 1, iei_found = 0;
873 *out_discard = FALSE;
876 * Check MWI types in the order from highest priority to lowest
877 * because they must override one another.
880 if (sms->deliver.udhi) {
882 struct sms_udh_iter iter;
885 if (!sms_udh_iter_init(sms, &iter))
888 while ((iei = sms_udh_iter_get_ie_type(&iter)) !=
891 case SMS_IEI_ENHANCED_VOICE_MAIL_INFORMATION:
892 sms_udh_iter_get_ie_data(&iter, evm_iei);
894 handle_enhanced_voicemail_iei(mw, evm_iei,
896 sms_udh_iter_get_ie_length(
903 sms_udh_iter_next(&iter);
907 if (sms->deliver.udhi) {
908 guint8 special_iei[4];
909 struct sms_udh_iter iter;
912 if (!sms_udh_iter_init(sms, &iter))
915 while ((iei = sms_udh_iter_get_ie_type(&iter)) !=
918 case SMS_IEI_SPECIAL_MESSAGE_INDICATION:
919 if (sms_udh_iter_get_ie_length(&iter) != 2)
921 sms_udh_iter_get_ie_data(&iter, special_iei);
923 handle_special_sms_iei(mw, special_iei,
926 *out_discard = *out_discard || discard;
933 sms_udh_iter_next(&iter);
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."
944 if (sms_mwi_dcs_decode(sms->deliver.dcs, NULL,
945 NULL, NULL, &discard)) {
947 *out_discard = *out_discard || discard;
954 if (sms_mwi_dcs_decode(sms->deliver.dcs, &type,
955 NULL, &active, out_discard)) {
956 mw_set_indicator(mw, profile, type, active, 0);
961 if (sms->deliver.pid == SMS_PID_TYPE_RETURN_CALL)
965 static void message_waiting_unregister(struct ofono_atom *atom)
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);
972 if (mw->sim_context) {
973 ofono_sim_context_free(mw->sim_context);
974 mw->sim_context = NULL;
979 g_dbus_unregister_interface(conn, path,
980 OFONO_MESSAGE_WAITING_INTERFACE);
981 ofono_modem_remove_interface(modem, OFONO_MESSAGE_WAITING_INTERFACE);
984 static void mw_mwis_changed(int id, void *userdata)
986 struct ofono_message_waiting *mw = userdata;
988 mw->efmwis_length = 0;
990 ofono_sim_read(mw->sim_context, SIM_EFMWIS_FILEID,
991 OFONO_SIM_FILE_STRUCTURE_FIXED,
992 mw_mwis_read_cb, mw);
995 static void mw_cphs_mwis_changed(int id, void *userdata)
997 struct ofono_message_waiting *mw = userdata;
999 mw->ef_cphs_mwis_length = 0;
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);
1006 static void mw_mbi_changed(int id, void *userdata)
1008 struct ofono_message_waiting *mw = userdata;
1010 mw->efmbdn_length = 0;
1011 mw->mbdn_not_provided = FALSE;
1013 mw->ef_cphs_mbdn_length = 0;
1014 mw->cphs_mbdn_not_provided = FALSE;
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);
1019 ofono_sim_read(mw->sim_context, SIM_EFMBI_FILEID,
1020 OFONO_SIM_FILE_STRUCTURE_FIXED,
1021 mw_mbi_read_cb, mw);
1024 void ofono_message_waiting_register(struct ofono_message_waiting *mw)
1026 DBusConnection *conn;
1028 struct ofono_modem *modem;
1033 conn = ofono_dbus_get_connection();
1034 modem = __ofono_atom_get_modem(mw->atom);
1035 path = __ofono_atom_get_path(mw->atom);
1037 if (!g_dbus_register_interface(conn, path,
1038 OFONO_MESSAGE_WAITING_INTERFACE,
1039 message_waiting_methods,
1040 message_waiting_signals,
1042 ofono_error("Could not create %s interface",
1043 OFONO_MESSAGE_WAITING_INTERFACE);
1047 ofono_modem_add_interface(modem, OFONO_MESSAGE_WAITING_INTERFACE);
1049 mw->sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
1051 /* Assume that if sim atom exists, it is ready */
1052 mw->sim_context = ofono_sim_context_create(mw->sim);
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);
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);
1068 * The operator could send us SMS mwi updates, but let's be
1069 * extra careful and track the file contents too.
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);
1077 ofono_sim_add_file_watch(mw->sim_context, SIM_EFMBI_FILEID,
1078 mw_mbi_changed, mw, NULL);
1081 __ofono_atom_register(mw->atom, message_waiting_unregister);
1084 static void mw_remove(struct ofono_atom *atom)
1086 struct ofono_message_waiting *mw = __ofono_atom_get_data(atom);
1088 DBG("atom: %p", atom);
1096 struct ofono_message_waiting *ofono_message_waiting_create(struct ofono_modem *modem)
1098 struct ofono_message_waiting *mw;
1100 mw = g_try_new0(struct ofono_message_waiting, 1);
1105 mw->atom = __ofono_modem_add_atom(modem,
1106 OFONO_ATOM_TYPE_MESSAGE_WAITING,
1112 void ofono_message_waiting_remove(struct ofono_message_waiting *mw)
1114 __ofono_atom_free(mw->atom);