---
 Makefile.am        |    3 +-
 src/cdma-sms.c     |  342 ++++++++++++++++++++++++++++++++++++++
 src/cdma-smsutil.c |  467 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/cdma-smsutil.h |  264 +++++++++++++++++++++++++++++
 4 files changed, 1075 insertions(+), 1 deletions(-)
 create mode 100644 src/cdma-sms.c
 create mode 100644 src/cdma-smsutil.c
 create mode 100644 src/cdma-smsutil.h

diff --git a/Makefile.am b/Makefile.am
index 13cbc37..b7dc5ee 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -319,7 +319,8 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) 
src/ofono.ver \
                        src/radio-settings.c src/stkutil.h src/stkutil.c \
                        src/nettime.c src/stkagent.c src/stkagent.h \
                        src/simfs.c src/simfs.h src/audio-settings.c \
-                       src/smsagent.c src/smsagent.h src/ctm.c
+                       src/smsagent.c src/smsagent.h src/ctm.c \
+                       src/cdma-sms.c src/cdma-smsutil.c
 
 src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl
 
diff --git a/src/cdma-sms.c b/src/cdma-sms.c
new file mode 100644
index 0000000..1271345
--- /dev/null
+++ b/src/cdma-sms.c
@@ -0,0 +1,342 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2010  Nokia 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 <errno.h>
+
+#include <glib.h>
+#include <gdbus.h>
+#include <sys/time.h>
+
+#include "ofono.h"
+
+#include "cdma-smsutil.h"
+#include "cdma-sms.h"
+
+static GSList *g_drivers;
+
+struct ofono_cdmasms {
+       const struct ofono_cdmasms_driver *driver;
+       void *driver_data;
+       struct ofono_atom *atom;
+};
+
+static GDBusMethodTable cdmasms_manager_methods[] = {
+       /* TODO */
+       { }
+};
+
+static GDBusSignalTable cdmasms_manager_signals[] = {
+       { "IncomingMessage",    "sa{sv}"        },
+       /* TODO */
+       { }
+};
+
+static void cdma_dispatch_text_message(struct ofono_cdmasms *cdmasms,
+                                                                               
const char *message,
+                                                                               
const char *oaddr)
+{
+       const char *path = ofono_cdmasms_get_path(cdmasms);
+       DBusConnection *conn = ofono_dbus_get_connection();
+       DBusMessage *signal;
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       const char *signal_name;
+
+       /* TODO: Support ImmediateMessage */
+       signal_name = "IncomingMessage";
+
+       signal = dbus_message_new_signal(path,
+                               OFONO_CDMA_MESSAGE_MANAGER_INTERFACE,
+                               signal_name);
+       if (signal == NULL)
+               return;
+
+       dbus_message_iter_init_append(signal, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+                       &(message));
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict);
+
+       ofono_dbus_dict_append(&dict, "Sender", DBUS_TYPE_STRING,
+                       &oaddr);
+
+       /* TODO: Other property not supported yet */
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       g_dbus_send_message(conn, signal);
+
+    /*TODO: Add the message to history*/
+}
+
+static void ofono_cdmasms_process_wmt_deliver(struct ofono_cdmasms *cdmasms,
+                                                                               
                struct cdma_sms *incoming)
+{
+       char *message;
+       char *oaddr;
+
+       message = cdmasms_decode_text(&incoming->p2p_msg.bearer_data.ud);
+       if (message == NULL)
+               return;
+
+       oaddr = cdmasms_address_to_string(&incoming->p2p_msg.oaddr);
+       if (oaddr == NULL) {
+               g_free(message);
+               return;
+       }
+
+       cdma_dispatch_text_message(cdmasms, message, oaddr);
+
+       g_free(message);
+       g_free(oaddr);
+}
+
+static void ofono_cdmasms_process_wmt(struct ofono_cdmasms *cdmasms,
+               struct cdma_sms *incoming)
+{
+       if (!check_bitmap(incoming->p2p_msg.bearer_data.subparam_bitmap,
+                               SMS_SUBPARAM_ID_MESSAGE_ID))
+               return;
+
+       /* TODO: Add duplicate detection support */
+
+       switch (incoming->p2p_msg.bearer_data.id.msg_type) {
+       case CDMASMS_RESERVED:
+               break;
+       case CDMASMS_DELIVER:
+               ofono_cdmasms_process_wmt_deliver(cdmasms, incoming);
+               break;
+       case CDMASMS_SUBMIT:
+       case CDMASMS_CANCEL:
+       case CDMASMS_DELIVER_ACK:
+       case CDMASMS_USER_ACK:
+       case CDMASMS_READ_ACK:
+               break; /* TODO */
+       }
+}
+
+static void ofono_cdmasms_process_p2p(struct ofono_cdmasms *cdmasms,
+                                                                               
struct cdma_sms *incoming)
+{
+       /* Check validity of incoming message, per Table 3.4.2.1-1 */
+       if (!(check_bitmap(incoming->p2p_msg.bearer_data.subparam_bitmap,
+                                       SMS_PARAM_ID_TELESERVICE_IDENTIFIER)
+                       &&
+                       check_bitmap(incoming->p2p_msg.param_bitmap,
+                               SMS_PARAM_ID_ORIGINATING_ADDRESS)
+                       ))
+               return;
+
+       switch (incoming->p2p_msg.teleservice_id) {
+       case TELESERVICE_CMT91:
+       case TELESERVICE_WPT:
+               break; /* TODO: Not supported yet */
+       case TELESERVICE_WMT:
+               ofono_cdmasms_process_wmt(cdmasms, incoming);
+               break;
+       case TELESERVICE_VMN:
+       case TELESERVICE_WAP:
+       case TELESERVICE_WEMT:
+       case TELESERVICE_SCPT:
+       case TELESERVICE_CATPT:
+               break; /* TODO: Not supported yet */
+       }
+}
+
+void ofono_cdmasms_deliver_notify(struct ofono_cdmasms *cdmasms,
+                                                                       
unsigned char *pdu, int pdu_len)
+{
+       struct cdma_sms s;
+       gboolean ret;
+
+       DBG("pdu len %d", pdu_len);
+
+       memset(&s, 0, sizeof(struct cdma_sms));
+
+       ret = cdmasms_decode(pdu, pdu_len, &s);
+       if (!ret)
+               return;
+
+       switch (s.type) {
+       case CDMASMS_P2P:
+               ofono_cdmasms_process_p2p(cdmasms, &s);
+               break;
+       case CDMASMS_BCAST:
+       case CDMASMS_ACK:
+               /*
+                * TODO: Support SMS Broadcast Message and SMS
+                * Acknowledge Message.
+                */
+               break;
+       }
+}
+
+int ofono_cdmasms_driver_register(const struct ofono_cdmasms_driver *d)
+{
+       DBG("driver: %p, name: %s", d, d->name);
+
+       if (d->probe == NULL)
+               return -EINVAL;
+
+       g_drivers = g_slist_prepend(g_drivers, (void *)d);
+
+       return 0;
+}
+
+void ofono_cdmasms_driver_unregister(const struct ofono_cdmasms_driver *d)
+{
+       DBG("driver: %p, name: %s", d, d->name);
+
+       g_drivers = g_slist_remove(g_drivers, (void *)d);
+}
+
+static void cdmasms_unregister(struct ofono_atom *atom)
+{
+       DBusConnection *conn = ofono_dbus_get_connection();
+       struct ofono_modem *modem = __ofono_atom_get_modem(atom);
+       const char *path = __ofono_atom_get_path(atom);
+
+       g_dbus_unregister_interface(conn, path,
+                                       OFONO_CDMA_MESSAGE_MANAGER_INTERFACE);
+
+       ofono_modem_remove_interface(modem,
+               OFONO_CDMA_MESSAGE_MANAGER_INTERFACE);
+}
+
+static void cdmasms_remove(struct ofono_atom *atom)
+{
+       struct ofono_cdmasms *cdmasms = __ofono_atom_get_data(atom);
+
+       DBG("atom: %p", atom);
+
+       if (cdmasms == NULL)
+               return;
+
+       if (cdmasms->driver && cdmasms->driver->remove)
+               cdmasms->driver->remove(cdmasms);
+
+       g_free(cdmasms);
+}
+
+/*
+ * Create a CDMA SMS driver
+ *
+ * This creates a CDMA SMS driver that is hung off a @modem
+ * object. However, for the driver to be used by the system, it has to
+ * be registered with the oFono core using ofono_sms_register().
+ *
+ * This is done once the modem driver determines that SMS is properly
+ * supported by the hardware.
+ */
+struct ofono_cdmasms *ofono_cdmasms_create(struct ofono_modem *modem,
+                                                                               
        unsigned int vendor,
+                                                                               
        const char *driver,
+                                                                               
        void *data)
+{
+       struct ofono_cdmasms *cdmasms;
+       GSList *l;
+
+       if (driver == NULL)
+               return NULL;
+
+       cdmasms = g_try_new0(struct ofono_cdmasms, 1);
+       if (cdmasms == NULL)
+               return NULL;
+
+       cdmasms->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_SMS,
+                                               cdmasms_remove, cdmasms);
+
+       for (l = g_drivers; l; l = l->next) {
+               const struct ofono_cdmasms_driver *drv = l->data;
+
+               if (g_strcmp0(drv->name, driver))
+                       continue;
+
+               if (drv->probe(cdmasms, vendor, data) < 0)
+                       continue;
+
+               cdmasms->driver = drv;
+               break;
+       }
+
+       return cdmasms;
+}
+
+/*
+ * Indicate oFono that a CDMA SMS driver is ready for operation
+ *
+ * This is called after ofono_cdmasms_create() was done and the modem
+ * driver determined that a modem supports SMS correctly. Once this
+ * call succeeds, the D-BUS interface for SMS goes live.
+ */
+void ofono_cdmasms_register(struct ofono_cdmasms *cdmasms)
+{
+       DBusConnection *conn = ofono_dbus_get_connection();
+       struct ofono_modem *modem = __ofono_atom_get_modem(cdmasms->atom);
+       const char *path = __ofono_atom_get_path(cdmasms->atom);
+
+       if (!g_dbus_register_interface(conn, path,
+                                       OFONO_CDMA_MESSAGE_MANAGER_INTERFACE,
+                                       cdmasms_manager_methods,
+                                       cdmasms_manager_signals,
+                                       NULL, cdmasms, NULL)) {
+               ofono_error("Could not create %s interface",
+                               OFONO_CDMA_MESSAGE_MANAGER_INTERFACE);
+               return;
+       }
+
+       ofono_modem_add_interface(modem, OFONO_CDMA_MESSAGE_MANAGER_INTERFACE);
+
+       __ofono_atom_register(cdmasms->atom, cdmasms_unregister);
+}
+
+void ofono_cdmasms_remove(struct ofono_cdmasms *cdmasms)
+{
+       __ofono_atom_free(cdmasms->atom);
+}
+
+void ofono_cdmasms_set_data(struct ofono_cdmasms *cdmasms, void *data)
+{
+       cdmasms->driver_data = data;
+}
+
+void *ofono_cdmasms_get_data(struct ofono_cdmasms *cdmasms)
+{
+       return cdmasms->driver_data;
+}
+
+struct ofono_atom *ofono_cdmasms_get_atom(struct ofono_cdmasms *cdmasms)
+{
+       return cdmasms->atom;
+}
+
+const char *ofono_cdmasms_get_path(struct ofono_cdmasms *cdmasms)
+{
+       return __ofono_atom_get_path(cdmasms->atom);
+}
diff --git a/src/cdma-smsutil.c b/src/cdma-smsutil.c
new file mode 100644
index 0000000..e140d60
--- /dev/null
+++ b/src/cdma-smsutil.c
@@ -0,0 +1,467 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2010  Nokia 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
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "cdma-smsutil.h"
+
+/*
+ * Mapping from binary DTMF code to the digit it represents.
+ * As defined in Table 2.7.1.3.2.4-4 of 3GPP2 C.S0005-E v2.0.
+ * Note, 0 is NOT a valid value and not mapped to
+ * any valid DTMF digit.
+ */
+const char cdmasms_dtmf_digits[13] = {0, '1', '2', '3', '4', '5', '6', '7',
+               '8', '9', '0', '*', '#'};
+
+
+/* Unpacks the byte stream. */
+static guint32 bit_field_unpack(const guint8 *buf,
+                                                               guint32 offset,
+                                                               guint32 nbit)
+{
+       guint32    val = 0;
+       guint32    byteIndex;
+       guint32    remainder;
+
+       if (buf == NULL)
+               return 0;
+
+       byteIndex =  offset >> 3;
+       remainder = (offset & 0x7);
+
+       if (remainder != 0) {
+               /* The field to be unpacked does not start at the byte boundary.
+                * Retrieve those bits first. */
+               if (nbit >= (8 - remainder)) {
+                       /* The field at least spans till the end of the byte. */
+                       val =  buf[byteIndex]  & ((1 << (8 - remainder)) - 1);
+                       nbit -=  (8 - remainder);
+                       byteIndex++;
+               } else {
+                       val = (buf[byteIndex]  &
+                               ((1 << (8 - remainder)) - 1)) >> (8 - remainder 
- nbit);
+                       return val;
+               }
+       }
+
+       /* Unpack rest of the bits in the field in 8-bit chunk. */
+       while (nbit >= 8) {
+               val = (val << 8) | buf[byteIndex];
+               nbit -= 8;
+               byteIndex++;
+       }
+
+       /* If still some left, unpack the last remaining bits. */
+       if (nbit > 0)
+               val = (val << nbit) | (buf[byteIndex]  >> (8 - nbit));
+
+       return val;
+}
+
+/* Convert CDMA DTMF digits into a string */
+static gboolean cdmasms_dtmf_to_ascii(char *buf, const char *addr,
+                                                                               
guint8 num_fields)
+{
+       guint8 index;
+       guint8 value;
+
+       if (buf == NULL || addr == NULL)
+               return FALSE;
+
+       for (index = 0; index < num_fields; index++) {
+               if ((addr[index] <= 0) || (addr[index] > 12))
+                       return FALSE;  /* Invalid digit in address field */
+
+               value = (guint8) addr[index];
+               buf[index] = cdmasms_dtmf_digits[value];
+       }
+
+       buf[index] = 0; /* Make it NULL terminated string */
+
+       return TRUE;
+}
+
+char *cdmasms_address_to_string(const struct cdmasms_address *addr)
+{
+       char *buf;
+
+       if (addr == NULL)
+               return NULL;
+
+       if (addr->digit_mode != DTMF_4_BIT)
+               return NULL; /* TODO: Only support DTMF_4_BIT currently */
+
+       buf = g_new(char, addr->num_fields + 1);
+       if (buf == NULL)
+               return NULL;
+
+       if (!cdmasms_dtmf_to_ascii(buf, addr->address, addr->num_fields)) {
+               g_free(buf);
+               return NULL;
+    }
+
+       return buf;
+}
+
+/* Decode Address parameter record */
+static gboolean cdmasms_decode_addr(const unsigned char *buf, int len,
+                                                                               
struct cdmasms_address *addr)
+{
+       guint32 bit_offset = 0;
+       guint8  chari_len;
+       guint32 total_num_bits = len * 8;
+       guint8  index;
+
+       if (len <= 0 || buf == NULL || addr == NULL)
+               return FALSE;
+
+       addr->digit_mode = (enum cdmasms_digit_mode) bit_field_unpack(buf, 0, 
1);
+       bit_offset += 1;
+       addr->number_mode = (guint8) bit_field_unpack(buf, bit_offset, 1);
+       bit_offset += 1;
+
+       if (addr->digit_mode == CODE_8_BIT) {
+               addr->number_type = (guint8) bit_field_unpack(buf, bit_offset, 
3);
+               bit_offset += 3;
+
+               if (addr->number_mode == 0) {
+                       if (bit_offset + 4 > total_num_bits)
+                               return FALSE;
+
+                       addr->number_plan = (enum cdmasms_numbering_plan)
+                                                                       
bit_field_unpack(buf, bit_offset, 4);
+                       bit_offset += 4;
+               }
+       }
+
+       if ((bit_offset + 8) > total_num_bits)
+               return FALSE;
+
+       addr->num_fields = (guint8) bit_field_unpack(buf, bit_offset, 8);
+       bit_offset += 8;
+
+       if (addr->digit_mode == DTMF_4_BIT)
+               chari_len = 4;
+       else
+               chari_len = 8;
+
+       if ((bit_offset + (chari_len * addr->num_fields)) > total_num_bits)
+               return FALSE;
+
+       for (index = 0; index < addr->num_fields; index++) {
+               addr->address[index] = (char) bit_field_unpack(buf, bit_offset,
+                                                                               
                                chari_len);
+               bit_offset += chari_len;
+       }
+
+       return TRUE;
+}
+
+char *cdmasms_decode_text(struct cdmasms_ud *ud)
+{
+       char *buf;
+
+       if (ud == NULL)
+               return NULL;
+
+       /* TODO: Only support MSG_ENCODING_7BIT_ASCII currently */
+       if (ud->msg_encoding != MSG_ENCODING_7BIT_ASCII)
+               return NULL;
+
+       buf = g_new(char, ud->num_fields + 1);
+       if (buf == NULL)
+               return NULL;
+
+       memcpy(buf, ud->chari, ud->num_fields);
+       buf[ud->num_fields] = 0; /* Make it NULL terminated string */
+
+       return buf;
+}
+
+/* Decode User Data */
+static gboolean cdmasms_decode_ud(const unsigned char *buf,
+                                                                       int 
len, struct cdmasms_ud *ud)
+{
+       guint32 bit_offset = 0;
+       guint8  chari_len = 0;
+       guint32 total_num_bits = len * 8;
+       guint8  index;
+       enum cdmasms_message_encoding  msg_encoding;
+
+       if (buf == NULL || ud == NULL)
+               return FALSE;
+
+       if (total_num_bits < 13)
+               return FALSE;
+
+       msg_encoding = (enum cdmasms_message_encoding)
+                                       bit_field_unpack(buf, bit_offset, 5);
+       ud->msg_encoding =  msg_encoding;
+       bit_offset += 5;
+
+       if (ud->msg_encoding == MSG_ENCODING_EXTENDED_PROTOCOL_MSG ||
+                       ud->msg_encoding == MSG_ENCODING_GSM_DATA_CODING) {
+               /* Skip message type field */
+               /* TODO: Add support for message type field */
+               bit_offset += 8;
+       }
+
+       if (bit_offset + 8 > total_num_bits)
+               return FALSE;
+
+       ud->num_fields = (guint8) bit_field_unpack(buf, bit_offset, 8);
+       bit_offset += 8;
+
+       switch (msg_encoding) {
+       case MSG_ENCODING_OCTET:
+               chari_len = 8;
+               break;
+       case MSG_ENCODING_EXTENDED_PROTOCOL_MSG:
+               return FALSE; /* TODO */
+       case MSG_ENCODING_7BIT_ASCII:
+       case MSG_ENCODING_IA5:
+               chari_len = 7;
+               break;
+       case MSG_ENCODING_UNICODE:
+       case MSG_ENCODING_SHIFT_JIS:
+       case MSG_ENCODING_KOREAN:
+               return FALSE; /* TODO */
+       case MSG_ENCODING_LATIN_HEBREW:
+       case MSG_ENCODING_LATIN:
+               chari_len = 8;
+               break;
+       case MSG_ENCODING_GSM_7BIT:
+               chari_len = 7;
+               break;
+       case MSG_ENCODING_GSM_DATA_CODING:
+               return FALSE; /* TODO */
+       }
+
+       if (chari_len == 0)
+               return FALSE;
+
+       if (bit_offset + chari_len * ud->num_fields > total_num_bits)
+               return FALSE;
+
+       for (index = 0; index < ud->num_fields; index++) {
+               ud->chari[index] = (guint8) bit_field_unpack(buf, bit_offset,
+                                                                               
chari_len);
+               bit_offset += chari_len;
+       }
+
+       return TRUE;
+}
+
+/* Decode Message Identifier */
+static gboolean cdmasms_decode_message_id(const unsigned char *buf,
+                                                                               
        int len,
+                                                                               
        struct cdmasms_identifier *id)
+{
+       guint32 bit_offset = 0;
+
+       if (buf == NULL || id == NULL)
+               return FALSE;
+
+    if (len != 3)
+               return FALSE;
+
+       id->msg_type = (enum cdmasms_msg_type) bit_field_unpack(buf, 
bit_offset, 4);
+       bit_offset += 4;
+       id->msg_id = (guint16) bit_field_unpack(buf, bit_offset, 16);
+       bit_offset += 16;
+       id->header_ind = (gboolean) bit_field_unpack(buf, bit_offset, 1);
+
+       return TRUE;
+}
+
+/* Decode Bearer Data */
+static gboolean cdmasms_decode_bearer_data(const unsigned char *buf, int len,
+                                                                       struct 
cdmasms_bearer_data *bearer_data)
+{
+       gboolean ret = TRUE;
+       enum cdmasms_subparam_id subparam_id;
+       guint8 subparam_len;
+
+       if (buf == NULL || bearer_data == NULL)
+               return FALSE;
+
+       while (len != 0) {
+
+               if (len < 2)
+                       return FALSE;
+
+               subparam_id = (enum cdmasms_subparam_id) bit_field_unpack(buf, 
0, 8);
+               buf += 1;
+               subparam_len = (guint8) bit_field_unpack(buf, 0, 8);
+               buf += 1;
+               len -= 2;
+
+               if (len < subparam_len)
+                       return FALSE;
+
+               switch (subparam_id) {
+               case SMS_SUBPARAM_ID_MESSAGE_ID:
+                       ret = cdmasms_decode_message_id(buf, subparam_len,
+                                                                               
&bearer_data->id);
+                       set_bitmap(&bearer_data->subparam_bitmap,
+                                       SMS_SUBPARAM_ID_MESSAGE_ID);
+                       break;
+               case SMS_SUBPARAM_ID_USER_DATA:
+                       ret = cdmasms_decode_ud(buf, subparam_len, 
&bearer_data->ud);
+                       set_bitmap(&bearer_data->subparam_bitmap,
+                                       SMS_SUBPARAM_ID_USER_DATA);
+                       break;
+               case SMS_SUBPARAM_ID_USER_RESPONSE_CODE:
+               case SMS_SUBPARAM_ID_MC_TIME_STAMP:
+               case SMS_SUBPARAM_ID_VALIDITY_PERIOD_ABSOLUTE:
+               case SMS_SUBPARAM_ID_VALIDITY_PERIOD_RELATIVE:
+               case SMS_SUBPARAM_ID_DEFERRED_DELIVERY_TIME_ABSOLUTE:
+               case SMS_SUBPARAM_ID_DEFERRED_DELIVERY_TIME_RELATIVE:
+               case SMS_SUBPARAM_ID_PRIORITY_INDICATOR:
+               case SMS_SUBPARAM_ID_PRIVACY_INDICATOR:
+               case SMS_SUBPARAM_ID_REPLY_OPTION:
+               case SMS_SUBPARAM_ID_NUMBER_OF_MESSAGES:
+               case SMS_SUBPARAM_ID_ALERT_ON_MESSAGE_DELIVERY:
+               case SMS_SUBPARAM_ID_LANGUAGE_INDICATOR:
+               case SMS_SUBPARAM_ID_CALL_BACK_NUMBER:
+               case SMS_SUBPARAM_ID_MESSAGE_DISPLAY_MODE:
+               case SMS_SUBPARAM_ID_MULTIPLE_ENCODING_USER_DATA:
+               case SMS_SUBPARAM_ID_MESSAGE_DEPOSIT_INDEX:
+               case SMS_SUBPARAM_ID_SERVICE_CATEGORY_PROGRAM_DATA:
+               case SMS_SUBPARAM_ID_SERVICE_CATEGORY_PROGRAM_RESULT:
+               case SMS_SUBPARAM_ID_MESSAGE_STATUS:
+               case SMS_SUBPARAM_ID_TP_FAILURE_CAUSE:
+               case SMS_SUBPARAM_ID_ENHANCED_VMN:
+               case SMS_SUBPARAM_ID_ENHANCED_VMN_ACK:
+                       /* TODO */
+                       /* Ignore any other unsupported/un-recognized parameter 
*/
+                       break;
+               }
+
+               if (ret == FALSE)
+                       return FALSE;
+
+               len -= subparam_len;
+               buf += subparam_len;
+       }
+
+       return TRUE;
+}
+
+static gboolean cdmasms_p2p_decode(const unsigned char *pdu, int len,
+                                                                       struct 
cdma_sms *incoming)
+{
+       gboolean ret = TRUE;
+       enum cdmasms_param_id rec_id;
+       guint8 rec_len;
+
+       if (pdu == NULL || incoming == NULL)
+               return FALSE;
+
+       while (len != 0) {
+
+               if (len <= 2)
+                       return FALSE;
+
+               rec_id = (enum cdmasms_param_id) bit_field_unpack(pdu, 0, 8);
+               pdu += 1;
+               rec_len = (guint8) bit_field_unpack(pdu, 0, 8);
+               pdu += 1;
+               len -= 2;
+
+               if (len < rec_len)
+                       return FALSE;
+
+               switch (rec_id) {
+               case SMS_PARAM_ID_TELESERVICE_IDENTIFIER:
+                       incoming->p2p_msg.teleservice_id = (enum 
cdmasms_teleservice_id)
+                                                                               
                bit_field_unpack(pdu, 0, 16);
+                       set_bitmap(&incoming->p2p_msg.param_bitmap,
+                                       SMS_PARAM_ID_TELESERVICE_IDENTIFIER);
+                       break;
+               case SMS_PARAM_ID_SERVICE_CATEGORY:
+                       break; /* TODO */
+               case SMS_PARAM_ID_ORIGINATING_ADDRESS:
+                       ret = cdmasms_decode_addr(pdu, rec_len, 
&incoming->p2p_msg.oaddr);
+                       set_bitmap(&incoming->p2p_msg.param_bitmap,
+                                       SMS_PARAM_ID_ORIGINATING_ADDRESS);
+                       break;
+               case SMS_PARAM_ID_ORIGINATING_SUBADDRESS:
+               case SMS_PARAM_ID_DESTINATION_ADDRESS:
+               case SMS_PARAM_ID_DESTINATION_SUBADDRESS:
+               case SMS_PARAM_ID_BEARER_REPLY_OPTION:
+               case SMS_PARAM_ID_CAUSE_CODE:
+                       break; /* TODO */
+               case SMS_PARAM_ID_BEARER_DATA:
+                       ret = cdmasms_decode_bearer_data(pdu, rec_len,
+                                                                               
        &incoming->p2p_msg.bearer_data);
+                       set_bitmap(&incoming->p2p_msg.param_bitmap,
+                                       SMS_PARAM_ID_BEARER_DATA);
+                       break;
+               }
+
+               if (!ret)
+                       return FALSE;
+
+               len -= rec_len;
+               pdu += rec_len;
+       }
+
+       return TRUE;
+}
+
+gboolean cdmasms_decode(const unsigned char *pdu, int len,
+                                               struct cdma_sms *incoming)
+{
+       gboolean ret = FALSE;
+
+       if ((len == 0) || (pdu == NULL) || (incoming == NULL))
+               return FALSE;
+
+       incoming->type = (enum cdmasms_tp_msg_type) bit_field_unpack(pdu, 0, 8);
+       pdu += 1;
+       len -= 1;
+
+       switch (incoming->type) {
+       case CDMASMS_P2P:
+               ret = cdmasms_p2p_decode(pdu, len, incoming);
+               break;
+       case CDMASMS_BCAST:
+       case CDMASMS_ACK:
+               /* TODO: Not supported yet */
+               ret = FALSE;
+               break;
+       }
+
+       return ret;
+}
diff --git a/src/cdma-smsutil.h b/src/cdma-smsutil.h
new file mode 100644
index 0000000..5188378
--- /dev/null
+++ b/src/cdma-smsutil.h
@@ -0,0 +1,264 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2010  Nokia 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
+ *
+ */
+
+/* 3GPP2 C.S0015-B v2.0, Table 3.4-1 */
+enum cdmasms_tp_msg_type {
+       CDMASMS_P2P =           0,
+       CDMASMS_BCAST =         1,
+       CDMASMS_ACK =           2
+};
+
+/* 3GPP2 X.S0004-550-E, Section 2.256 */
+enum cdmasms_teleservice_id {
+       TELESERVICE_CMT91 =     4096,
+       TELESERVICE_WPT =       4097,
+       TELESERVICE_WMT =       4098,
+       TELESERVICE_VMN =       4099,
+       TELESERVICE_WAP =       4100,
+       TELESERVICE_WEMT =      4101,
+       TELESERVICE_SCPT =      4102,
+       TELESERVICE_CATPT =     4103
+};
+
+/* 3GPP2 C.S0005-E v2.0 Table 2.7.1.3.2.4-2 */
+enum cdmasms_digi_number_type {
+       CDMASMS_NUM_TYPE_UNKNOWN =                                      0,
+       CDMASMS_NUM_TYPE_INTERNATIONAL_NUMBER =         1,
+       CDMASMS_NUM_TYPE_NATIONAL_NUMBER =                      2,
+       CDMASMS_NUM_TYPE_NETWORK_SPECIFIC_NUMBER =      3,
+       CDMASMS_NUM_TYPE_SUBSCRIBER_NUMBER =            4,
+       /* Reserved 5 */
+       CDMASMS_NUM_TYPE_ABBREVIATED_NUMBER =           6
+       /* Reserved 7 */
+};
+
+/* 3GPP2 C.S0015-B v2.0 Table 3.4.3.3-1 */
+enum cdmasms_data_network_number_type {
+       CDMASMS_NETWORK_NUM_TYPE_UNKNOWN =                              0,
+       CDMASMS_NETWORK_TYPE_INTERNET_PROTOCOL =                1,
+       CDMASMS_NETWORK_TYPE_INTERNET_EMAIL_ADDRESS =   2,
+       /* All Other Values Reserved */
+};
+
+/* 3GPP2 C.S0005-E v2.0 Table 2.7.1.3.2.4-3 */
+enum cdmasms_numbering_plan {
+       CDMASMS_NUMBERING_PLAN_UNKNOWN =        0,
+       CDMASMS_NUMBERING_PLAN_ISDN =           1,
+       CDMASMS_NUMBERING_PLAN_DATA =           3,
+       CDMASMS_NUMBERING_PLAN_TELEX =          4,
+       CDMASMS_NUMBERING_PLAN_PRIVATE =        9,
+       CDMASMS_NUMBERING_PLAN_RESERVED =       15
+};
+
+/* 3GPP2 C.S0015-B v2.0 Table 4.5.1-1 */
+enum cdmasms_msg_type {
+       CDMASMS_RESERVED =              0,
+       CDMASMS_DELIVER =               1,
+       CDMASMS_SUBMIT =                2,
+       CDMASMS_CANCEL =                3,
+       CDMASMS_DELIVER_ACK =   4,
+       CDMASMS_USER_ACK =              5,
+       CDMASMS_READ_ACK =              6,
+};
+
+/* C.R1001-G_v1.0 Table 9.1-1 */
+enum cdmasms_message_encoding {
+       MSG_ENCODING_OCTET =                                    0,
+       MSG_ENCODING_EXTENDED_PROTOCOL_MSG =    1,
+       MSG_ENCODING_7BIT_ASCII =                               2,
+       MSG_ENCODING_IA5 =                                              3,
+       MSG_ENCODING_UNICODE =                                  4,
+       MSG_ENCODING_SHIFT_JIS =                                5,
+       MSG_ENCODING_KOREAN =                                   6,
+       MSG_ENCODING_LATIN_HEBREW =                             7,
+       MSG_ENCODING_LATIN =                                    8,
+       MSG_ENCODING_GSM_7BIT =                                 9,
+       MSG_ENCODING_GSM_DATA_CODING =                  10
+};
+
+/* 3GPP2 C.S0015-B v2.0 Table 3.4.3-1 */
+enum cdmasms_param_id {
+       SMS_PARAM_ID_TELESERVICE_IDENTIFIER  =  0x00,
+       SMS_PARAM_ID_SERVICE_CATEGORY =                 0x01,
+       SMS_PARAM_ID_ORIGINATING_ADDRESS =              0x02,
+       SMS_PARAM_ID_ORIGINATING_SUBADDRESS =   0x03,
+       SMS_PARAM_ID_DESTINATION_ADDRESS =              0x04,
+       SMS_PARAM_ID_DESTINATION_SUBADDRESS =   0x05,
+       SMS_PARAM_ID_BEARER_REPLY_OPTION =              0x06,
+       SMS_PARAM_ID_CAUSE_CODE =                               0x07,
+       SMS_PARAM_ID_BEARER_DATA =                              0x08
+};
+
+/* 3GPP2 C.S0015-B v2.0 Table 4.5-1 */
+enum cdmasms_subparam_id {
+       SMS_SUBPARAM_ID_MESSAGE_ID =                                            
0x00,
+       SMS_SUBPARAM_ID_USER_DATA =                                             
        0x01,
+       SMS_SUBPARAM_ID_USER_RESPONSE_CODE =                            0x02,
+       SMS_SUBPARAM_ID_MC_TIME_STAMP =                                         
0x03,
+       SMS_SUBPARAM_ID_VALIDITY_PERIOD_ABSOLUTE =                      0x04,
+       SMS_SUBPARAM_ID_VALIDITY_PERIOD_RELATIVE =                      0x05,
+       SMS_SUBPARAM_ID_DEFERRED_DELIVERY_TIME_ABSOLUTE =       0x06,
+       SMS_SUBPARAM_ID_DEFERRED_DELIVERY_TIME_RELATIVE =       0x07,
+       SMS_SUBPARAM_ID_PRIORITY_INDICATOR =                            0x08,
+       SMS_SUBPARAM_ID_PRIVACY_INDICATOR =                                     
0x09,
+       SMS_SUBPARAM_ID_REPLY_OPTION =                                          
0x0A,
+       SMS_SUBPARAM_ID_NUMBER_OF_MESSAGES =                            0x0B,
+       SMS_SUBPARAM_ID_ALERT_ON_MESSAGE_DELIVERY =                     0x0C,
+       SMS_SUBPARAM_ID_LANGUAGE_INDICATOR =                            0x0D,
+       SMS_SUBPARAM_ID_CALL_BACK_NUMBER =                                      
0x0E,
+       SMS_SUBPARAM_ID_MESSAGE_DISPLAY_MODE =                          0x0F,
+       SMS_SUBPARAM_ID_MULTIPLE_ENCODING_USER_DATA =           0x10,
+       SMS_SUBPARAM_ID_MESSAGE_DEPOSIT_INDEX =                         0x11,
+       SMS_SUBPARAM_ID_SERVICE_CATEGORY_PROGRAM_DATA =         0x12,
+       SMS_SUBPARAM_ID_SERVICE_CATEGORY_PROGRAM_RESULT =       0x13,
+       SMS_SUBPARAM_ID_MESSAGE_STATUS =                                        
0x14,
+       SMS_SUBPARAM_ID_TP_FAILURE_CAUSE =                                      
0x15,
+       SMS_SUBPARAM_ID_ENHANCED_VMN =                                          
0x16,
+       SMS_SUBPARAM_ID_ENHANCED_VMN_ACK =                                      
0x17
+};
+
+/* 3GPP2 C.R1001-G Table 9.3.1-1 */
+enum cdmasms_service_category {
+       SERVICE_CAT_EMERGENCY_BROADCAST =                                       
1,
+       SERVICE_CAT_ADMINISTRATIVE =                                            
2,
+       SERVICE_CAT_MAINTENANCE =                                               
        3,
+       SERVICE_CAT_GENERALNEWSLOCAL =                                          
4,
+       SERVICE_CAT_GENERALNEWSREGIONAL =                                       
5,
+       SERVICE_CAT_GENERALNEWSNATIONAL =                                       
6,
+       SERVICE_CAT_GENERALNEWSINTERNATIONAL =                          7,
+       SERVICE_CAT_BUSINESSFINALNEWSLOCAL =                            8,
+       SERVICE_CAT_BUSINESSFINALNEWSREGIONAL =                         9,
+       SERVICE_CAT_BUSINESSFINALNEWSNATIONAL =                         10,
+       SERVICE_CAT_BUSINESSFINALNEWSINTNL =                            11,
+       SERVICE_CAT_SPORTSNEWSLOCAL =                                           
12,
+       SERVICE_CAT_SPORTSNEWSREGIONAL =                                        
13,
+       SERVICE_CAT_SPORTSNEWSNATIONAL =                                        
14,
+       SERVICE_CAT_SPORTSNEWSINTERNATIONAL =                           15,
+       SERVICE_CAT_ENTERTAINMENTNEWSLOCAL =                            16,
+       SERVICE_CAT_ENTERTAINMENTNEWSREGIONAL =                         17,
+       SERVICE_CAT_ENTERTAINMENTNEWSNATIONAL =                         18,
+       SERVICE_CAT_ENTERTAINMENTNEWSINTERNATIONAL =            19,
+       SERVICE_CAT_ENTERTAINMENTNEWSLOCALWEATHER =                     20,
+       SERVICE_CAT_AREATRAFFICREPORTS =                                        
21,
+       SERVICE_CAT_LOCALAIRTPORTFLIGHTSCHEDULES =                      22,
+       SERVICE_CAT_RESTURANTS =                                                
        23,
+       SERVICE_CAT_LODGINGS =                                                  
        24,
+       SERVICE_CAT_RETAILDIRECTORYADVERTISEMENTS =                     25,
+       SERVICE_CAT_ADVERTISEMENTS =                                            
26,
+       SERVICE_CAT_STOCKQUOTES =                                               
        27,
+       SERVICE_CAT_EMPLOYMENTOPPORTUNITIES =                           28,
+       SERVICE_CAT_MEDICALHEALTHHOSPITALS =                            29,
+       SERVICE_CAT_TECHNOLOGYNEWS =                                            
30,
+       SERVICE_CAT_MULTICATEGORY =                                             
        31,
+       SERVICE_CAT_CAPT =                                                      
                32
+};
+
+enum cdmasms_digit_mode {
+       DTMF_4_BIT =    0,
+       CODE_8_BIT =    1
+};
+
+/* 3GPP2 C.S0015-B v2.0 Section 3.4.3.3 */
+struct cdmasms_address {
+       enum cdmasms_digit_mode digit_mode;
+       guint8 number_mode;
+       guint8 number_type;
+       enum cdmasms_numbering_plan number_plan;
+       guint8 num_fields;
+       char address[256];
+};
+
+/* 3GPP2 C.S0015-B v2.0 Section 3.4.3.6 */
+struct cdmasms_cause_code {
+       guint8 reply_seq;
+       guint8 error_class;
+       guint8 cause_code;
+};
+
+/* 3GPP2 C.S0015-B v2.0 Section 4.5.1 */
+struct cdmasms_identifier {
+       enum cdmasms_msg_type msg_type;
+       guint16 msg_id;
+       gboolean header_ind;
+};
+
+/* 3GPP2 C.S0015-B v2.0 Section 4.5.2 */
+struct cdmasms_ud {
+       enum cdmasms_message_encoding msg_encoding;
+       guint8  num_fields;
+       guint8  chari[512];
+};
+
+/* 3GPP2 C.S0015-B v2.0 Section 4.5 */
+struct cdmasms_bearer_data {
+       guint32 subparam_bitmap;
+       struct cdmasms_identifier id;
+       struct cdmasms_ud ud;
+};
+
+/* 3GPP2 C.S0015-B v2.0 Table 3.4.2.1-1. */
+struct cdmasms_p2p_msg {
+       guint32 param_bitmap;
+       enum cdmasms_teleservice_id teleservice_id;
+       struct cdmasms_address oaddr;
+       struct cdmasms_bearer_data bearer_data;
+};
+
+/* 3GPP2 C.S0015-B v2.0 Table 3.4.2.2-1 */
+struct cdmasms_broadcast_msg {
+       enum cdmasms_service_category service_category;
+       struct cdmasms_bearer_data bearer_data;
+};
+
+/* 3GPP2 C.S0015-B v2.0 Table 3.4.2.3-1 */
+struct cdmasms_ack_msg {
+       struct cdmasms_address daddr;
+       struct cdmasms_cause_code cause_code;
+};
+
+/* 3GPP2 C.S0015-B v2.0 Section 3.4.1 */
+struct cdma_sms {
+       enum cdmasms_tp_msg_type type;
+       union {
+               struct cdmasms_p2p_msg p2p_msg;
+               struct cdmasms_broadcast_msg broadcast_msg;
+               struct cdmasms_ack_msg ack_msg;
+       };
+};
+
+static inline gboolean check_bitmap(guint32 bitmap, guint32 pos)
+{
+       guint32 mask = 0x1 << pos;
+       return bitmap & mask ? TRUE : FALSE;
+}
+
+static inline void set_bitmap(guint32 *bitmap, guint32 pos)
+{
+       if (bitmap == NULL)
+               return;
+
+       *bitmap = *bitmap | (1 << pos);
+}
+
+gboolean cdmasms_decode(const unsigned char *pdu, int len,
+       struct cdma_sms *out);
+char *cdmasms_decode_text(struct cdmasms_ud *ud);
+char *cdmasms_address_to_string(const struct cdmasms_address *addr);
-- 
1.7.0.4

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to