[PATCH 4/4] Add a MessageWaiting interface to track message waiting indications.
by Andrzej Zaborowski
Comments are welcome about how the interface should look. The state of the
indications is kept in memory and written back to the SIM after any
changes.
Patch is untested because write ofono_sim_write is unimplemented, I'll add
it as a separate patch. Should it take a callback parameter?
---
src/Makefile.am | 3 +-
src/driver.h | 3 +
src/message-waiting.c | 512 +++++++++++++++++++++++++++++++++++++++++++++++++
src/message-waiting.h | 33 ++++
src/modem.h | 1 +
src/simutil.h | 3 +
src/sms.c | 216 ++++++++++++++++++++-
src/smsutil.h | 1 +
8 files changed, 765 insertions(+), 7 deletions(-)
create mode 100644 src/message-waiting.c
create mode 100644 src/message-waiting.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 2fb3f06..144b872 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/driver.h b/src/driver.h
index 928c20a..51e5587 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -439,3 +439,6 @@ void ofono_phonebook_entry(struct ofono_modem *modem, int index,
const char *adnumber, int adtype,
const char *secondtext, const char *email,
const char *sip_uri, const char *tel_uri);
+
+int ofono_message_waiting_register(struct ofono_modem *modem);
+void ofono_message_waiting_unregister(struct ofono_modem *modem);
diff --git a/src/message-waiting.c b/src/message-waiting.c
new file mode 100644
index 0000000..564961a
--- /dev/null
+++ b/src/message-waiting.c
@@ -0,0 +1,512 @@
+/*
+ *
+ * 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 "dbus-gsm.h"
+#include "modem.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 message_waiting_data {
+ int pending;
+
+ int messages[5];
+ int efmwis_length;
+ int efmbdn_length;
+
+ struct ofono_phone_number mailbox_number[5];
+
+ char *last_message;
+};
+
+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;
+
+ if (data->last_message)
+ g_free(data->last_message);
+
+ g_free(data);
+
+ modem->network_registration = NULL;
+}
+
+static const char *mw_messages_property_name[5] = {
+ "VoicemailMessages",
+#if 0
+ "FaxMessages",
+ "EmailMessages",
+ "OtherMessages",
+ "VideomailMessages",
+#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;
+ unsigned char value;
+ 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,
+ PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ for (i = 0; i < 5; i++)
+ if (mw_messages_property_name[i]) {
+ value = mw->messages[i];
+
+ dbus_gsm_dict_append(&dict,
+ mw_messages_property_name[i],
+ DBUS_TYPE_BYTE, &value);
+ }
+
+ for (i = 0; i < 5; i++)
+ if (mw_mailbox_property_name[i]) {
+ number = phone_number_to_string(&mw->mailbox_number[i]);
+
+ dbus_gsm_dict_append(&dict,
+ mw_mailbox_property_name[i],
+ DBUS_TYPE_STRING, &number);
+ }
+
+ dbus_gsm_dict_append(&dict, "LastNotificationText",
+ DBUS_TYPE_STRING, &mw->last_message);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static gboolean mw_mwis_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;
+ int i;
+ unsigned char value;
+
+ if (mw->efmwis_length == 0)
+ return dbus_gsm_busy(msg);
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return dbus_gsm_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return dbus_gsm_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+
+ for (i = 0; i < 5; i++)
+ if (mw_messages_property_name[i] &&
+ !strcmp(name, mw_messages_property_name[i]))
+ break;
+ if (i == 5)
+ return dbus_gsm_invalid_args(msg);
+
+ dbus_message_iter_next(&iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return dbus_gsm_invalid_args(msg);
+
+ dbus_message_iter_recurse(&iter, &var);
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
+ return dbus_gsm_invalid_format(msg);
+
+ dbus_message_iter_get_basic(&var, &value);
+
+ if (mw->messages[i] != value) {
+ mw->messages[i] = value;
+
+ if (!mw->pending)
+ mw->pending = g_timeout_add(0, mw_mwis_update, modem);
+
+ dbus_gsm_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_messages_property_name[i],
+ DBUS_TYPE_BYTE, &value);
+ }
+
+ 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, messages[5];
+ unsigned char value;
+ DBusConnection *conn = dbus_gsm_connection();
+ struct message_waiting_data *mw = modem->message_waiting;
+
+ /* Handle only current identity (TODO: currently assumes first) */
+ if (record != 1)
+ return;
+
+ if (!ok ||
+ structure != OFONO_SIM_FILE_STRUCTURE_FIXED ||
+ record_length < 5) {
+ ofono_error("Unable to read waiting messages numbers "
+ "from SIM");
+ return;
+ }
+
+ status = data[0];
+ data++;
+
+ for (i = 0; i < 5 && i < record_length - 1; i++) {
+ messages[i] = ((status >> i) & 1) ? data[i] : 0;
+
+ if (mw->messages[i] != messages[i]) {
+ mw->messages[i] = messages[i];
+ value = messages[i];
+
+ if (!mw_messages_property_name[i])
+ continue;
+
+ dbus_gsm_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_messages_property_name[i],
+ DBUS_TYPE_BYTE, &value);
+ }
+ }
+
+ 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, *ids = userdata;
+ DBusConnection *conn = dbus_gsm_connection();
+ struct message_waiting_data *mw = modem->message_waiting;
+
+ 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");
+ g_free(ids);
+ return;
+ }
+
+ for (i = 0; i < 5; i++)
+ if (record == ids[i])
+ break;
+ if (i == 5)
+ goto final;
+
+ if (sim_adn_parse(data, record_length, &mw->mailbox_number[i]) ==
+ FALSE)
+ mw->mailbox_number[i].number[0] = '\0';
+
+ mw->efmbdn_length = record_length;
+
+final:
+ /* Is this the last MBDN record? */
+ if (record == total_length / record_length)
+ g_free(ids);
+}
+
+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, *ids = userdata;
+ DBusConnection *conn = dbus_gsm_connection();
+ struct message_waiting_data *mw = modem->message_waiting;
+
+ /* Handle only current identity (TODO: currently assumes first) */
+ if (record != 1)
+ return;
+
+ if (!ok ||
+ structure != OFONO_SIM_FILE_STRUCTURE_FIXED ||
+ record_length < 4) {
+ ofono_error("Unable to read mailbox identifies "
+ "from SIM");
+
+ g_free(ids);
+ return;
+ }
+
+ for (i = 0; i < 5 && i < record_length; i++)
+ ids[i] = data[i];
+
+ err = ofono_sim_read(modem, SIM_EFMBDN_FILEID, mw_mbdn_read_cb, ids);
+ if (err != 0) {
+ ofono_error("Unable to read EF-MBDN from SIM");
+
+ g_free(ids);
+ }
+}
+
+/* Loads MWI states from SIM */
+static gboolean mw_mwis_load(struct ofono_modem *modem)
+{
+ int err;
+ int *ids;
+
+ err = ofono_sim_read(modem, SIM_EFMWIS_FILEID, mw_mwis_read_cb, NULL);
+ if (err != 0)
+ return FALSE;
+
+ /* Alloc space for mailbox identifiers */
+ ids = g_malloc0(5);
+
+ err = ofono_sim_read(modem, SIM_EFMBI_FILEID, mw_mbi_read_cb, ids);
+ if (err != 0) {
+ g_free(ids);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Writes MWI states back to SIM */
+static gboolean mw_mwis_update(gpointer user)
+{
+ struct ofono_modem *modem = user;
+ struct message_waiting_data *mw = modem->message_waiting;
+ unsigned char *file;
+ int i;
+
+ mw->pending = 0;
+
+ if (mw->efmwis_length == 0)
+ return FALSE;
+
+ 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];
+
+ /* Fill in indicator state bits in byte 0 */
+ for (i = 0; i < 5 && i < mw->efmwis_length - 1; i++)
+ if (file[i + 1] > 0)
+ file[0] |= 1 << i;
+
+ if (ofono_sim_write(modem, SIM_EFMWIS_FILEID,
+ OFONO_SIM_FILE_STRUCTURE_FIXED, 1,
+ file, mw->efmwis_length) != 0) {
+ ofono_error("Writing MWI states to SIM failed");
+ }
+
+ g_free(file);
+
+ return FALSE;
+}
+
+void ofono_message_waiting_notify(struct ofono_modem *modem, int information,
+ enum sms_mwi_type type, int profile)
+{
+ struct message_waiting_data *mw = modem->message_waiting;
+ DBusConnection *conn = dbus_gsm_connection();
+ int invalidate = 0;
+ unsigned char value;
+
+ if (mw == NULL)
+ return;
+
+ /* Handle only current identity (TODO: currently assumes first) */
+ if (profile != 1)
+ return;
+
+ /* Ignore the unspecified type of notification. It probably means
+ * that the (voicemail) indication should become active but there's
+ * no way to know when to deactivate it. It's used for the obsolete
+ * Return Call type of indication in SMS PDUs which also carry text
+ * and we provide this text instead. */
+ if (information == MWI_UNSPECIFIED)
+ return;
+
+ if (information == MWI_MESSAGES_WAITING) {
+ if (mw->messages[type] == 0) {
+ mw->messages[type] = 1;
+ invalidate = 1;
+ }
+ } else if (information == MWI_NO_MESSAGES_WAITING) {
+ if (mw->messages[type] > 0) {
+ mw->messages[type] = 0;
+ invalidate = 1;
+ }
+ } else {
+ if (mw->messages[type] != information) {
+ mw->messages[type] = information;
+ invalidate = 1;
+ }
+ }
+
+ if (invalidate) {
+ if (mw_messages_property_name[type]) {
+ value = mw->messages[type];
+
+ dbus_gsm_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE,
+ mw_messages_property_name[type],
+ DBUS_TYPE_BYTE, &value);
+ }
+
+ if (!mw->pending)
+ mw->pending = g_timeout_add(0, mw_mwis_update, modem);
+ }
+}
+
+void ofono_message_waiting_message(struct ofono_modem *modem, const char *msg)
+{
+ struct message_waiting_data *mw = modem->message_waiting;
+ DBusConnection *conn = dbus_gsm_connection();
+
+ if (!mw)
+ return;
+
+ if (mw->last_message && !strcmp(mw->last_message, msg))
+ return;
+
+ if (mw->last_message)
+ g_free(mw->last_message);
+
+ mw->last_message = g_strdup(msg);
+
+ dbus_gsm_signal_property_changed(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE, "LastNotificationText",
+ DBUS_TYPE_STRING, &mw->last_message);
+}
+
+static void initialize_message_waiting(struct ofono_modem *modem)
+{
+ DBusConnection *conn = dbus_gsm_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);
+
+ 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 = dbus_gsm_connection();
+
+ g_dbus_unregister_interface(conn, modem->path,
+ MESSAGE_WAITING_INTERFACE);
+ modem_remove_interface(modem, MESSAGE_WAITING_INTERFACE);
+}
diff --git a/src/message-waiting.h b/src/message-waiting.h
new file mode 100644
index 0000000..cad4c40
--- /dev/null
+++ b/src/message-waiting.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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
+ *
+ */
+
+enum mwi_information_type {
+ MWI_UNSPECIFIED = -1,
+ MWI_MESSAGES_WAITING = -2,
+ MWI_NO_MESSAGES_WAITING = -3,
+};
+
+/* information either a positive (or zero) message count or a
+ * partial information using one of mwi_information_type constants
+ */
+void ofono_message_waiting_notify(struct ofono_modem *modem, int information,
+ enum sms_mwi_type type, int profile);
+void ofono_message_waiting_message(struct ofono_modem *modem, const char *msg);
diff --git a/src/modem.h b/src/modem.h
index d322df8..90993ca 100644
--- a/src/modem.h
+++ b/src/modem.h
@@ -43,6 +43,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;
};
diff --git a/src/simutil.h b/src/simutil.h
index 6572e72..c2b1e20 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 ef039d9..caab2e0 100644
--- a/src/sms.c
+++ b/src/sms.c
@@ -39,6 +39,7 @@
#include "util.h"
#include "sim.h"
#include "smsutil.h"
+#include "message-waiting.h"
#define uninitialized_var(x) x = x
@@ -658,9 +659,196 @@ static void handle_deliver(struct ofono_modem *modem,
g_slist_free(l);
}
-static void handle_mwi(struct ofono_modem *modem, struct sms *mwi)
+static void handle_special_sms_iei(struct ofono_modem *modem,
+ const guint8 *iei, int *set, int *store)
{
- ofono_error("MWI information not yet handled");
+ enum sms_mwi_type type;
+ int profile;
+
+ /* Parse type & storage byte */
+ *set = 0;
+ if (iei[0] & (1 << 7))
+ *store = 1;
+
+ 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_notify(modem, iei[1], type, profile);
+}
+
+static void handle_enhanced_voicemail_iei(struct ofono_modem *modem,
+ const guint8 *iei, int *set, int *store, 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 */
+ *set = 0;
+ if (iei[0] & (1 << 4))
+ *store = 1;
+
+ /* 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_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 */
+ *set = 0;
+ if (iei[0] & (1 << 4))
+ *store = 1;
+
+ /* TODO: VM_MAILBOX_ACCESS_ADDRESS */
+ n = 2 + (iei[1] + 1) / 2;
+ if (length < n + 11)
+ return;
+
+ /* Other parameters currently not supported */
+
+ ofono_message_waiting_notify(modem, iei[2 + n],
+ SMS_MWI_TYPE_VOICE, profile);
+ }
+}
+
+static void handle_mwi(struct ofono_modem *modem,
+ struct sms *sms, gboolean *out_discard)
+{
+ gboolean active, discard;
+ enum sms_mwi_type type;
+ char *message;
+ int profile = 1;
+ GSList *sms_list;
+
+ /* "Store" bits are ORed if multiple MWI types are present
+ * but if neither Special SMS Message Indication nor DCS based
+ * indication is present, the bit must remain set. */
+ int set = 1, store = 0;
+
+ /* Check MWI types in the order from lowest to highest priority
+ * because they will override one another. */
+
+ if (sms->deliver.pid == SMS_PID_TYPE_RETURN_CALL) {
+ ofono_message_waiting_notify(modem, MWI_UNSPECIFIED,
+ SMS_MWI_TYPE_VOICE, profile);
+ }
+
+ if (sms_mwi_dcs_decode(sms->deliver.dcs, &type,
+ NULL, &active, &discard)) {
+ set = 0;
+ store = (discard == FALSE);
+
+ if (active)
+ ofono_message_waiting_notify(modem,
+ MWI_MESSAGES_WAITING, type, profile);
+ else
+ ofono_message_waiting_notify(modem,
+ MWI_NO_MESSAGES_WAITING, type, profile);
+ }
+
+ if (sms_dcs_decode(sms->deliver.dcs, NULL, NULL, NULL, NULL) &&
+ sms->deliver.udhi) {
+ guint8 special_iei[4], *evm_iei;
+ struct sms_udh_iter iter;
+ enum sms_iei iei;
+
+ if (!sms_udh_iter_init(sms, &iter))
+ goto final;
+
+ 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,
+ &set, &store);
+ break;
+ }
+
+ sms_udh_iter_next(&iter);
+ }
+
+ /* Go through the UDH again because Enhanced Voice Mail
+ * Notification takes precedence over both DCS based
+ * indication and Special SMS Message indication
+ * (23.040 9.2.3.24.13.1). */
+
+ if (!sms_udh_iter_init(sms, &iter))
+ goto final;
+
+ 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,
+ &set, &store,
+ sms_udh_iter_get_ie_length(
+ &iter));
+
+ g_free(evm_iei);
+ break;
+ }
+
+ sms_udh_iter_next(&iter);
+ }
+ }
+
+final:
+ /* Only bother the Message Waiting interface with textual
+ * notifications that are not to be stored together with other
+ * Short Messages in ME. The other messages will be delivered
+ * to the user through normal SMS store. */
+ if (!store) {
+ sms_list = g_slist_append(NULL, sms);
+ message = sms_decode_text(sms_list);
+ g_slist_free(sms_list);
+
+ if (message) {
+ ofono_message_waiting_message(modem, message);
+ g_free(message);
+ }
+ }
+
+ if (out_discard)
+ *out_discard = !(set || store);
}
void ofono_sms_deliver_notify(struct ofono_modem *modem, unsigned char *pdu,
@@ -688,14 +876,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);
+ handle_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)) {
+ handle_mwi(modem, &sms, &discard);
if (discard)
return;
@@ -760,7 +952,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. */
+ handle_mwi(modem, &sms, &discard);
+
+ if (discard)
+ return;
+
goto out;
case SMS_IEI_WCMP:
ofono_error("No support for WCMP, ignoring");
@@ -792,6 +991,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)
@@ -827,4 +1029,6 @@ void ofono_sms_manager_unregister(struct ofono_modem *modem)
SMS_MANAGER_INTERFACE);
modem_remove_interface(modem, SMS_MANAGER_INTERFACE);
+
+ ofono_message_waiting_unregister(modem);
}
diff --git a/src/smsutil.h b/src/smsutil.h
index 89da973..d362aa9 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 {
--
1.6.1
12 years, 10 months
[PATCH 3/4] Fix possible memory leak on SIM reading error.
by Andrzej Zaborowski
This would also stall the SIM op queue if there's a read error for a record
other than the first. The other solution would be "goto next;" (keep
reading further records).
---
src/sim.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/src/sim.c b/src/sim.c
index deab6bd..695744f 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -317,9 +317,7 @@ static void sim_op_retrieve_cb(const struct ofono_error *error,
int fd;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- if (op->current == 1)
- sim_op_error(modem);
-
+ sim_op_error(modem);
return;
}
--
1.6.1
12 years, 10 months
ofono build error on ARM
by Andres Salomon
Hi,
I'm seeing the following build error when building ofono on an HTC G1
phone:
gcc -DHAVE_CONFIG_H -I. -I.. -I/usr/include/glib-2.0
-I/usr/lib/glib-2.0/include -g -O2 -g -Werror -Wextra
-Wno-unused-parameter -Wno-missing-field-initializers
-Wdeclaration-after-statement -Wmissing-declarations -Wredundant-decls
-Wcast-align -MT netlink.lo -MD -MP -MF .deps/netlink.Tpo -c netlink.c
-fPIC -DPIC -o .libs/netlink.o
cc1: warnings being treated as errors
netlink.c: In function ‘g_pn_nl_process’:
netlink.c:75: error: cast increases required alignment of target type
netlink.c:107: error: cast increases required alignment of target type
netlink.c:109: error: cast increases required alignment of target type
make[2]: *** [netlink.lo] Error 1
This is on a Debian lenny system. The code in question is (for
example):
for (rta = IFA_RTA(ifa);
Which expands to:
for (rta =
((struct rtattr*) ( ((char*)(ifa)) + ( ((sizeof(struct ifaddrmsg))+4 -1) & ~(4 -1) )))
;
I believe the compiler is not liking the cast from char* to rtattr*,
but I'm not certain.
gcc info:
localhost:~/ofono# gcc -v
Using built-in specs.
Target: arm-linux-gnueabi
Configured with: ../src/configure -v --with-pkgversion='Debian 4.3.2-1.1' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --disable-libssp --disable-sjlj-exceptions --enable-checking=release --build=arm-linux-gnueabi --host=arm-linux-gnueabi --target=arm-linux-gnueabi
Thread model: posix
gcc version 4.3.2 (Debian 4.3.2-1.1)
localhost:~/ofono# cat /proc/cpuinfo
Processor : ARMv6-compatible processor rev 2 (v6l)
BogoMIPS : 383.38
Features : swp half thumb fastmult edsp java
CPU implementer : 0x41
CPU architecture: 6TEJ
CPU variant : 0x1
CPU part : 0xb36
CPU revision : 2
Cache type : write-back
Cache clean : cp15 c7 ops
Cache lockdown : format C
Cache format : Harvard
I size : 32768
I assoc : 4
I line length : 32
I sets : 256
D size : 32768
D assoc : 4
D line length : 32
D sets : 256
Hardware : trout
Revision : 0080
Serial : 0000000000000000
12 years, 10 months
[PATCH RESEND]: add manpage for ofonod
by Andres Salomon
From 2b60ba66a75b1c60786bc92fee1a4e8ee67cb8da Mon Sep 17 00:00:00 2001
From: Andres Salomon <dilinger(a)collabora.co.uk>
Date: Mon, 27 Jul 2009 21:34:51 -0400
Subject: [PATCH] add manpage for ofonod
I created this manpage for Debian; feel free to use it. The license
is the same as oFono's.
---
doc/Makefile.am | 2 ++
doc/ofonod.8 | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+), 0 deletions(-)
create mode 100644 doc/ofonod.8
diff --git a/doc/Makefile.am b/doc/Makefile.am
index dae164a..85f6023 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -2,3 +2,5 @@
EXTRA_DIST = overview.txt
MAINTAINERCLEANFILES = Makefile.in
+
+man_MANS = ofonod.8
diff --git a/doc/ofonod.8 b/doc/ofonod.8
new file mode 100644
index 0000000..474d7fb
--- /dev/null
+++ b/doc/ofonod.8
@@ -0,0 +1,35 @@
+.\"
+.\" ofonod(8)
+.\"
+.\" Copyright (C) 2009 Collabora Ltd.
+.TH ofonod 8 "Jul 2009"
+.SH NAME
+ofonod \- oFono mobile telephony daemon
+.SH SYNOPSIS
+.B "ofonod [options]"
+.SH DESCRIPTION
+.B ofonod
+is a daemon which provides an oFono stack for interfacing mobile telephony devices.
+oFono is controlled through \fID-Bus\fP; for example, one can tell
+.B ofonod
+to send AT commands over /dev/rfcomm0 by calling the \fID-Bus\fP method org.ofono.at.Manager.Create.
+.I "/etc/dbus-1/system.d/ofono.conf"
+is used to manage \fID-Bus\fP permissions for oFono.
+.SH OPTIONS
+.TP
+.B --debug, -d
+Enable debug information output.
+.TP
+.B --nodetach, -n
+Don't run as daemon in background.
+.TP
+.SH SEE ALSO
+.PP
+\&\fIdbus-send\fR\|(1)
+
+.SH FILES
+.BR /etc/dbus-1/system.d/ofono.conf
+.SH AUTHOR
+.br
+This man page was written by Andres Salomon <dilinger(a)collabora.co.uk>.
+
--
1.6.3.3
12 years, 10 months
[PATCH 2/4] Don't use g_slist_length to check for empty lists.
by Andrzej Zaborowski
A glib Anti-pattern according to http://www.burtonini.com/blog
---
src/voicecall.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/voicecall.c b/src/voicecall.c
index 409d97a..b343ed6 100644
--- a/src/voicecall.c
+++ b/src/voicecall.c
@@ -897,7 +897,7 @@ static DBusMessage *manager_hangup_all(DBusConnection *conn,
if (!calls->ops->release_specific)
return dbus_gsm_not_implemented(msg);
- if (g_slist_length(calls->call_list) == 0) {
+ if (calls->call_list == NULL) {
DBusMessage *reply = dbus_message_new_method_return(msg);
return reply;
}
@@ -1009,7 +1009,7 @@ static DBusMessage *multiparty_hangup(DBusConnection *conn,
if (!calls->ops->release_all_active)
return dbus_gsm_not_implemented(msg);
- if (g_slist_length(calls->multiparty_list) == 0) {
+ if (calls->multiparty_list == NULL) {
DBusMessage *reply = dbus_message_new_method_return(msg);
return reply;
}
@@ -1362,7 +1362,7 @@ static void multirelease_callback(const struct ofono_error *error, void *data)
DBusConnection *conn = dbus_gsm_connection();
DBusMessage *reply;
- if (g_slist_length(calls->release_list)) {
+ if (calls->release_list != NULL) {
voicecalls_release_next(modem);
return;
}
--
1.6.1
12 years, 10 months
[PATCH 1/4] Clean up in sim.c.
by Andrzej Zaborowski
Remove unused variables and fields.
Move EFadn format parsing to a common function because various files use
this same format.
---
src/sim.c | 25 +++++--------------------
src/simutil.c | 28 ++++++++++++++++++++++++++++
src/simutil.h | 3 +++
unit/Makefile.am | 3 ++-
unit/test-simutil.c | 1 +
5 files changed, 39 insertions(+), 21 deletions(-)
diff --git a/src/sim.c b/src/sim.c
index 5122ee5..deab6bd 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -64,8 +64,6 @@ struct sim_file_op {
struct sim_manager_data {
struct ofono_sim_ops *ops;
- int flags;
- DBusMessage *pending;
char *imsi;
GSList *own_numbers;
GSList *ready_notify;
@@ -183,8 +181,6 @@ static void sim_msisdn_read_cb(struct ofono_modem *modem, int ok,
struct sim_manager_data *sim = modem->sim_manager;
int total;
struct ofono_phone_number *ph;
- int number_len;
- int ton_npi;
if (!ok)
return;
@@ -197,23 +193,12 @@ static void sim_msisdn_read_cb(struct ofono_modem *modem, int ok,
total = length / record_length;
- /* Skip Alpha-Identifier field */
- data += record_length - 14;
-
- number_len = *data++;
- ton_npi = *data++;
-
- if (number_len > 11 || ton_npi == 0xff)
- goto check;
-
ph = g_new(struct ofono_phone_number, 1);
- ph->type = bit_field(ton_npi, 4, 3);
-
- /* BCD coded, however the TON/NPI is given by the first byte */
- number_len = (number_len - 1) * 2;
-
- extract_bcd_number(data, number_len, ph->number);
+ if (sim_adn_parse(data, record_length, ph) == FALSE) {
+ g_free(ph);
+ goto check;
+ }
sim->own_numbers = g_slist_prepend(sim->own_numbers, ph);
@@ -792,5 +777,5 @@ void ofono_sim_manager_exit(struct ofono_modem *modem)
g_free(modem->sim_manager);
- modem->sim_manager = 0;
+ modem->sim_manager = NULL;
}
diff --git a/src/simutil.c b/src/simutil.c
index 1430ec3..51b1f5c 100644
--- a/src/simutil.c
+++ b/src/simutil.c
@@ -398,3 +398,31 @@ const struct sim_eons_operator_info *sim_eons_lookup_with_lac(
{
return sim_eons_lookup_common(eons, mcc, mnc, TRUE, lac);
}
+
+gboolean sim_adn_parse(const unsigned char *data, int length,
+ struct ofono_phone_number *ph)
+{
+ int number_len;
+ int ton_npi;
+
+ if (length < 14)
+ return FALSE;
+
+ /* Skip Alpha-Identifier field */
+ data += length - 14;
+
+ number_len = *data++;
+ ton_npi = *data++;
+
+ if (number_len > 11 || ton_npi == 0xff)
+ return FALSE;
+
+ ph->type = bit_field(ton_npi, 4, 3);
+
+ /* BCD coded, however the TON/NPI is given by the first byte */
+ number_len = (number_len - 1) * 2;
+
+ extract_bcd_number(data, number_len, ph->number);
+
+ return TRUE;
+}
diff --git a/src/simutil.h b/src/simutil.h
index d6526fc..6572e72 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -76,3 +76,6 @@ static inline enum sim_file_access file_access_condition_decode(int bcd)
return SIM_FILE_ACCESS_ADM;
return bcd;
}
+
+gboolean sim_adn_parse(const unsigned char *data, int length,
+ struct ofono_phone_number *ph);
diff --git a/unit/Makefile.am b/unit/Makefile.am
index d996465..8a27267 100644
--- a/unit/Makefile.am
+++ b/unit/Makefile.am
@@ -9,7 +9,8 @@ test_sms_SOURCES = test-sms.c $(top_srcdir)/src/util.c \
$(top_srcdir)/src/smsutil.c
test_simutil_SOURCES = test-simutil.c $(top_srcdir)/src/util.c \
- $(top_srcdir)/src/simutil.c
+ $(top_srcdir)/src/simutil.c \
+ $(top_srcdir)/src/smsutil.c
LDADD = @GLIB_LIBS@ @GTHREAD_LIBS@
diff --git a/unit/test-simutil.c b/unit/test-simutil.c
index 5945af0..0a0fa7c 100644
--- a/unit/test-simutil.c
+++ b/unit/test-simutil.c
@@ -24,6 +24,7 @@
#include <assert.h>
#include <glib.h>
+#include "driver.h"
#include "simutil.h"
const unsigned char valid_efopl[] = {
--
1.6.1
12 years, 10 months
sms segment fault with 160 char
by Li, Zhigang
Hi,
There was segment fault during send 160 char sms.
The content is 160 char like: abcdefghijklmnopqrstuvwxyz0123456789][=+..........
ofonod[12988]: Response line: +CSCA: "+8613800210500",145
ofonod[12988]: csca_query_cb: 8613800210500, 145
ofonod[12988]: Got 1 recipients
ofonod[12988]: ref: 1, offset: 3
ofonod[12988]: pdu_len: 155, tpdu_len: 154
ofonod[12988]: pdu_len: 36, tpdu_len: 35
ofonod[12988]: tx_next: 0x82660f0
ofonod[12988]: at_cmgs_cb got result: 1
ofonod[12988]: Final response: OK
ofonod[12988]: Response line: +CMGS: 31
ofonod[12988]: Got MR: 31
ofonod[12988]: tx_finished
ofonod[12988]: Peeking in the queue
ofonod[12988]: Scheduling next
Segmentation fault
Basically the "[ ]' will be encoded as UCS2, but it is 7bit according message head in fact.
So there were two problem:
1, tpdu_len was wrong: the problem was in sms encode
2, send more segment had issue.
Thanks
Zhigang
12 years, 10 months
Network information can't be updated dynamically
by Li, Zhigang
Hi,
I take a phone as modem to use ofono and find the network information can't be updated dynamically in ofono: so the network status always is roaming.
Because ofono get the response is roaming status at beginning.
ofonod[10503]: Response line: +CREG: 2,5,"188E","00006302"
The network status and signal strength will update dynamically but ofono can't receive it automatically because modem can't send it regular. or anything wrong in my understanding?
Can ofono send the CREG command regular to get the network information look like COPS command?
If we expect application to initialize this request then which interface for it?
Get properties and properties_changed can't get the updated information so far.
Thanks
12 years, 11 months
[PATCH] Cache EF-PNN, EF-OPL sim files on disk.
by Andrzej Zaborowski
This uses plain files in /var/cache/ofono for storing contents of the
operator lists to avoid possibly numerous queries to the SIM on every
startup. Files are indexed with IMSI. I'm not 100% sure about the
autoconf magic.
Users need to rerun bootstrap-configure after applying this.
---
bootstrap-configure | 3 +-
configure.ac | 5 +
src/sim.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 233 insertions(+), 8 deletions(-)
diff --git a/bootstrap-configure b/bootstrap-configure
index 2519f22..2c4d9a2 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -10,4 +10,5 @@ fi
--prefix=/usr \
--mandir=/usr/share/man \
--sysconfdir=/etc \
- --disable-datafiles
+ --disable-datafiles \
+ --localstatedir=/var
diff --git a/configure.ac b/configure.ac
index 2d16fae..dd1d7aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,6 +87,11 @@ AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
+eval "eval LOCALSTATE_DIR=$localstatedir"
+AC_SUBST(LOCALSTATE_DIR)
+AC_DEFINE_UNQUOTED(CONFIG_LOCALSTATEDIR, "$LOCALSTATE_DIR",
+ [Define to the location where state is stored.])
+
COMPILER_FLAGS
AC_OUTPUT(Makefile gdbus/Makefile gatchat/Makefile gisi/Makefile
diff --git a/src/sim.c b/src/sim.c
index 13557bf..f7992c7 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -25,6 +25,10 @@
#include <string.h>
#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
#include <dbus/dbus.h>
#include <glib.h>
@@ -70,6 +74,219 @@ struct sim_manager_data {
int pnn_current;
};
+static int create_dirs(const char *filename, const mode_t mode)
+{
+ struct stat st;
+ char *dir;
+ const char *prev, *next;
+ int err;
+
+ err = stat(filename, &st);
+ if (!err && S_ISREG(st.st_mode))
+ return 0;
+
+ dir = g_malloc(strlen(filename) + 1);
+ strcpy(dir, "/");
+
+ for (prev = filename; next = strchr(prev + 1, '/'); prev = next)
+ if (next > prev + 1) {
+ strncat(dir, prev + 1, next - prev);
+
+ if (mkdir(dir, mode) && errno != EEXIST) {
+ g_free(dir);
+ return -1;
+ }
+ }
+
+ g_free(dir);
+ return 0;
+}
+
+#define SIM_CACHE_MODE 0600
+#define SIM_CACHE_PATH CONFIG_LOCALSTATEDIR "/cache/ofono/%s/%04x"
+#define SIM_CACHE_PATH_LEN(imsilen) (strlen(SIM_CACHE_PATH) - 2 + imsilen)
+
+struct sim_cache_callback {
+ struct sim_manager_data *sim;
+ void *cb;
+ void *data;
+ int fileid;
+ int record;
+};
+
+static void read_file_info_cached_cb(const struct ofono_error *error,
+ int file_length, enum ofono_sim_file_structure structure,
+ int record_length, void *data)
+{
+ struct sim_cache_callback *cbs = data;
+ ofono_sim_file_info_cb_t cb = cbs->cb;
+ char *path;
+ char *imsi = cbs->sim->imsi;
+ unsigned char fileinfo[6];
+ int fd = -1, fileid, ret;
+
+ cb(error, file_length, structure, record_length, cbs->data);
+
+ fileid = cbs->fileid;
+ g_free(cbs);
+
+ /* Even if the file doesn't exist, cache this fact so we don't
+ * try and fail every time. */
+ if (imsi) {
+ path = g_strdup_printf(SIM_CACHE_PATH ".info", imsi, fileid);
+ if (create_dirs(path, SIM_CACHE_MODE | S_IXUSR) == 0)
+ fd = open(path, O_WRONLY | O_CREAT, SIM_CACHE_MODE);
+ g_free(path);
+
+ if (fd == -1) {
+ ofono_debug("Error %i creating cache file for "
+ "fileid %04x, IMSI %s",
+ errno, fileid, imsi);
+ return;
+ }
+
+ fileinfo[0] = error->type;
+ fileinfo[1] = file_length >> 8;
+ fileinfo[2] = file_length & 0xff;
+ fileinfo[3] = structure;
+ fileinfo[4] = record_length >> 8;
+ fileinfo[5] = record_length & 0xff;
+
+ write(fd, fileinfo, 6);
+ close(fd);
+ }
+}
+
+static void read_file_info_cached(struct ofono_modem *modem, int fileid,
+ ofono_sim_file_info_cb_t cb, void *data)
+{
+ char *path;
+ char *imsi = modem->sim_manager->imsi;
+ int fd;
+ unsigned char fileinfo[6];
+ ssize_t len;
+ struct ofono_error error;
+ int file_length;
+ enum ofono_sim_file_structure structure;
+ int record_length;
+ struct sim_cache_callback *cbs;
+
+ if (!imsi)
+ goto uncached;
+
+ path = g_strdup_printf(SIM_CACHE_PATH ".info", imsi, fileid);
+ fd = open(path, O_RDONLY);
+ g_free(path);
+
+ if (fd == -1) {
+ if (errno != ENOENT)
+ ofono_debug("Error %i opening cache file for "
+ "fileid %04x, IMSI %s",
+ errno, fileid, imsi);
+
+ goto uncached;
+ }
+
+ len = read(fd, fileinfo, 6);
+ close(fd);
+
+ if (len == 6) {
+ error.type = fileinfo[0];
+ file_length = (fileinfo[1] << 8) | fileinfo[2];
+ structure = fileinfo[3];
+ record_length = (fileinfo[4] << 8) | fileinfo[5];
+
+ return cb(&error, file_length, structure, record_length, data);
+ }
+
+uncached:
+ cbs = g_new(struct sim_cache_callback, 1);
+ cbs->sim = modem->sim_manager;
+ cbs->cb = cb;
+ cbs->data = data;
+ cbs->fileid = fileid;
+ return modem->sim_manager->ops->read_file_info(modem,
+ fileid, read_file_info_cached_cb, cbs);
+}
+
+static void read_file_linear_cached_cb(const struct ofono_error *error,
+ const unsigned char *buffer, int length, void *data)
+{
+ struct sim_cache_callback *cbs = data;
+ ofono_sim_read_cb_t cb = cbs->cb;
+ char *path;
+ char *imsi = cbs->sim->imsi;
+ int fd = -1, fileid, ret, record;
+
+ cb(error, buffer, length, cbs->data);
+
+ fileid = cbs->fileid;
+ record = cbs->record;
+ g_free(cbs);
+
+ /* If read was successful, store the record contents */
+ if (error->type == OFONO_ERROR_TYPE_NO_ERROR && imsi) {
+ path = g_strdup_printf(SIM_CACHE_PATH, imsi, fileid);
+ if (create_dirs(path, SIM_CACHE_MODE | S_IXUSR) == 0)
+ fd = open(path, O_WRONLY | O_CREAT, SIM_CACHE_MODE);
+ g_free(path);
+
+ if (fd == -1)
+ return;
+
+ if (!record || lseek(fd, length * record, SEEK_SET) !=
+ (off_t) -1)
+ write(fd, buffer, length);
+ close(fd);
+ }
+}
+
+static void read_file_linear_cached(struct ofono_modem *modem, int fileid,
+ int record, int length, ofono_sim_read_cb_t cb, void *data)
+{
+ char *path;
+ char *imsi = modem->sim_manager->imsi;
+ int fd;
+ unsigned char buffer[length];
+ ssize_t rlength = 0;
+ struct ofono_error error;
+ struct sim_cache_callback *cbs;
+
+ if (!imsi)
+ goto uncached;
+
+ path = g_strdup_printf(SIM_CACHE_PATH, imsi, fileid);
+ fd = open(path, O_RDONLY);
+ g_free(path);
+
+ if (fd == -1) {
+ if (errno != ENOENT)
+ ofono_debug("Error %i opening cache file for "
+ "fileid %04x, IMSI %s", fileid, imsi);
+
+ goto uncached;
+ }
+
+ if (!record || lseek(fd, length * record, SEEK_SET) != (off_t) -1)
+ rlength = read(fd, buffer, length);
+ close(fd);
+
+ if (rlength == length) {
+ error.type = OFONO_ERROR_TYPE_NO_ERROR;
+ return cb(&error, buffer, length, data);
+ }
+
+uncached:
+ cbs = g_new(struct sim_cache_callback, 1);
+ cbs->sim = modem->sim_manager;
+ cbs->cb = cb;
+ cbs->data = data;
+ cbs->fileid = fileid;
+ cbs->record = record;
+ return modem->sim_manager->ops->read_file_linear(modem, fileid,
+ record, length, read_file_linear_cached_cb, cbs);
+}
+
static char **get_own_numbers(GSList *own_numbers)
{
int nelem = 0;
@@ -762,7 +979,7 @@ static void sim_opl_read_cb(const struct ofono_error *error,
skip:
sim->opl_current ++;
if (sim->opl_current < sim->opl_num)
- sim->ops->read_file_linear(modem, SIM_EFOPL_FILEID,
+ read_file_linear_cached(modem, SIM_EFOPL_FILEID,
sim->opl_current,
sim->opl_size,
sim_opl_read_cb, modem);
@@ -787,7 +1004,7 @@ static void sim_opl_info_cb(const struct ofono_error *error, int length,
sim->opl_current = 0;
sim->opl_size = record_length;
sim->opl_num = length / record_length;
- sim->ops->read_file_linear(modem, SIM_EFOPL_FILEID, 0,
+ read_file_linear_cached(modem, SIM_EFOPL_FILEID, 0,
record_length, sim_opl_read_cb, modem);
}
@@ -796,7 +1013,7 @@ static gboolean sim_retrieve_opl(void *user_data)
struct ofono_modem *modem = user_data;
struct sim_manager_data *sim = modem->sim_manager;
- sim->ops->read_file_info(modem, SIM_EFOPL_FILEID,
+ read_file_info_cached(modem, SIM_EFOPL_FILEID,
sim_opl_info_cb, modem);
return FALSE;
@@ -861,7 +1078,7 @@ static void sim_pnn_read_cb(const struct ofono_error *error,
skip:
sim->pnn_current ++;
if (sim->pnn_current < sim->pnn_num)
- sim->ops->read_file_linear(modem, SIM_EFPNN_FILEID,
+ read_file_linear_cached(modem, SIM_EFPNN_FILEID,
sim->pnn_current,
sim->pnn_size,
sim_pnn_read_cb, modem);
@@ -892,7 +1109,7 @@ static void sim_pnn_info_cb(const struct ofono_error *error, int length,
sim->pnn_size = record_length;
sim->pnn_num = length / record_length;
sim->pnn = g_new0(struct pnn_operator, sim->pnn_num);
- sim->ops->read_file_linear(modem, SIM_EFPNN_FILEID, 0,
+ read_file_linear_cached(modem, SIM_EFPNN_FILEID, 0,
record_length, sim_pnn_read_cb, modem);
}
@@ -901,7 +1118,7 @@ static gboolean sim_retrieve_pnn(void *user_data)
struct ofono_modem *modem = user_data;
struct sim_manager_data *sim = modem->sim_manager;
- sim->ops->read_file_info(modem, SIM_EFPNN_FILEID,
+ read_file_info_cached(modem, SIM_EFPNN_FILEID,
sim_pnn_info_cb, modem);
return FALSE;
@@ -940,8 +1157,10 @@ static void initialize_sim_manager(struct ofono_modem *modem)
if (modem->sim_manager->ops->read_file_transparent)
g_timeout_add(0, sim_retrieve_spdi, modem);
+ /* Schedule later than IMSI so that there's a chance we can
+ * use SIM cache, which is IMSI-indexed. */
if (modem->sim_manager->ops->read_file_linear)
- g_timeout_add(0, sim_retrieve_pnn, modem);
+ g_timeout_add_seconds(1, sim_retrieve_pnn, modem);
}
int ofono_sim_manager_register(struct ofono_modem *modem,
--
1.6.0
12 years, 11 months
Segment fault in sending sms to more reciptent
by Li, Zhigang
HI
Current sms should support more recipients, right?
And base on the interface the parameter should be: [number1, number2], content
But there was segment fault:
ofonod[11097]: Got 2 recipients
ofonod[11097]: ref: 2, offset: 0
ofonod[11097]: pdu_len: 19, tpdu_len: 18
ofonod[11097]: ref: 3, offset: 0
ofonod[11097]: pdu_len: 19, tpdu_len: 18
ofonod[11097]: tx_next: 0x9d04c78
ofonod[11097]: at_cmgs_cb got result: 1
ofonod[11097]: Final response: OK
ofonod[11097]: Response line: +CMGS: 30
ofonod[11097]: Got MR: 30
ofonod[11097]: tx_finished
ofonod[11097]: Peeking in the queue
ofonod[11097]: Scheduling next
Segmentation fault
Thanks
12 years, 11 months