summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrzej Zaborowski <andrew.zaborowski@intel.com>2009-08-03 14:50:14 +0200
committerDenis Kenzior <denkenz@gmail.com>2009-08-04 15:08:11 -0500
commit203ed17cecba2ab21317b8ba35b50907d0684675 (patch)
tree1cd305186f91e60c4bf655684a842258dc681972 /src
parentba8ef5c3e4e453f66fc657e51e04cdf39fd1fc1c (diff)
downloadofono-203ed17cecba2ab21317b8ba35b50907d0684675.tar.bz2
Add a MessageWaiting interface to track message waiting indications.
The state of the indications is kept in memory and written back to the SIM after any changes.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/message-waiting.c761
-rw-r--r--src/message-waiting.h30
-rw-r--r--src/ofono.h4
-rw-r--r--src/simutil.h3
-rw-r--r--src/sms.c30
-rw-r--r--src/smsutil.h1
7 files changed, 822 insertions, 10 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 2e3e607d..4644c693 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,7 +13,8 @@ ofonod_SOURCES = main.c ofono.h log.c plugin.c \
network.c voicecall.c ussd.h ussd.c sms.c \
call-settings.c call-forwarding.c call-meter.c \
smsutil.h smsutil.c cssn.h cssn.c call-barring.c sim.h sim.c \
- phonebook.c history.c simutil.h simutil.c
+ phonebook.c history.c simutil.h simutil.c \
+ message-waiting.c message-waiting.h
ofonod_LDADD = $(top_builddir)/plugins/libbuiltin.la \
$(top_builddir)/drivers/libbuiltin.la \
diff --git a/src/message-waiting.c b/src/message-waiting.c
new file mode 100644
index 00000000..fcb4519d
--- /dev/null
+++ b/src/message-waiting.c
@@ -0,0 +1,761 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include <dbus/dbus.h>
+#include <glib.h>
+#include <gdbus.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "ofono.h"
+
+#include "driver.h"
+#include "common.h"
+#include "util.h"
+#include "sim.h"
+#include "simutil.h"
+#include "smsutil.h"
+#include "message-waiting.h"
+
+#define MESSAGE_WAITING_INTERFACE "org.ofono.MessageWaiting"
+
+struct mailbox_state {
+ gboolean indication;
+ int message_count;
+};
+
+struct message_waiting_data {
+ struct mailbox_state messages[5];
+ int efmwis_length;
+ int efmbdn_length;
+ int efmbdn_record_id[5];
+
+ struct ofono_phone_number mailbox_number[5];
+
+ int pending;
+ struct mailbox_state messages_new[5];
+ struct ofono_phone_number mailbox_number_new[5];
+};
+
+static struct message_waiting_data *message_waiting_create()
+{
+ return g_try_new0(struct message_waiting_data, 1);
+}
+
+static void message_waiting_destroy(gpointer userdata)
+{
+ struct ofono_modem *modem = userdata;
+ struct message_waiting_data *data = modem->message_waiting;
+
+ g_free(data);
+
+ modem->message_waiting = NULL;
+}
+
+static const char *mw_message_waiting_property_name[5] = {
+ "VoicemailWaiting",
+#if 0
+ "FaxWaiting",
+ "EmailWaiting",
+ "OtherWaiting",
+ "VideomailWaiting",
+#endif
+};
+
+static const char *mw_message_count_property_name[5] = {
+ "VoicemailMessageCount",
+#if 0
+ "FaxMessageCount",
+ "EmailMessageCount",
+ "OtherMessageCount",
+ "VideomailMessageCount",
+#endif
+};
+
+static const char *mw_mailbox_property_name[5] = {
+ "VoicemailMailboxNumber",
+#if 0
+ "FaxMailboxNumber",
+ "EmailMailboxNumber",
+ "OtherMailboxNumber",
+ "VideomailMailboxNumber",
+#endif
+};
+
+static DBusMessage *mw_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct message_waiting_data *mw = modem->message_waiting;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ int i;
+ dbus_bool_t indication;
+ unsigned char count;
+ const char *number;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict);
+
+ for (i = 0; i < 5; i++) {
+ if (mw_message_waiting_property_name[i]) {
+ indication = mw->messages[i].indication;
+
+ ofono_dbus_dict_append(&dict,
+ mw_message_waiting_property_name[i],
+ DBUS_TYPE_BOOLEAN, &indication);
+ }
+
+ if (mw_message_count_property_name[i]) {
+ count = mw->messages[i].message_count;
+
+ ofono_dbus_dict_append(&dict,
+ mw_message_count_property_name[i],
+ DBUS_TYPE_BYTE, &count);
+ }
+
+ if (mw_mailbox_property_name[i]) {
+ number = phone_number_to_string(&mw->mailbox_number[i]);
+
+ ofono_dbus_dict_append(&dict,
+ mw_mailbox_property_name[i],
+ DBUS_TYPE_STRING, &number);
+ }
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static gboolean mw_update(gpointer user);
+
+static DBusMessage *mw_set_property(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+ struct message_waiting_data *mw = modem->message_waiting;
+ DBusMessageIter iter;
+ DBusMessageIter var;
+ const char *name, *value;
+ int i;
+ struct ofono_phone_number new_number;
+
+ if (mw->efmbdn_length == 0)
+ return __ofono_error_busy(msg);
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return __ofono_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+
+ for (i = 0; i < 5; i++)
+ if (mw_mailbox_property_name[i] &&
+ !strcmp(name, mw_mailbox_property_name[i]))
+ break;
+ if (i == 5)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_next(&iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&iter, &var);
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_format(msg);
+
+ dbus_message_iter_get_basic(&var, &value);
+ if (!valid_phone_number_format(value))
+ return __ofono_error_invalid_format(msg);
+ string_to_phone_number(value, &new_number);
+
+ if (strcmp(mw->mailbox_number_new[i].number, new_number.number) ||
+ mw->mailbox_number_new[i].type != new_number.type) {
+ memcpy(&mw->mailbox_number_new[i], &new_number,
+ sizeof(struct ofono_phone_number));
+
+ if (!mw->pending)
+ mw->pending = g_timeout_add(0, mw_update, modem);
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable message_waiting_methods[] = {
+ { "GetProperties", "", "a{sv}", mw_get_properties },
+ { "SetProperty", "sv", "", mw_set_property, },
+ { }
+};
+
+static GDBusSignalTable message_waiting_signals[] = {
+ { "PropertyChanged", "sv" },
+ { }
+};
+
+static void mw_mwis_read_cb(struct ofono_modem *modem, int ok,
+ enum ofono_sim_file_structure structure, int total_length,
+ int record, const unsigned char *data, int record_length,
+ void *userdata)
+{
+ int i, status;
+ struct mailbox_state info;
+ dbus_bool_t indication;
+ unsigned char count;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct message_waiting_data *mw = modem->message_waiting;
+
+ if (!ok ||
+ structure != OFONO_SIM_FILE_STRUCTURE_FIXED ||
+ record_length < 5) {
+ ofono_error("Unable to read waiting messages numbers "
+ "from SIM");
+
+ mw->efmwis_length = -1;
+
+ return;
+ }
+
+ /* Handle only current identity (TODO: currently assumes first) */
+ if (record != 1)
+ return;
+
+ status = data[0];
+ data++;
+
+ for (i = 0; i < 5 && i < record_length - 1; i++) {
+ info.indication = (status >> i) & 1;
+ info.message_count = info.indication ? data[0] : 0;
+
+ if (mw->messages[i].indication != info.indication ||
+ mw->messages[i].message_count !=
+ info.message_count) {
+ memcpy(&mw->messages[i], &info, sizeof(info));
+ memcpy(&mw->messages_new[i], &info, sizeof(info));
+
+ if (!mw_message_waiting_property_name[i])
+ continue;
+
+ indication = info.indication;
+ count = info.message_count;
+
+ ofono_dbus_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_message_waiting_property_name[i],
+ DBUS_TYPE_BOOLEAN, &indication);
+ ofono_dbus_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_message_count_property_name[i],
+ DBUS_TYPE_BYTE, &count);
+ }
+ }
+
+ mw->efmwis_length = record_length;
+}
+
+static void mw_mbdn_read_cb(struct ofono_modem *modem, int ok,
+ enum ofono_sim_file_structure structure, int total_length,
+ int record, const unsigned char *data, int record_length,
+ void *userdata)
+{
+ int i;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct message_waiting_data *mw = modem->message_waiting;
+ const char *value;
+
+ if (!ok ||
+ structure != OFONO_SIM_FILE_STRUCTURE_FIXED ||
+ record_length < 14 || total_length < record_length) {
+ ofono_error("Unable to read mailbox dialling numbers "
+ "from SIM");
+
+ mw->efmbdn_length = -1;
+
+ return;
+ }
+
+ for (i = 0; i < 5; i++)
+ if (record == mw->efmbdn_record_id[i])
+ break;
+ if (i == 5)
+ return;
+
+ if (sim_adn_parse(data, record_length, &mw->mailbox_number[i]) ==
+ FALSE) {
+ mw->mailbox_number[i].number[0] = '\0';
+ mw->mailbox_number_new[i].number[0] = '\0';
+ } else {
+ memcpy(&mw->mailbox_number_new[i], &mw->mailbox_number[i],
+ sizeof(struct ofono_phone_number));
+ }
+
+ if (mw_mailbox_property_name[i]) {
+ value = phone_number_to_string(&mw->mailbox_number[i]);
+
+ ofono_dbus_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_mailbox_property_name[i],
+ DBUS_TYPE_STRING, &value);
+ }
+
+ mw->efmbdn_length = record_length;
+}
+
+static void mw_mbi_read_cb(struct ofono_modem *modem, int ok,
+ enum ofono_sim_file_structure structure, int total_length,
+ int record, const unsigned char *data, int record_length,
+ void *userdata)
+{
+ int i, err;
+ struct message_waiting_data *mw = modem->message_waiting;
+
+ if (!ok ||
+ structure != OFONO_SIM_FILE_STRUCTURE_FIXED ||
+ record_length < 4) {
+ ofono_error("Unable to read mailbox identifies "
+ "from SIM");
+
+ mw->efmbdn_length = -1;
+
+ return;
+ }
+
+ /* Handle only current identity (TODO: currently assumes first) */
+ if (record != 1)
+ return;
+
+ for (i = 0; i < 5 && i < record_length; i++)
+ mw->efmbdn_record_id[i] = data[i];
+
+ err = ofono_sim_read(modem, SIM_EFMBDN_FILEID, mw_mbdn_read_cb, NULL);
+ if (err != 0) {
+ ofono_error("Unable to read EF-MBDN from SIM");
+ }
+}
+
+static void mw_mbdn_write_cb(struct ofono_modem *modem, int ok, void *userdata)
+{
+ if (!ok)
+ ofono_error("Writing new EF-MBDN failed");
+}
+
+/* Loads MWI states and MBDN from SIM */
+static gboolean mw_mwis_load(struct ofono_modem *modem)
+{
+ int err;
+
+ err = ofono_sim_read(modem, SIM_EFMWIS_FILEID, mw_mwis_read_cb, NULL);
+ if (err != 0)
+ return FALSE;
+
+ err = ofono_sim_read(modem, SIM_EFMBI_FILEID, mw_mbi_read_cb, NULL);
+ if (err != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Writes MWI states and/or MBDN back to SIM */
+static gboolean mw_update(gpointer user)
+{
+ struct ofono_modem *modem = user;
+ struct message_waiting_data *mw = modem->message_waiting;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t indication;
+ unsigned char count;
+ const char *number;
+ int i;
+ unsigned char *file;
+
+ mw->pending = 0;
+
+ for (i = 0; i < 5; i++) {
+ if (mw->messages_new[i].message_count !=
+ mw->messages[i].message_count) {
+ mw->messages[i].message_count =
+ mw->messages_new[i].message_count;
+
+ if (!mw_message_count_property_name[i])
+ continue;
+
+ count = mw->messages[i].message_count;
+
+ ofono_dbus_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_message_count_property_name[i],
+ DBUS_TYPE_BYTE, &count);
+ }
+
+ if (mw->messages_new[i].indication !=
+ mw->messages[i].indication) {
+ mw->messages[i].indication =
+ mw->messages_new[i].indication;
+
+ if (!mw_message_waiting_property_name[i])
+ continue;
+
+ indication = mw->messages[i].indication;
+
+ ofono_dbus_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_message_waiting_property_name[i],
+ DBUS_TYPE_BOOLEAN, &indication);
+ }
+ }
+ if (mw->efmwis_length < 1)
+ goto mbdn;
+
+ file = g_malloc0(mw->efmwis_length);
+
+ /* Fill in numbers of messages in bytes 1 to X of EF-MWIS */
+ for (i = 0; i < 5 && i < mw->efmwis_length - 1; i++)
+ file[i + 1] = mw->messages[i].message_count;
+
+ /* Fill in indicator state bits in byte 0 */
+ for (i = 0; i < 5 && i < mw->efmwis_length - 1; i++)
+ if (mw->messages[i].indication)
+ file[0] |= 1 << i;
+
+ if (ofono_sim_write(modem, SIM_EFMWIS_FILEID, mw_mbdn_write_cb,
+ OFONO_SIM_FILE_STRUCTURE_FIXED, 1,
+ file, mw->efmwis_length, NULL) != 0) {
+ ofono_error("Queuing a EF-MWI write to SIM failed");
+ }
+
+ g_free(file);
+
+mbdn:
+ for (i = 0; i < 5; i++)
+ if (strcmp(mw->mailbox_number_new[i].number,
+ mw->mailbox_number[i].number) ||
+ mw->mailbox_number_new[i].type !=
+ mw->mailbox_number[i].type) {
+ memcpy(&mw->mailbox_number[i],
+ &mw->mailbox_number_new[i],
+ sizeof(struct ofono_phone_number));
+
+ if (!mw_mailbox_property_name[i])
+ continue;
+
+ number = phone_number_to_string(
+ &mw->mailbox_number[i]);
+
+ ofono_dbus_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_mailbox_property_name[i],
+ DBUS_TYPE_STRING, &number);
+ }
+ if (mw->efmbdn_length < 1)
+ return FALSE;
+
+ return FALSE;
+}
+
+void ofono_message_waiting_present_notify(struct ofono_modem *modem,
+ enum sms_mwi_type type, gboolean present, int profile)
+{
+ struct message_waiting_data *mw = modem->message_waiting;
+
+ if (mw == NULL)
+ return;
+
+ /* Handle only current identity (TODO: currently assumes first) */
+ if (profile != 1)
+ return;
+
+ present = !!present;
+ if (mw->messages_new[type].indication != present) {
+ mw->messages_new[type].indication = present;
+ if (!present)
+ mw->messages_new[type].message_count = 0;
+
+ if (!mw->pending)
+ mw->pending = g_timeout_add(0, mw_update, modem);
+ }
+}
+
+void ofono_message_waiting_count_notify(struct ofono_modem *modem,
+ enum sms_mwi_type type, int count, int profile)
+{
+ struct message_waiting_data *mw = modem->message_waiting;
+
+ if (mw == NULL)
+ return;
+
+ /* Handle only current identity (TODO: currently assumes first) */
+ if (profile != 1)
+ return;
+
+ if (mw->messages_new[type].message_count != count ||
+ mw->messages_new[type].indication != (count > 0)) {
+ mw->messages_new[type].message_count = count;
+ mw->messages_new[type].indication = (count > 0);
+
+ if (!mw->pending)
+ mw->pending = g_timeout_add(0, mw_update, modem);
+ }
+}
+
+static void initialize_message_waiting(struct ofono_modem *modem)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+
+ if (!mw_mwis_load(modem)) {
+ ofono_error("Could not register MessageWaiting interface");
+ message_waiting_destroy(modem);
+
+ return;
+ }
+
+ if (!g_dbus_register_interface(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ message_waiting_methods,
+ message_waiting_signals,
+ NULL, modem,
+ message_waiting_destroy)) {
+ ofono_error("Could not register MessageWaiting interface");
+ message_waiting_destroy(modem);
+
+ return;
+ }
+
+ ofono_debug("MessageWaiting interface for modem: %s created",
+ modem->path);
+
+ ofono_modem_add_interface(modem, MESSAGE_WAITING_INTERFACE);
+}
+
+int ofono_message_waiting_register(struct ofono_modem *modem)
+{
+ if (modem == NULL)
+ return -1;
+
+ modem->message_waiting = message_waiting_create();
+
+ ofono_sim_ready_notify_register(modem, initialize_message_waiting);
+ if (ofono_sim_get_ready(modem))
+ initialize_message_waiting(modem);
+
+ return 0;
+}
+
+void ofono_message_waiting_unregister(struct ofono_modem *modem)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+
+ g_dbus_unregister_interface(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE);
+ ofono_modem_remove_interface(modem, MESSAGE_WAITING_INTERFACE);
+}
+
+static void handle_special_sms_iei(struct ofono_modem *modem,
+ const guint8 *iei, gboolean *discard)
+{
+ enum sms_mwi_type type;
+ int profile;
+
+ /* Parse type & storage byte */
+ if (discard)
+ *discard = (iei[0] & (1 << 7)) ? FALSE : TRUE;
+
+ type = iei[0] & 0x1f;
+ if (type > SMS_MWI_TYPE_OTHER) {
+ if (type == (SMS_MWI_TYPE_OTHER | 4))
+ type = SMS_MWI_TYPE_VIDEO;
+ else
+ /* 23.040 9.2.3.24.2: "Terminals should be capable of
+ * receiving any values in octet 1, even including
+ * those marked as Reserved." Treat Reserved as
+ * "Other". */
+ type = SMS_MWI_TYPE_OTHER;
+ }
+
+ profile = ((iei[0] >> 5) & 3) + 1;
+
+ ofono_message_waiting_count_notify(modem, iei[1], type, profile);
+}
+
+static void handle_enhanced_voicemail_iei(struct ofono_modem *modem,
+ const guint8 *iei, gboolean *discard, int length)
+{
+ int profile, n;
+
+ if (length < 3)
+ return;
+
+ /* ENHANCED_VOICE_MAIL_PDU_TYPE */
+ if (!(iei[0] & 1)) {
+ /* 9.2.3.24.13.1 Enhanced Voice Mail Notification */
+
+ /* MULTIPLE_SUBSCRIBER_PROFILE */
+ profile = (iei[0] >> 2) & 3;
+
+ /* SM_STORAGE */
+ if (discard)
+ *discard = (iei[0] & (1 << 4)) ? FALSE : TRUE;
+
+ /* TODO: VM_MAILBOX_ACCESS_ADDRESS */
+ n = 2 + (iei[1] + 1) / 2;
+ if (length < n + 11)
+ return;
+
+ /* TODO: VM_MESSAGE_PRIORITY_INDICATION */
+
+ /* Other parameters currently not supported */
+
+ ofono_message_waiting_count_notify(modem, iei[2 + n],
+ SMS_MWI_TYPE_VOICE, profile);
+ } else {
+ /* 9.2.3.24.13.2 Enhanced Voice Delete Confirmation */
+
+ /* MULTIPLE_SUBSCRIBER_PROFILE */
+ profile = (iei[0] >> 2) & 3;
+
+ /* SM_STORAGE */
+ if (discard)
+ *discard = (iei[0] & (1 << 4)) ? FALSE : TRUE;
+
+ /* TODO: VM_MAILBOX_ACCESS_ADDRESS */
+ n = 2 + (iei[1] + 1) / 2;
+ if (length < n + 11)
+ return;
+
+ /* Other parameters currently not supported */
+
+ ofono_message_waiting_count_notify(modem, iei[2 + n],
+ SMS_MWI_TYPE_VOICE, profile);
+ }
+}
+
+void ofono_handle_sms_mwi(struct ofono_modem *modem,
+ struct sms *sms, gboolean *out_discard)
+{
+ gboolean active, discard;
+ enum sms_mwi_type type;
+ int profile = 1, iei_found = 0;
+
+ if (out_discard)
+ *out_discard = FALSE;
+
+ /* Check MWI types in the order from highest priority to lowest
+ * because they must override one another.
+ */
+
+ if (sms->deliver.udhi) {
+ guint8 *evm_iei;
+ struct sms_udh_iter iter;
+ enum sms_iei iei;
+
+ if (!sms_udh_iter_init(sms, &iter))
+ return;
+
+ while ((iei = sms_udh_iter_get_ie_type(&iter)) !=
+ SMS_IEI_INVALID) {
+ switch (iei) {
+ case SMS_IEI_ENHANCED_VOICE_MAIL_INFORMATION:
+ evm_iei = g_malloc0(
+ sms_udh_iter_get_ie_length(
+ &iter));
+ sms_udh_iter_get_ie_data(&iter, evm_iei);
+
+ handle_enhanced_voicemail_iei(modem, evm_iei,
+ out_discard,
+ sms_udh_iter_get_ie_length(
+ &iter));
+
+ g_free(evm_iei);
+ return;
+ }
+
+ sms_udh_iter_next(&iter);
+ }
+ }
+
+ if (sms->deliver.udhi) {
+ guint8 special_iei[4];
+ struct sms_udh_iter iter;
+ enum sms_iei iei;
+
+ if (!sms_udh_iter_init(sms, &iter))
+ return;
+
+ while ((iei = sms_udh_iter_get_ie_type(&iter)) !=
+ SMS_IEI_INVALID) {
+ switch (iei) {
+ case SMS_IEI_SPECIAL_MESSAGE_INDICATION:
+ if (sms_udh_iter_get_ie_length(&iter) != 2)
+ break;
+ sms_udh_iter_get_ie_data(&iter, special_iei);
+
+ handle_special_sms_iei(modem, special_iei,
+ &discard);
+ if (out_discard)
+ *out_discard = *out_discard || discard;
+ iei_found = 1;
+ }
+
+ sms_udh_iter_next(&iter);
+ }
+
+ if (iei_found) {
+ /* 23.040 9.2.3.24.2 says "In the event of a
+ * conflict between this setting and the setting
+ * of the Data Coding Scheme (see 3GPP TS 23.038 [9])
+ * then the message shall be stored if either the DCS
+ * indicates this, or Octet 1 above indicates this."
+ */
+ if (sms_mwi_dcs_decode(sms->deliver.dcs, NULL,
+ NULL, NULL, &discard)) {
+ if (out_discard)
+ *out_discard = *out_discard || discard;
+ }
+
+ return;
+ }
+ }
+
+ if (sms_mwi_dcs_decode(sms->deliver.dcs, &type,
+ NULL, &active, out_discard)) {
+ ofono_message_waiting_present_notify(modem,
+ type, active, profile);
+
+ return;
+ }
+
+ if (sms->deliver.pid == SMS_PID_TYPE_RETURN_CALL)
+ return;
+}
diff --git a/src/message-waiting.h b/src/message-waiting.h
new file mode 100644
index 00000000..c0e60bfb
--- /dev/null
+++ b/src/message-waiting.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void ofono_message_waiting_present_notify(struct ofono_modem *modem,
+ enum sms_mwi_type type,
+ gboolean present, int profile);
+void ofono_message_waiting_count_notify(struct ofono_modem *modem,
+ enum sms_mwi_type type, int count,
+ int profile);
+
+void ofono_handle_sms_mwi(struct ofono_modem *modem,
+ struct sms *sms, gboolean *out_discard);
diff --git a/src/ofono.h b/src/ofono.h
index 3cb2d753..4e344306 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -79,6 +79,7 @@ struct ofono_modem {
struct sim_manager_data *sim_manager;
struct sms_manager_data *sms_manager;
struct phonebook_data *phonebook;
+ struct message_waiting_data *message_waiting;
GSList *history_contexts;
};
@@ -99,3 +100,6 @@ void __ofono_history_call_ended(struct ofono_modem *modem,
void __ofono_history_call_missed(struct ofono_modem *modem,
const struct ofono_call *call, time_t when);
+
+int ofono_message_waiting_register(struct ofono_modem *modem);
+void ofono_message_waiting_unregister(struct ofono_modem *modem);
diff --git a/src/simutil.h b/src/simutil.h
index 6572e72f..c2b1e20c 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -24,6 +24,9 @@ enum sim_fileid {
SIM_EFSPN_FILEID = 0x6f46,
SIM_EFPNN_FILEID = 0x6fc5,
SIM_EFOPL_FILEID = 0x6fc6,
+ SIM_EFMBDN_FILEID = 0x6fc7,
+ SIM_EFMBI_FILEID = 0x6fc9,
+ SIM_EFMWIS_FILEID = 0x6fca,
SIM_EFSPDI_FILEID = 0x6fcd,
};
diff --git a/src/sms.c b/src/sms.c
index 3a471e31..84b98de9 100644
--- a/src/sms.c
+++ b/src/sms.c
@@ -36,6 +36,7 @@
#include "util.h"
#include "sim.h"
#include "smsutil.h"
+#include "message-waiting.h"
#define uninitialized_var(x) x = x
@@ -655,11 +656,6 @@ static void handle_deliver(struct ofono_modem *modem,
g_slist_free(l);
}
-static void handle_mwi(struct ofono_modem *modem, struct sms *mwi)
-{
- ofono_error("MWI information not yet handled");
-}
-
void ofono_sms_deliver_notify(struct ofono_modem *modem, unsigned char *pdu,
int len, int tpdu_len)
{
@@ -685,14 +681,18 @@ void ofono_sms_deliver_notify(struct ofono_modem *modem, unsigned char *pdu,
/* This is an older style MWI notification, process MWI
* headers and handle it like any other message */
if (sms.deliver.pid == SMS_PID_TYPE_RETURN_CALL) {
- handle_mwi(modem, &sms);
+ ofono_handle_sms_mwi(modem, &sms, &discard);
+
+ if (discard)
+ return;
+
goto out;
}
/* The DCS indicates this is an MWI notification, process it
* and then handle the User-Data as any other message */
- if (sms_mwi_dcs_decode(sms.deliver.dcs, NULL, NULL, NULL, &discard)) {
- handle_mwi(modem, &sms);
+ if (sms_mwi_dcs_decode(sms.deliver.dcs, NULL, NULL, NULL, NULL)) {
+ ofono_handle_sms_mwi(modem, &sms, &discard);
if (discard)
return;
@@ -757,7 +757,14 @@ void ofono_sms_deliver_notify(struct ofono_modem *modem, unsigned char *pdu,
switch (iei) {
case SMS_IEI_SPECIAL_MESSAGE_INDICATION:
case SMS_IEI_ENHANCED_VOICE_MAIL_INFORMATION:
- handle_mwi(modem, &sms);
+ /* TODO: ignore if not in the very first
+ * segment of a concatenated SM so as not
+ * to repeat the indication. */
+ ofono_handle_sms_mwi(modem, &sms, &discard);
+
+ if (discard)
+ return;
+
goto out;
case SMS_IEI_WCMP:
ofono_error("No support for WCMP, ignoring");
@@ -789,6 +796,9 @@ int ofono_sms_manager_register(struct ofono_modem *modem,
if (ops == NULL)
return -1;
+ if (ofono_message_waiting_register(modem))
+ return -1;
+
modem->sms_manager = sms_manager_create();
if (!modem->sms_manager)
@@ -824,4 +834,6 @@ void ofono_sms_manager_unregister(struct ofono_modem *modem)
SMS_MANAGER_INTERFACE);
ofono_modem_remove_interface(modem, SMS_MANAGER_INTERFACE);
+
+ ofono_message_waiting_unregister(modem);
}
diff --git a/src/smsutil.h b/src/smsutil.h
index 89da973f..d362aa98 100644
--- a/src/smsutil.h
+++ b/src/smsutil.h
@@ -158,6 +158,7 @@ enum sms_mwi_type {
SMS_MWI_TYPE_FAX = 1,
SMS_MWI_TYPE_EMAIL = 2,
SMS_MWI_TYPE_OTHER = 3,
+ SMS_MWI_TYPE_VIDEO = 4,
};
enum sms_pid_type {