aboutsummaryrefslogtreecommitdiff
path: root/src/mm-generic-gsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mm-generic-gsm.c')
-rw-r--r--src/mm-generic-gsm.c556
1 files changed, 527 insertions, 29 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 98713b0..9cb9690 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -167,6 +167,16 @@ static void ciev_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data);
+static void cmti_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data);
+
+#define GS_HASH_TAG "get-sms"
+static GValue *simple_string_value (const char *str);
+static GValue *simple_uint_value (guint32 i);
+static GValue *simple_boolean_value (gboolean b);
+static void simple_free_gvalue (gpointer data);
+
MMModem *
mm_generic_gsm_new (const char *device,
const char *driver,
@@ -697,9 +707,10 @@ initial_pin_check (MMGenericGsm *self)
g_return_if_fail (priv->primary != NULL);
- if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error))
+ if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) {
+ mm_at_serial_port_queue_command (priv->primary, "+CMEE=1", 2, NULL, NULL);
check_pin (self, initial_pin_check_done, NULL);
- else {
+ } else {
g_warning ("%s: failed to open serial port: (%d) %s",
__func__,
error ? error->code : -1,
@@ -814,6 +825,9 @@ mm_generic_gsm_grab_port (MMGenericGsm *self,
regex = g_regex_new ("\\r\\n\\+CIEV: (\\d+),(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, ciev_received, self, NULL);
+
+ regex = g_regex_new ("\\r\\n\\+CMTI: \"(\\S+)\",(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, cmti_received, self, NULL);
g_regex_unref (regex);
if (ptype == MM_PORT_TYPE_PRIMARY) {
@@ -1293,6 +1307,29 @@ ciev_received (MMAtSerialPort *port,
}
static void
+cmti_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (user_data);
+
+ guint idx=0;
+ char *str;
+
+ str = g_match_info_fetch (info, 2);
+ if (str)
+ idx = atoi (str);
+ g_free (str);
+
+ /* todo: parse pdu to know if the sms is complete */
+ mm_modem_gsm_sms_received (MM_MODEM_GSM_SMS (self),
+ idx,
+ TRUE);
+
+ /* todo: send mm_modem_gsm_sms_completed if complete */
+}
+
+static void
cmer_cb (MMAtSerialPort *port,
GString *response,
GError *error,
@@ -1352,6 +1389,7 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self,
MMCallbackInfo *info)
{
MMGenericGsmPrivate *priv;
+ gchar *cmd = NULL;
g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_GENERIC_GSM (self));
@@ -1377,8 +1415,16 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self,
}
}
- /* Try to enable XON/XOFF flow control */
- mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL);
+ /* Try to enable flow control */
+ g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_FLOW_CONTROL_CMD, &cmd, NULL);
+ if (cmd && strlen (cmd))
+ mm_at_serial_port_queue_command (priv->primary, cmd, 3, NULL, NULL);
+ g_free (cmd);
+
+ /* Enable SMS notifications */
+ mm_at_serial_port_queue_command (priv->primary, "+CNMI=2,1,2,1,0", 3, NULL, NULL);
+ /* Set SMS storage location to ME */
+ mm_at_serial_port_queue_command (priv->primary, "+CPMS=\"ME\",\"ME\",\"ME\"", 3, NULL, NULL);
mm_at_serial_port_queue_command (priv->primary, "+CIND=?", 3, cind_cb, self);
@@ -1912,8 +1958,17 @@ pin_puk_recheck_done (MMModem *modem, GError *error, gpointer user_data)
/* If we have a saved error from sending PIN/PUK, return that to callers */
saved_error = mm_callback_info_get_data (info, SAVED_ERROR_TAG);
if (saved_error) {
- g_clear_error (&info->error);
- info->error = saved_error;
+ if (info->modem && !mm_modem_base_get_unlock_required (MM_MODEM_BASE (info->modem))) {
+ /* Original unlock failed but the modem is actually unlocked, so
+ * return success. Sometimes happens if the modem doesn't allow
+ * CPIN="xxxx" when it's already unlocked and returns an error.
+ * Do nothing.
+ */
+ } else {
+ /* Unlock failed after recheck, return original error */
+ g_clear_error (&info->error);
+ info->error = g_error_copy (saved_error);
+ }
}
mm_callback_info_schedule (info);
@@ -1938,7 +1993,8 @@ send_puk_done (MMAtSerialPort *port,
* when we're done rechecking CPIN status.
*/
mm_callback_info_set_data (info, SAVED_ERROR_TAG,
- g_error_copy (error), NULL);
+ g_error_copy (error),
+ (GDestroyNotify) g_error_free);
}
}
@@ -2001,7 +2057,8 @@ send_pin_done (MMAtSerialPort *port,
* when we're done rechecking CPIN status.
*/
mm_callback_info_set_data (info, SAVED_ERROR_TAG,
- g_error_copy (error), NULL);
+ g_error_copy (error),
+ (GDestroyNotify) g_error_free);
}
}
@@ -3735,24 +3792,6 @@ set_charset_done (MMAtSerialPort *port,
mm_at_serial_port_queue_command (port, "+CSCS?", 3, set_get_charset_done, info);
}
-static gboolean
-check_for_single_value (guint32 value)
-{
- gboolean found = FALSE;
- guint32 i;
-
- for (i = 1; i <= 32; i++) {
- if (value & 0x1) {
- if (found)
- return FALSE; /* More than one bit set */
- found = TRUE;
- }
- value >>= 1;
- }
-
- return TRUE;
-}
-
static void
set_charset (MMModem *modem,
MMModemCharset charset,
@@ -3767,7 +3806,7 @@ set_charset (MMModem *modem,
info = mm_callback_info_new (modem, callback, user_data);
- if (!(priv->charsets & charset) || !check_for_single_value (charset)) {
+ if (!(priv->charsets & charset) || !utils_check_for_single_value (charset)) {
info->error = g_error_new (MM_MODEM_ERROR,
MM_MODEM_ERROR_UNSUPPORTED_CHARSET,
"Character set 0x%X not supported",
@@ -3811,6 +3850,29 @@ mm_generic_gsm_get_charset (MMGenericGsm *self)
/*****************************************************************************/
/* MMModemGsmSms interface */
+
+#define SMS_TP_MTI_MASK 0x03
+#define SMS_TP_MTI_SMS_DELIVER 0x00
+#define SMS_TP_MTI_SMS_SUBMIT_REPORT 0x01
+#define SMS_TP_MTI_SMS_STATUS_REPORT 0x02
+
+#define SMS_TP_MMS 0x04
+#define SMS_TP_SRI 0x20
+#define SMS_TP_UDHI 0x40
+#define SMS_TP_RP 0x80
+
+#define SMS_DCS_CODING_MASK 0xec
+#define SMS_DCS_CODING_DEFAULT 0x00
+#define SMS_DCS_CODING_8BIT 0x04
+#define SMS_DCS_CODING_UCS2 0x08
+
+#define SMS_DCS_CLASS_VALID 0x10
+#define SMS_DCS_CLASS_MASK 0x03
+
+#define SMS_TIMESTAMP_LEN 7
+#define SMS_MIN_PDU_LEN (7 + SMS_TIMESTAMP_LEN)
+#define SMS_MAX_PDU_LEN 344
+
static void
sms_send_done (MMAtSerialPort *port,
GString *response,
@@ -3855,6 +3917,414 @@ sms_send (MMModemGsmSms *modem,
g_free (command);
}
+static char sms_bcd_chars[] = "0123456789*#abc\0\0";
+
+static void
+sms_semi_octets_to_bcd_string (char *dest, const guint8 *octets, int num_octets)
+{
+ int i;
+
+ for (i = 0 ; i < num_octets; i++) {
+ *dest++ = sms_bcd_chars[octets[i] & 0xf];
+ *dest++ = sms_bcd_chars[(octets[i] >> 4) & 0xf];
+ }
+ *dest++ = '\0';
+}
+
+/* len is in septets for gsm7 and in digits (semi-octets) for others */
+static char *
+sms_decode_address (const guint8 *address, int len)
+{
+ guint8 addrtype;
+ char *utf8;
+
+ addrtype = address[0];
+ address++;
+
+ if (addrtype == 0xd0) {
+ guint8 *unpacked;
+ guint32 unpacked_len;
+ unpacked = gsm_unpack (address + 1, len, 0, &unpacked_len);
+ utf8 = (char *)mm_charset_gsm_unpacked_to_utf8 (unpacked,
+ unpacked_len);
+ g_free(unpacked);
+ } else {
+ utf8 = g_malloc (len + 2); /* may need one extra for trailing 0xf */
+ sms_semi_octets_to_bcd_string (utf8, address, (len + 1) / 2);
+ }
+
+ return utf8;
+}
+
+
+static char *
+sms_decode_timestamp (const guint8 *timestamp)
+{
+ /* YYMMDDHHMMSS+ZZ */
+ char *timestr;
+ int quarters, hours;
+
+ timestr = g_malloc0 (16);
+ sms_semi_octets_to_bcd_string (timestr, timestamp, 6);
+ quarters = ((timestamp[6] & 0x7) * 10) + ((timestamp[6] >> 4) & 0xf);
+ hours = quarters / 4;
+ if (timestamp[6] & 0x08)
+ timestr[12] = '-';
+ else
+ timestr[12] = '+';
+ timestr[13] = (hours / 10) + '0';
+ timestr[14] = (hours % 10) + '0';
+ /* TODO(njw): Change timestamp rep to something that includes quarter-hours */
+ return timestr;
+}
+
+static char *
+sms_decode_text (const guint8 *text, int len, int dcs, int bit_offset)
+{
+ char *utf8;
+ guint8 coding = dcs & SMS_DCS_CODING_MASK;
+ guint8 *unpacked;
+ guint32 unpacked_len;
+
+ if (coding == SMS_DCS_CODING_DEFAULT) {
+ unpacked = gsm_unpack ((const guint8 *) text, len, bit_offset, &unpacked_len);
+ utf8 = (char *) mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len);
+ g_free (unpacked);
+ } else if (coding == SMS_DCS_CODING_UCS2)
+ utf8 = g_convert ((char *) text, len, "UTF8", "UCS-2BE", NULL, NULL, NULL);
+ else if (coding == SMS_DCS_CODING_8BIT)
+ utf8 = g_strndup ((const char *)text, len);
+ else
+ utf8 = g_strdup ("");
+
+ return utf8;
+}
+
+
+static GHashTable *
+sms_parse_pdu (const char *hexpdu)
+{
+ GHashTable *properties;
+ gsize pdu_len;
+ guint8 *pdu;
+ int smsc_addr_num_octets, variable_length_items, msg_start_offset,
+ sender_addr_num_digits, sender_addr_num_octets,
+ tp_pid_offset, tp_dcs_offset, user_data_offset, user_data_len,
+ user_data_len_offset, user_data_dcs, bit_offset;
+ char *smsc_addr, *sender_addr, *sc_timestamp, *msg_text;
+
+ /* Convert PDU from hex to binary */
+ pdu = (guint8 *) utils_hexstr2bin (hexpdu, &pdu_len);
+ if (!pdu) {
+ mm_err("Couldn't parse PDU of SMS GET response from hex");
+ return NULL;
+ }
+
+ /* SMSC, in address format, precedes the TPDU */
+ smsc_addr_num_octets = pdu[0];
+ variable_length_items = smsc_addr_num_octets;
+ if (pdu_len < variable_length_items + SMS_MIN_PDU_LEN) {
+ mm_err ("PDU too short (1): %zd vs %d", pdu_len,
+ variable_length_items + SMS_MIN_PDU_LEN);
+ g_free (pdu);
+ return NULL;
+ }
+
+ /* where in the PDU the actual SMS protocol message begins */
+ msg_start_offset = 1 + smsc_addr_num_octets;
+ sender_addr_num_digits = pdu[msg_start_offset + 1];
+ /*
+ * round the sender address length up to an even number of
+ * semi-octets, and thus an integral number of octets
+ */
+ sender_addr_num_octets = (sender_addr_num_digits + 1) >> 1;
+ variable_length_items += sender_addr_num_octets;
+ if (pdu_len < variable_length_items + SMS_MIN_PDU_LEN) {
+ mm_err ("PDU too short (2): %zd vs %d", pdu_len,
+ variable_length_items + SMS_MIN_PDU_LEN);
+ g_free (pdu);
+ return NULL;
+ }
+
+ tp_pid_offset = msg_start_offset + 3 + sender_addr_num_octets;
+ tp_dcs_offset = tp_pid_offset + 1;
+
+ user_data_len_offset = tp_dcs_offset + 1 + SMS_TIMESTAMP_LEN;
+ user_data_offset = user_data_len_offset + 1;
+ user_data_len = pdu[user_data_len_offset];
+ user_data_dcs = pdu[tp_dcs_offset];
+ if ((user_data_dcs & SMS_DCS_CODING_MASK) == SMS_DCS_CODING_DEFAULT)
+ variable_length_items += (7 * (user_data_len + 1 )) / 8;
+ else
+ variable_length_items += user_data_len;
+ if (pdu_len < variable_length_items + SMS_MIN_PDU_LEN) {
+ mm_err ("PDU too short (3): %zd vs %d", pdu_len,
+ variable_length_items + SMS_MIN_PDU_LEN);
+ g_free (pdu);
+ return NULL;
+ }
+
+ /* Only handle SMS-DELIVER */
+ if ((pdu[msg_start_offset] & SMS_TP_MTI_MASK) != SMS_TP_MTI_SMS_DELIVER) {
+ mm_err ("Unhandled message type: 0x%02x", pdu[msg_start_offset]);
+ g_free (pdu);
+ return NULL;
+ }
+
+ /* Only handle the basic protocol identifier */
+ if (pdu[tp_pid_offset] != 0) {
+ mm_err ("Unhandled protocol identifier: 0x%02x vs 0x00",
+ pdu[tp_pid_offset]);
+ g_free (pdu);
+ return NULL;
+ }
+
+ smsc_addr = sms_decode_address (&pdu[1], 2 * (pdu[0] - 1));
+ sender_addr = sms_decode_address (&pdu[msg_start_offset + 2],
+ pdu[msg_start_offset + 1]);
+ sc_timestamp = sms_decode_timestamp (&pdu[tp_dcs_offset + 1]);
+ bit_offset = 0;
+ if (pdu[msg_start_offset] & SMS_TP_UDHI) {
+ /*
+ * Skip over the user data headers to prevent it from being
+ * decoded into garbage text.
+ */
+ int udhl;
+ udhl = pdu[user_data_offset] + 1;
+ user_data_offset += udhl;
+ if ((user_data_dcs & SMS_DCS_CODING_MASK) == SMS_DCS_CODING_DEFAULT) {
+ bit_offset = 7 - (udhl * 8) % 7;
+ user_data_len -= (udhl * 8 + bit_offset) / 7;
+ } else
+ user_data_len -= udhl;
+ }
+
+ msg_text = sms_decode_text (&pdu[user_data_offset], user_data_len,
+ user_data_dcs, bit_offset);
+
+ properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+ simple_free_gvalue);
+ g_hash_table_insert (properties, "number",
+ simple_string_value (sender_addr));
+ g_hash_table_insert (properties, "text",
+ simple_string_value (msg_text));
+ g_hash_table_insert (properties, "smsc",
+ simple_string_value (smsc_addr));
+ g_hash_table_insert (properties, "timestamp",
+ simple_string_value (sc_timestamp));
+ if (user_data_dcs & SMS_DCS_CLASS_VALID)
+ g_hash_table_insert (properties, "class",
+ simple_uint_value (user_data_dcs &
+ SMS_DCS_CLASS_MASK));
+ g_hash_table_insert (properties, "completed", simple_boolean_value (TRUE));
+
+ g_free (smsc_addr);
+ g_free (sender_addr);
+ g_free (sc_timestamp);
+ g_free (msg_text);
+ g_free (pdu);
+
+ return properties;
+}
+
+static void
+sms_get_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GHashTable *properties;
+ int rv, status, tpdu_len, offset;
+ char pdu[SMS_MAX_PDU_LEN + 1];
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto out;
+ }
+
+ /* 344 == SMS_MAX_PDU_LEN */
+ rv = sscanf (response->str, "+CMGR: %d,,%d %344s %n",
+ &status, &tpdu_len, pdu, &offset);
+ if (rv != 4) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse CMGR response (parsed %d items)",
+ rv);
+ goto out;
+ }
+
+ properties = sms_parse_pdu (pdu);
+ if (!properties) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse SMS PDU");
+ goto out;
+ }
+
+ mm_callback_info_set_data (info, GS_HASH_TAG, properties,
+ (GDestroyNotify) g_hash_table_unref);
+
+out:
+ mm_callback_info_schedule (info);
+}
+
+static void
+sms_get_invoke (MMCallbackInfo *info)
+{
+ MMModemGsmSmsGetFn callback = (MMModemGsmSmsGetFn) info->callback;
+
+ callback (MM_MODEM_GSM_SMS (info->modem),
+ (GHashTable *) mm_callback_info_get_data (info, GS_HASH_TAG),
+ info->error, info->user_data);
+}
+
+static void
+sms_get (MMModemGsmSms *modem,
+ guint idx,
+ MMModemGsmSmsGetFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_new_full (MM_MODEM (modem),
+ sms_get_invoke,
+ G_CALLBACK (callback),
+ user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ command = g_strdup_printf ("+CMGR=%d\r\n", idx);
+ mm_at_serial_port_queue_command (port, command, 10, sms_get_done, info);
+}
+
+static void
+sms_delete_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error)
+ info->error = g_error_copy (error);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+sms_delete (MMModemGsmSms *modem,
+ guint idx,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ command = g_strdup_printf ("+CMGD=%d\r\n", idx);
+ mm_at_serial_port_queue_command (port, command, 10, sms_delete_done, info);
+}
+
+static void
+sms_list_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GPtrArray *results = NULL;
+ int rv, status, tpdu_len, offset;
+ char *rstr;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else {
+ results = g_ptr_array_new ();
+ rstr = response->str;
+
+ while (*rstr) {
+ GHashTable *properties;
+ int idx;
+ char pdu[SMS_MAX_PDU_LEN + 1];
+
+ rv = sscanf (rstr, "+CMGL: %d,%d,,%d %344s %n",
+ &idx, &status, &tpdu_len, pdu, &offset);
+ if (4 != rv) {
+ mm_err("Couldn't parse response to SMS LIST (%d)", rv);
+ break;
+ }
+ rstr += offset;
+
+ properties = sms_parse_pdu (pdu);
+ if (properties) {
+ g_hash_table_insert (properties, "index",
+ simple_uint_value (idx));
+ g_ptr_array_add (results, properties);
+ }
+ }
+ /*
+ * todo(njw): mm_gsm_destroy_scan_data does what we want
+ * (destroys a GPtrArray of g_hash_tables), but it should be
+ * renamed to describe that or there should be a function
+ * named for what we're doing here.
+ */
+ if (results)
+ mm_callback_info_set_data (info, "list-sms", results,
+ mm_gsm_destroy_scan_data);
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+sms_list_invoke (MMCallbackInfo *info)
+{
+ MMModemGsmSmsListFn callback = (MMModemGsmSmsListFn) info->callback;
+
+ callback (MM_MODEM_GSM_SMS (info->modem),
+ (GPtrArray *) mm_callback_info_get_data (info, "list-sms"),
+ info->error, info->user_data);
+}
+
+static void
+sms_list (MMModemGsmSms *modem,
+ MMModemGsmSmsListFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_new_full (MM_MODEM (modem),
+ sms_list_invoke,
+ G_CALLBACK (callback),
+ user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ command = g_strdup_printf ("+CMGL=4\r\n");
+ mm_at_serial_port_queue_command (port, command, 10, sms_list_done, info);
+}
+
MMAtSerialPort *
mm_generic_gsm_get_at_port (MMGenericGsm *modem,
MMPortType ptype)
@@ -4063,7 +4533,7 @@ ussd_respond (MMModemGsmUssd *modem,
mm_callback_info_schedule (info);
return;
}
-
+
ussd_send (modem, command, callback, user_data);
return;
}
@@ -4364,7 +4834,7 @@ simple_connect (MMModemSimple *simple,
g_free (data_device);
info = mm_callback_info_new (MM_MODEM (simple), callback, user_data);
- mm_callback_info_set_data (info, "simple-connect-properties",
+ mm_callback_info_set_data (info, "simple-connect-properties",
g_hash_table_ref (properties),
(GDestroyNotify) g_hash_table_unref);
@@ -4391,6 +4861,18 @@ simple_uint_value (guint32 i)
}
static GValue *
+simple_boolean_value (gboolean b)
+{
+ GValue *val;
+
+ val = g_slice_new0 (GValue);
+ g_value_init (val, G_TYPE_BOOLEAN);
+ g_value_set_boolean (val, b);
+
+ return val;
+}
+
+static GValue *
simple_string_value (const char *str)
{
GValue *val;
@@ -4728,6 +5210,9 @@ static void
modem_gsm_sms_init (MMModemGsmSms *class)
{
class->send = sms_send;
+ class->get = sms_get;
+ class->delete = sms_delete;
+ class->list = sms_list;
}
static void
@@ -4825,6 +5310,7 @@ set_property (GObject *object, guint prop_id,
case MM_GENERIC_GSM_PROP_USSD_STATE:
case MM_GENERIC_GSM_PROP_USSD_NETWORK_REQUEST:
case MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION:
+ case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -4932,6 +5418,10 @@ get_property (GObject *object, guint prop_id,
case MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION:
g_value_set_string (value, "");
break;
+ case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD:
+ /* By default, try to set XOFF/XON flow control */
+ g_value_set_string (value, "+IFC=1,1");
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -5075,5 +5565,13 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
"Optional initialization command (errors ignored)",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
+ (object_class, MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD,
+ g_param_spec_string (MM_GENERIC_GSM_FLOW_CONTROL_CMD,
+ "FlowControlCommand",
+ "Flow control configuration command (errors ignored)",
+ "+IFC=1,1",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}