gsm: add preliminary USSD support (bgo #590798)

We currently convert to and from the modem's set charset and always pass
'15' as the data coding scheme. Passing the correct data coding scheme
as third argument to CUSD only upsets the network. This contradicts 3GPP
TS 23.038. Other tools like gsm-ussd handle it the same way.

Network responses that require further actions are not yet implemented.

(some fixes and cleanups by Dan Williams)
This commit is contained in:
Guido Günther
2010-11-05 14:50:50 -05:00
committed by Dan Williams
parent 2a98b2ae2d
commit 3c13d9aec8
8 changed files with 665 additions and 2 deletions

View File

@@ -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>

View File

@@ -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=$@ $<

View File

@@ -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"
/******************/

View File

@@ -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);
@@ -3668,6 +3673,180 @@ mm_generic_gsm_get_best_at_port (MMGenericGsm *self, GError **error)
return priv->secondary;
}
/*****************************************************************************/
/* 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 */
@@ -4308,6 +4487,13 @@ modem_gsm_sms_init (MMModemGsmSms *class)
class->send = sms_send;
}
static void
modem_gsm_ussd_init (MMModemGsmUssd *class)
{
class->initiate = ussd_initiate;
class->cancel = ussd_cancel;
}
static void
modem_simple_init (MMModemSimple *class)
{
@@ -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;

View File

@@ -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 {

321
src/mm-modem-gsm-ussd.c Normal file
View File

@@ -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;
}

65
src/mm-modem-gsm-ussd.h Normal file
View File

@@ -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 */

27
test/ussd.py Normal file
View File

@@ -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