const char *old, const char *new,
DBusMessage *msg, void *data);
+typedef void (*ofono_ussd_request_cb_t)(int error, int dcs,
+ const unsigned char *pdu, int len, void *data);
+
gboolean __ofono_ussd_ssc_register(struct ofono_ussd *ussd, const char *sc,
ofono_ussd_ssc_cb_t cb, void *data,
ofono_destroy_func destroy);
void __ofono_ussd_passwd_unregister(struct ofono_ussd *ussd, const char *sc);
gboolean __ofono_ussd_is_busy(struct ofono_ussd *ussd);
+int __ofono_ussd_initiate(struct ofono_ussd *ussd, int dcs,
+ const unsigned char *pdu, int len,
+ ofono_ussd_request_cb_t cb, void *user_data);
+void __ofono_ussd_initiate_cancel(struct ofono_ussd *ussd);
+
#include <ofono/netreg.h>
typedef void (*ofono_netreg_status_notify_cb_t)(int status, int lac, int ci,
USSD_STATE_RESPONSE_SENT,
};
+struct ussd_request {
+ struct ofono_ussd *ussd;
+ int dcs;
+ unsigned char *pdu;
+ int len;
+ ofono_ussd_request_cb_t cb;
+ void *user_data;
+};
+
struct ofono_ussd {
int state;
DBusMessage *pending;
const struct ofono_ussd_driver *driver;
void *driver_data;
struct ofono_atom *atom;
+ struct ussd_request *req;
};
struct ssc_entry {
if (!ussd)
return FALSE;
- if (ussd->pending || ussd->state != USSD_STATE_IDLE)
+ if (ussd->pending || ussd->state != USSD_STATE_IDLE || ussd->req)
return TRUE;
return FALSE;
"State", DBUS_TYPE_STRING, &value);
}
+static void ussd_request_finish(struct ofono_ussd *ussd, int error, int dcs,
+ const unsigned char *pdu, int len)
+{
+ struct ussd_request *req = ussd->req;
+
+ if (req && req->cb)
+ req->cb(error, dcs, pdu, len, req->user_data);
+
+ g_free(req->pdu);
+ g_free(req);
+ ussd->req = NULL;
+}
+
+static int ussd_status_to_failure_code(int status)
+{
+ switch (status) {
+ case OFONO_USSD_STATUS_TIMED_OUT:
+ return -ETIMEDOUT;
+ case OFONO_USSD_STATUS_NOT_SUPPORTED:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs,
const unsigned char *data, int data_len)
{
DBusMessageIter iter;
DBusMessageIter variant;
+ if (ussd->req &&
+ (status == OFONO_USSD_STATUS_NOTIFY ||
+ status == OFONO_USSD_STATUS_TERMINATED ||
+ status == OFONO_USSD_STATUS_TIMED_OUT ||
+ status == OFONO_USSD_STATUS_NOT_SUPPORTED)) {
+ ussd_request_finish(ussd, ussd_status_to_failure_code(status),
+ dcs, data, data_len);
+
+ ussd_change_state(ussd, USSD_STATE_IDLE);
+ return;
+ }
+
if (status == OFONO_USSD_STATUS_NOT_SUPPORTED) {
ussd_change_state(ussd, USSD_STATE_IDLE);
unsigned char buf[160];
long num_packed;
- if (ussd->pending)
- return __ofono_error_busy(msg);
-
- if (ussd->state != USSD_STATE_IDLE)
+ if (__ofono_ussd_is_busy(ussd))
return __ofono_error_busy(msg);
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
reply = dbus_message_new_method_return(ussd->cancel);
__ofono_dbus_pending_reply(&ussd->cancel, reply);
+ if (ussd->req)
+ ussd_request_finish(ussd, -1, -ECANCELED, NULL, -1);
+
ussd_change_state(ussd, USSD_STATE_IDLE);
}
{
return ussd->driver_data;
}
+
+static void ussd_request_callback(const struct ofono_error *error, void *data)
+{
+ struct ofono_ussd *ussd = data;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ ussd_request_finish(ussd, error->error, -1, NULL, -1);
+ else
+ ussd_change_state(ussd, USSD_STATE_ACTIVE);
+}
+
+int __ofono_ussd_initiate(struct ofono_ussd *ussd, int dcs,
+ const unsigned char *pdu, int len,
+ ofono_ussd_request_cb_t cb, void *user_data)
+{
+ struct ussd_request *req;
+
+ if (!ussd->driver->request)
+ return -ENOSYS;
+
+ if (__ofono_ussd_is_busy(ussd))
+ return -EBUSY;
+
+ req = g_try_new0(struct ussd_request, 1);
+ req->dcs = dcs;
+ req->pdu = g_memdup(pdu, len);
+ req->len = len;
+ req->cb = cb;
+ req->user_data = user_data;
+
+ ussd->req = req;
+
+ ussd->driver->request(ussd, dcs, pdu, len, ussd_request_callback, ussd);
+
+ return 0;
+}
+
+void __ofono_ussd_initiate_cancel(struct ofono_ussd *ussd)
+{
+ if (!ussd->req || !ussd->req->cb)
+ return;
+
+ ussd->req->cb = NULL;
+}