diff options
-rw-r--r-- | policy/org.freedesktop.modem-manager.policy.in | 9 | ||||
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/mm-auth-provider.h | 1 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 233 | ||||
-rw-r--r-- | src/mm-generic-gsm.h | 3 | ||||
-rw-r--r-- | src/mm-modem-gsm-ussd.c | 321 | ||||
-rw-r--r-- | src/mm-modem-gsm-ussd.h | 65 | ||||
-rw-r--r-- | test/ussd.py | 27 |
8 files changed, 665 insertions, 2 deletions
diff --git a/policy/org.freedesktop.modem-manager.policy.in b/policy/org.freedesktop.modem-manager.policy.in index 87199363..ed98f636 100644 --- a/policy/org.freedesktop.modem-manager.policy.in +++ b/policy/org.freedesktop.modem-manager.policy.in @@ -54,4 +54,13 @@ </defaults> </action> + <action id="org.freedesktop.ModemManager.USSD"> + <_description>Query and utilize network information and services</_description> + <_message>System policy prevents querying or utilizing network information and services.</_message> + <defaults> + <allow_inactive>no</allow_inactive> + <allow_active>yes</allow_active> + </defaults> + </action> + </policyconfig> diff --git a/src/Makefile.am b/src/Makefile.am index 268b29df..cadc98ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,6 +104,8 @@ modem_manager_SOURCES = \ mm-modem-gsm-network.h \ mm-modem-gsm-sms.c \ mm-modem-gsm-sms.h \ + mm-modem-gsm-ussd.c \ + mm-modem-gsm-ussd.h \ mm-modem-simple.c \ mm-modem-simple.h \ mm-options.c \ @@ -138,6 +140,9 @@ mm-modem-gsm-network-glue.h: $(top_srcdir)/introspection/mm-modem-gsm-network.xm mm-modem-gsm-sms-glue.h: $(top_srcdir)/introspection/mm-modem-gsm-sms.xml $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_gsm_sms --mode=glib-server --output=$@ $< +mm-modem-gsm-ussd-glue.h: $(top_srcdir)/introspection/mm-modem-gsm-ussd.xml + $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_gsm_ussd --mode=glib-server --output=$@ $< + BUILT_SOURCES = \ mm-manager-glue.h \ mm-modem-glue.h \ @@ -145,7 +150,8 @@ BUILT_SOURCES = \ mm-modem-cdma-glue.h \ mm-modem-gsm-card-glue.h \ mm-modem-gsm-network-glue.h \ - mm-modem-gsm-sms-glue.h + mm-modem-gsm-sms-glue.h \ + mm-modem-gsm-ussd-glue.h mm-modem-location-glue.h: $(top_srcdir)/introspection/mm-modem-location.xml $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_location --mode=glib-server --output=$@ $< diff --git a/src/mm-auth-provider.h b/src/mm-auth-provider.h index 26ff340c..32082f09 100644 --- a/src/mm-auth-provider.h +++ b/src/mm-auth-provider.h @@ -26,6 +26,7 @@ #define MM_AUTHORIZATION_DEVICE_CONTROL "org.freedesktop.ModemManager.Device.Control" #define MM_AUTHORIZATION_CONTACTS "org.freedesktop.ModemManager.Contacts" #define MM_AUTHORIZATION_SMS "org.freedesktop.ModemManager.SMS" +#define MM_AUTHORIZATION_USSD "org.freedesktop.ModemManager.USSD" #define MM_AUTHORIZATION_LOCATION "org.freedesktop.ModemManager.Location" /******************/ diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 2ffa8cfc..20e26c25 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -25,6 +25,7 @@ #include "mm-modem-gsm-card.h" #include "mm-modem-gsm-network.h" #include "mm-modem-gsm-sms.h" +#include "mm-modem-gsm-ussd.h" #include "mm-modem-simple.h" #include "mm-errors.h" #include "mm-callback-info.h" @@ -41,6 +42,7 @@ static void modem_init (MMModem *modem_class); static void modem_gsm_card_init (MMModemGsmCard *gsm_card_class); static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class); static void modem_gsm_sms_init (MMModemGsmSms *gsm_sms_class); +static void modem_gsm_ussd_init (MMModemGsmUssd *gsm_ussd_class); static void modem_simple_init (MMModemSimple *class); static void modem_location_init (MMModemLocation *class); @@ -50,6 +52,7 @@ G_DEFINE_TYPE_EXTENDED (MMGenericGsm, mm_generic_gsm, MM_TYPE_MODEM_BASE, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init) G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_SMS, modem_gsm_sms_init) G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_LOCATION, modem_location_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_USSD, modem_gsm_ussd_init) G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init)) #define MM_GENERIC_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_GENERIC_GSM, MMGenericGsmPrivate)) @@ -110,6 +113,8 @@ typedef struct { guint32 loc_caps; gboolean loc_enabled; gboolean loc_signal; + + MMModemGsmUssdState ussd_state; } MMGenericGsmPrivate; static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info); @@ -3603,7 +3608,7 @@ sms_send_done (MMAtSerialPort *port, } static void -sms_send (MMModemGsmSms *modem, +sms_send (MMModemGsmSms *modem, const char *number, const char *text, const char *smsc, @@ -3669,6 +3674,180 @@ mm_generic_gsm_get_best_at_port (MMGenericGsm *self, GError **error) } /*****************************************************************************/ +/* MMModemGsmUssd interface */ + +static void +ussd_update_state (MMGenericGsm *self, MMModemGsmUssdState new_state) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + if (new_state != priv->ussd_state) { + priv->ussd_state = new_state; + g_object_notify (G_OBJECT (self), MM_MODEM_GSM_USSD_STATE); + } +} + +static void +ussd_initiate_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMGenericGsmPrivate *priv; + gint status; + gboolean parsed = FALSE; + MMModemGsmUssdState ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE; + const char *str, *start = NULL, *end = NULL; + char *reply = NULL, *converted; + + if (error) { + info->error = g_error_copy (error); + goto done; + } + + priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + ussd_state = priv->ussd_state; + + str = mm_strip_tag (response->str, "+CUSD:"); + if (!str || !isdigit (*str)) + goto done; + + status = g_ascii_digit_value (*str); + switch (status) { + case 0: /* no further action required */ + ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE; + break; + case 1: /* Not an error but not yet implemented */ + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Further action required."); + ussd_state = MM_MODEM_GSM_USSD_STATE_USER_RESPONSE; + break; + case 2: + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "USSD terminated by network."); + ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE; + break; + case 4: + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Operiation not supported."); + ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE; + break; + default: + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Unknown USSD reply %d", status); + ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE; + break; + } + if (info->error) + goto done; + + /* look for the reply */ + if ((start = strchr (str, '"')) && (end = strrchr (str, '"')) && (start != end)) + reply = g_strndup (start + 1, end - start -1); + + if (reply) { + /* look for the reply data coding scheme */ + if (mm_options_debug ()) { + if ((start = strrchr (end, ',')) != NULL) + g_debug ("USSD data coding scheme %d", atoi (start + 1)); + } + + converted = mm_modem_charset_hex_to_utf8 (reply, priv->cur_charset); + mm_callback_info_set_result (info, converted, g_free); + parsed = TRUE; + g_free (reply); + } + +done: + if (!parsed && !info->error) { + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Could not parse USSD reply '%s'", + response->str); + } + mm_callback_info_schedule (info); + + if (info->modem) + ussd_update_state (MM_GENERIC_GSM (info->modem), ussd_state); +} + +static void +ussd_initiate (MMModemGsmUssd *modem, + const char *command, + MMModemStringFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + char *atc_command; + char *hex; + GByteArray *ussd_command = g_byte_array_new(); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + MMAtSerialPort *port; + + info = mm_callback_info_string_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; + } + + /* encode to cur_charset */ + g_warn_if_fail (mm_modem_charset_byte_array_append (ussd_command, command, FALSE, priv->cur_charset)); + /* convert to hex representation */ + hex = utils_bin2hexstr (ussd_command->data, ussd_command->len); + g_byte_array_free (ussd_command, TRUE); + atc_command = g_strdup_printf ("+CUSD=1,\"%s\",15", hex); + g_free (hex); + + mm_at_serial_port_queue_command (port, atc_command, 10, ussd_initiate_done, info); + g_free (atc_command); + + ussd_update_state (MM_GENERIC_GSM (modem), MM_MODEM_GSM_USSD_STATE_ACTIVE); +} + +static void +ussd_cancel_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); + + if (info->modem) + ussd_update_state (MM_GENERIC_GSM (info->modem), MM_MODEM_GSM_USSD_STATE_IDLE); +} + +static void +ussd_cancel (MMModemGsmUssd *modem, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + 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; + } + + mm_at_serial_port_queue_command (port, "+CUSD=2", 10, ussd_cancel_done, info); +} + +/*****************************************************************************/ /* MMModemSimple interface */ typedef enum { @@ -4309,6 +4488,13 @@ modem_gsm_sms_init (MMModemGsmSms *class) } static void +modem_gsm_ussd_init (MMModemGsmUssd *class) +{ + class->initiate = ussd_initiate; + class->cancel = ussd_cancel; +} + +static void modem_simple_init (MMModemSimple *class) { class->connect = simple_connect; @@ -4354,6 +4540,21 @@ mm_generic_gsm_init (MMGenericGsm *self) NULL, MM_MODEM_LOCATION_DBUS_INTERFACE); + mm_properties_changed_signal_register_property (G_OBJECT (self), + MM_MODEM_GSM_USSD_STATE, + "State", + MM_MODEM_GSM_USSD_DBUS_INTERFACE); + + mm_properties_changed_signal_register_property (G_OBJECT (self), + MM_MODEM_GSM_USSD_NETWORK_NOTIFICATION, + "NetworkNotification", + MM_MODEM_GSM_USSD_DBUS_INTERFACE); + + mm_properties_changed_signal_register_property (G_OBJECT (self), + MM_MODEM_GSM_USSD_NETWORK_REQUEST, + "NetworkRequest", + MM_MODEM_GSM_USSD_DBUS_INTERFACE); + g_signal_connect (self, "notify::" MM_MODEM_STATE, G_CALLBACK (modem_state_changed), NULL); } @@ -4377,6 +4578,9 @@ set_property (GObject *object, guint prop_id, case MM_GENERIC_GSM_PROP_LOC_ENABLED: case MM_GENERIC_GSM_PROP_LOC_SIGNAL: case MM_GENERIC_GSM_PROP_LOC_LOCATION: + case MM_GENERIC_GSM_PROP_USSD_STATE: + case MM_GENERIC_GSM_PROP_USSD_NETWORK_REQUEST: + case MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION: break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -4384,6 +4588,24 @@ set_property (GObject *object, guint prop_id, } } +static const char * +ussd_state_to_string (MMModemGsmUssdState ussd_state) +{ + switch (ussd_state) { + case MM_MODEM_GSM_USSD_STATE_IDLE: + return "idle"; + case MM_MODEM_GSM_USSD_STATE_ACTIVE: + return "active"; + case MM_MODEM_GSM_USSD_STATE_USER_RESPONSE: + return "user-response"; + default: + break; + } + + g_warning ("Unknown GSM USSD state %d", ussd_state); + return "unknown"; +} + static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) @@ -4457,6 +4679,15 @@ get_property (GObject *object, guint prop_id, locations = g_hash_table_new (g_direct_hash, g_direct_equal); g_value_take_boxed (value, locations); break; + case MM_GENERIC_GSM_PROP_USSD_STATE: + g_value_set_string (value, ussd_state_to_string (priv->ussd_state)); + break; + case MM_GENERIC_GSM_PROP_USSD_NETWORK_REQUEST: + g_value_set_string (value, ""); + break; + case MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION: + g_value_set_string (value, ""); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index c6836efa..57126600 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -54,6 +54,9 @@ typedef enum { MM_GENERIC_GSM_PROP_LOC_SIGNAL, MM_GENERIC_GSM_PROP_LOC_LOCATION, MM_GENERIC_GSM_PROP_SIM_IDENTIFIER, + MM_GENERIC_GSM_PROP_USSD_STATE, + MM_GENERIC_GSM_PROP_USSD_NETWORK_REQUEST, + MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION, } MMGenericGsmProp; typedef enum { diff --git a/src/mm-modem-gsm-ussd.c b/src/mm-modem-gsm-ussd.c new file mode 100644 index 00000000..def22134 --- /dev/null +++ b/src/mm-modem-gsm-ussd.c @@ -0,0 +1,321 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Copyright (C) 2010 Guido Guenther <agx@sigxcpu.org> + */ + +#include <string.h> +#include <dbus/dbus-glib.h> + +#include "mm-modem-gsm-ussd.h" +#include "mm-errors.h" +#include "mm-callback-info.h" +#include "mm-marshal.h" + +static void impl_modem_gsm_ussd_initiate(MMModemGsmUssd *modem, + const char*command, + DBusGMethodInvocation *context); + +static void impl_modem_gsm_ussd_respond(MMModemGsmUssd *modem, + const char *response, + DBusGMethodInvocation *context); + +static void impl_modem_gsm_ussd_cancel(MMModemGsmUssd *modem, + DBusGMethodInvocation *context); + +#include "mm-modem-gsm-ussd-glue.h" + + +/*****************************************************************************/ + +static void +str_call_done (MMModem *modem, const char *result, GError *error, gpointer user_data) +{ + DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context, result); +} + +static void +str_call_not_supported (MMModemGsmUssd *self, + MMModemStringFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + + info = mm_callback_info_string_new (MM_MODEM (self), callback, user_data); + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, + "Operation not supported"); + + mm_callback_info_schedule (info); +} + +static void +async_call_done (MMModem *modem, GError *error, gpointer user_data) +{ + DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); +} + +static void +async_call_not_supported (MMModemGsmUssd *self, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + + info = mm_callback_info_new (MM_MODEM (self), callback, user_data); + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, + "Operation not supported"); + mm_callback_info_schedule (info); +} + +/*****************************************************************************/ + +void +mm_modem_gsm_ussd_initiate (MMModemGsmUssd *self, + const char *command, + MMModemStringFn callback, + gpointer user_data) +{ + g_return_if_fail (MM_IS_MODEM_GSM_USSD (self)); + g_return_if_fail (command != NULL); + g_return_if_fail (callback != NULL); + + if (MM_MODEM_GSM_USSD_GET_INTERFACE (self)->initiate) + MM_MODEM_GSM_USSD_GET_INTERFACE (self)->initiate(self, command, callback, user_data); + else + str_call_not_supported (self, callback, user_data); + +} + +void +mm_modem_gsm_ussd_cancel (MMModemGsmUssd *self, + MMModemFn callback, + gpointer user_data) +{ + g_return_if_fail (MM_IS_MODEM_GSM_USSD (self)); + g_return_if_fail (callback != NULL); + + if (MM_MODEM_GSM_USSD_GET_INTERFACE (self)->cancel) + MM_MODEM_GSM_USSD_GET_INTERFACE (self)->cancel(self, callback, user_data); + else + async_call_not_supported (self, callback, user_data); + +} + +/*****************************************************************************/ + +typedef struct { + char *command; +} UssdAuthInfo; + +static void +ussd_auth_info_destroy (gpointer data) +{ + UssdAuthInfo *info = data; + + g_free (info->command); + g_free (info); +} + +static UssdAuthInfo * +ussd_auth_info_new (const char* command) +{ + UssdAuthInfo *info; + + info = g_malloc0 (sizeof (UssdAuthInfo)); + info->command = g_strdup (command); + + return info; +} + +/*****************************************************************************/ + +static void +impl_modem_gsm_ussd_respond (MMModemGsmUssd *modem, + const char *responste, + DBusGMethodInvocation *context) +{ + async_call_not_supported (modem, async_call_done, context); +} + +/*****************************************************************************/ + +static void +ussd_initiate_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmUssd *self = MM_MODEM_GSM_USSD (owner); + UssdAuthInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise initiate the USSD */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) + goto done; + + if (!info->command) { + error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Missing USSD command"); + } + +done: + if (error) { + str_call_done (MM_MODEM (self), NULL, error, context); + g_error_free (error); + } else + mm_modem_gsm_ussd_initiate (self, info->command, str_call_done, context); +} + +static void +impl_modem_gsm_ussd_initiate (MMModemGsmUssd *modem, + const char *command, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + UssdAuthInfo *info; + + info = ussd_auth_info_new (command); + + /* Make sure the caller is authorized to initiate the USSD */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_USSD, + context, + ussd_initiate_auth_cb, + info, + ussd_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +static void +ussd_cancel_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmUssd *self = MM_MODEM_GSM_USSD (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise cancel the USSD */ + mm_modem_auth_finish (MM_MODEM (self), req, &error); + + if (error) { + str_call_done (MM_MODEM (self), NULL, error, context); + g_error_free (error); + } else + mm_modem_gsm_ussd_cancel (self, async_call_done, context); +} + +static void +impl_modem_gsm_ussd_cancel (MMModemGsmUssd *modem, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + UssdAuthInfo *info; + + info = ussd_auth_info_new (NULL); + + /* Make sure the caller is authorized to cancel USSD */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_USSD, + context, + ussd_cancel_auth_cb, + info, + ussd_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +mm_modem_gsm_ussd_init (gpointer g_iface) +{ + static gboolean initialized = FALSE; + + if (initialized) + return; + + /* Properties */ + g_object_interface_install_property + (g_iface, + g_param_spec_string (MM_MODEM_GSM_USSD_STATE, + "State", + "Current state of USSD session", + NULL, + G_PARAM_READABLE)); + + g_object_interface_install_property + (g_iface, + g_param_spec_string (MM_MODEM_GSM_USSD_NETWORK_NOTIFICATION, + "NetworkNotification", + "Network initiated request, no response required", + NULL, + G_PARAM_READABLE)); + + g_object_interface_install_property + (g_iface, + g_param_spec_string (MM_MODEM_GSM_USSD_NETWORK_REQUEST, + "NetworkRequest", + "Network initiated request, reponse required", + NULL, + G_PARAM_READABLE)); + + initialized = TRUE; +} + +GType +mm_modem_gsm_ussd_get_type (void) +{ + static GType ussd_type = 0; + + if (!G_UNLIKELY (ussd_type)) { + const GTypeInfo ussd_info = { + sizeof (MMModemGsmUssd), /* class_size */ + mm_modem_gsm_ussd_init, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + ussd_type = g_type_register_static (G_TYPE_INTERFACE, + "MMModemGsmUssd", + &ussd_info, 0); + + g_type_interface_add_prerequisite (ussd_type, G_TYPE_OBJECT); + dbus_g_object_type_install_info (ussd_type, &dbus_glib_mm_modem_gsm_ussd_object_info); + + dbus_g_object_type_register_shadow_property (ussd_type, + "State", + MM_MODEM_GSM_USSD_STATE); + } + + return ussd_type; +} diff --git a/src/mm-modem-gsm-ussd.h b/src/mm-modem-gsm-ussd.h new file mode 100644 index 00000000..d0da59be --- /dev/null +++ b/src/mm-modem-gsm-ussd.h @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Copyright (C) 2010 Guido Guenther <agx@sigxcpu.org> + */ + +#ifndef MM_MODEM_GSM_USSD_H +#define MM_MODEM_GSM_USSD_H + +#include <mm-modem.h> + +typedef enum { + MM_MODEM_GSM_USSD_STATE_IDLE = 0x00000000, + MM_MODEM_GSM_USSD_STATE_ACTIVE = 0x00000001, + MM_MODEM_GSM_USSD_STATE_USER_RESPONSE = 0x00000002, +} MMModemGsmUssdState; + +#define MM_MODEM_GSM_USSD_STATE "ussd-state" +#define MM_MODEM_GSM_USSD_NETWORK_NOTIFICATION "network-notification" +#define MM_MODEM_GSM_USSD_NETWORK_REQUEST "network-request" + +#define MM_TYPE_MODEM_GSM_USSD (mm_modem_gsm_ussd_get_type ()) +#define MM_MODEM_GSM_USSD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_GSM_USSD, MMModemGsmUssd)) +#define MM_IS_MODEM_GSM_USSD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_GSM_USSD)) +#define MM_MODEM_GSM_USSD_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM_GSM_USSD, MMModemGsmUssd)) + +#define MM_MODEM_GSM_USSD_DBUS_INTERFACE "org.freedesktop.ModemManager.Modem.Gsm.Ussd" + +typedef struct _MMModemGsmUssd MMModemGsmUssd; + +struct _MMModemGsmUssd { + GTypeInterface g_iface; + + /* Methods */ + void (*initiate) (MMModemGsmUssd *modem, + const char *command, + MMModemStringFn callback, + gpointer user_data); + + void (*cancel) (MMModemGsmUssd *modem, + MMModemFn callback, + gpointer user_data); +}; + +GType mm_modem_gsm_ussd_get_type (void); + +void mm_modem_gsm_ussd_initiate (MMModemGsmUssd *self, + const char *command, + MMModemStringFn callback, + gpointer user_data); + +void mm_modem_gsm_ussd_cancel (MMModemGsmUssd *self, + MMModemFn callback, + gpointer user_data); + +#endif /* MM_MODEM_GSM_USSD_H */ diff --git a/test/ussd.py b/test/ussd.py new file mode 100644 index 00000000..332cc172 --- /dev/null +++ b/test/ussd.py @@ -0,0 +1,27 @@ +#!/usr/bin/python +# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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: +# +# Copyright (C) 2010 Guido Guenther <agx@sigxcpu.org> +# +# Usage: ./test/ussd.py /org/freedesktop/ModemManager/Modems/0 '*130#' + +import sys, dbus + +MM_DBUS_SERVICE='org.freedesktop.ModemManager' +MM_DBUS_INTERFACE_USSD='org.freedesktop.ModemManager.Modem.Gsm.Ussd' + +bus = dbus.SystemBus() +proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1]) +modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_USSD) +ret = modem.Initiate (sys.argv[2]) +print ret |