---
 src/voicecall.c |  208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 207 insertions(+), 1 deletions(-)

diff --git a/src/voicecall.c b/src/voicecall.c
index b2bb41f..1b6a6c7 100644
--- a/src/voicecall.c
+++ b/src/voicecall.c
@@ -36,6 +36,7 @@
 #include "common.h"
 #include "simutil.h"
 #include "smsutil.h"
+#include "gatserver.h"
 
 #define VOICECALLS_FLAG_MULTI_RELEASE 0x1
 
@@ -56,6 +57,10 @@ struct ofono_voicecall {
        struct ofono_sim *sim;
        unsigned int sim_watch;
        unsigned int sim_state_watch;
+       struct ofono_emulator *oe;
+       struct emulator *e;
+       unsigned int emulator_watch;
+       unsigned int emulator_status_watch;
        const struct ofono_voicecall_driver *driver;
        void *driver_data;
        struct ofono_atom *atom;
@@ -857,7 +862,7 @@ static struct ofono_call *synthesize_outgoing_call(struct 
ofono_voicecall *vc,
 
        __ofono_modem_callid_hold(modem, call->id);
 
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
+       if (!msg || dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
                                DBUS_TYPE_INVALID) == FALSE)
                number = "";
        else
@@ -990,6 +995,99 @@ static DBusMessage *manager_dial(DBusConnection *conn,
        return NULL;
 }
 
+static void emulator_dial_callback(const struct ofono_error *error, void *data)
+{
+       struct ofono_voicecall *vc = data;
+       GSList *l;
+       struct ofono_call *call;
+       gboolean need_to_emit = FALSE;
+
+       if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+               DBG("Dial callback returned error: %s",
+                       telephony_error_to_str(error));
+               ofono_emulator_send_final(vc->e, G_AT_SERVER_RESULT_ERROR);
+               return;
+       }
+
+       /* Two things can happen, the call notification arrived before dial
+        * callback or dial callback was first. Handle here */
+       for (l = vc->call_list; l; l = l->next) {
+               struct voicecall *v = l->data;
+
+               if (v->call->status == CALL_STATUS_DIALING ||
+                               v->call->status == CALL_STATUS_ALERTING ||
+                               v->call->status == CALL_STATUS_ACTIVE)
+                       break;
+       }
+
+       if (!l) {
+               struct voicecall *v;
+
+               call = synthesize_outgoing_call(vc, vc->pending);
+               if (!call) {
+                       ofono_emulator_send_final(vc->e,
+                                               G_AT_SERVER_RESULT_ERROR);
+                       return;
+               }
+
+               v = voicecall_create(vc, call);
+               if (!v) {
+                       ofono_emulator_send_final(vc->e,
+                                               G_AT_SERVER_RESULT_ERROR);
+                       return;
+               }
+
+               v->detect_time = time(NULL);
+
+               DBG("Registering new call: %d", call->id);
+               voicecall_dbus_register(v);
+
+               vc->call_list = g_slist_insert_sorted(vc->call_list, v,
+                                       call_compare);
+
+               need_to_emit = TRUE;
+       }
+
+       if (need_to_emit)
+               emit_call_list_changed(vc);
+}
+
+static GAtServerResult emulator_dial(struct ofono_voicecall *vc,
+                                               const char *number)
+{
+       struct ofono_phone_number ph;
+       enum ofono_clir_option clir = OFONO_CLIR_OPTION_DEFAULT;
+
+       if (vc->pending)
+               return G_AT_SERVER_RESULT_ERROR;
+
+       if (g_slist_length(vc->call_list) >= MAX_VOICE_CALLS)
+               return G_AT_SERVER_RESULT_ERROR;
+
+       if (!valid_phone_number_format(number))
+               return G_AT_SERVER_RESULT_ERROR;
+
+       if (!vc->driver->dial)
+               return G_AT_SERVER_RESULT_ERROR;
+
+       if (voicecalls_have_incoming(vc))
+               return G_AT_SERVER_RESULT_ERROR;
+
+       /* We can't have two dialing/alerting calls, reject outright */
+       if (voicecalls_num_connecting(vc) > 0)
+               return G_AT_SERVER_RESULT_ERROR;
+
+       if (voicecalls_have_active(vc) && voicecalls_have_held(vc))
+               return G_AT_SERVER_RESULT_ERROR;
+
+       string_to_phone_number(number, &ph);
+
+       vc->driver->dial(vc, &ph, clir, OFONO_CUG_OPTION_DEFAULT,
+                               emulator_dial_callback, vc);
+
+       return G_AT_SERVER_RESULT_OK;
+}
+
 static DBusMessage *manager_transfer(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
@@ -1731,6 +1829,38 @@ check:
        set_new_ecc(vc);
 }
 
+static void dial_voicecall(struct ofono_voicecall *vc,
+                               struct ofono_emulator_dial_req *req)
+{
+       GAtServerResult res;
+       const char *dial_str = req->dial_str;
+       int len = strlen(dial_str);
+       char *dial_num;
+       char c;
+
+       DBG("%p %s", vc, dial_str);
+
+       /* Skip last comma */
+       c = dial_str[len-1];
+       /* Skip closed user group flag */
+       if (c == 'G' || c == 'g')
+               len--;
+
+       c = dial_str[len-1];
+       /* Skip caller id suppress flag */
+       if (c == 'I' || c == 'i')
+               len--;
+
+       dial_num = g_strndup(dial_str, len);
+
+       /* Voice call */
+       res = emulator_dial(vc, dial_num);
+
+       req->cb(res, req->data);
+
+       g_free(dial_num);
+}
+
 int ofono_voicecall_driver_register(const struct ofono_voicecall_driver *d)
 {
        DBG("driver: %p, name: %s", d, d->name);
@@ -1778,6 +1908,8 @@ static void voicecall_unregister(struct ofono_atom *atom)
 
        g_slist_free(vc->call_list);
 
+       vc->e = NULL;
+
        ofono_modem_remove_interface(modem, OFONO_VOICECALL_MANAGER_INTERFACE);
        g_dbus_unregister_interface(conn, path,
                                        OFONO_VOICECALL_MANAGER_INTERFACE);
@@ -1813,6 +1945,13 @@ static void voicecall_remove(struct ofono_atom *atom)
                vc->sim = NULL;
        }
 
+       if (vc->emulator_status_watch) {
+               __ofono_emulator_remove_status_watch(vc->oe,
+                                               vc->emulator_status_watch);
+               vc->emulator_status_watch = 0;
+               vc->oe = NULL;
+       }
+
        g_free(vc);
 }
 
@@ -1851,6 +1990,61 @@ struct ofono_voicecall *ofono_voicecall_create(struct 
ofono_modem *modem,
        return vc;
 }
 
+static void emulator_status_watch(struct emulator *e,
+                                       enum ofono_emulator_status status,
+                                       void *data, void *user_data)
+{
+       struct ofono_voicecall *vc = user_data;
+
+       if (e == NULL)
+               return;
+
+       switch (status) {
+       case OFONO_EMULATOR_STATUS_CREATE:
+               if (vc->e)
+                       return;
+
+               vc->e = e;
+               break;
+       case OFONO_EMULATOR_STATUS_DESTROY:
+               if (vc->e != e)
+                       return;
+
+               vc->e = NULL;
+               break;
+       case OFONO_EMULATOR_STATUS_DIAL_VOICECALL:
+               if (vc->e == NULL || data == NULL)
+                       return;
+
+               if (vc->e != e)
+                       return;
+
+               dial_voicecall(vc, data);
+               break;
+       default:
+               break;
+       }
+}
+
+static void emulator_watch(struct ofono_atom *atom,
+                                       enum ofono_atom_watch_condition cond,
+                                       void *data)
+{
+       struct ofono_voicecall *vc = data;
+       struct ofono_emulator *oe = __ofono_atom_get_data(atom);
+
+       if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+               vc->emulator_status_watch = 0;
+               vc->oe = NULL;
+               vc->e = NULL;
+               return;
+       }
+
+       vc->emulator_status_watch = __ofono_emulator_add_status_watch(oe,
+                                                       emulator_status_watch,
+                                                       vc, NULL);
+}
+
 static void sim_state_watch(void *user, enum ofono_sim_state new_state)
 {
        struct ofono_voicecall *vc = user;
@@ -1911,6 +2105,7 @@ void ofono_voicecall_register(struct ofono_voicecall *vc)
        struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
        const char *path = __ofono_atom_get_path(vc->atom);
        struct ofono_atom *sim_atom;
+       struct ofono_atom *emulator_atom;
 
        if (!g_dbus_register_interface(conn, path,
                                        OFONO_VOICECALL_MANAGER_INTERFACE,
@@ -1939,6 +2134,17 @@ void ofono_voicecall_register(struct ofono_voicecall *vc)
        if (sim_atom && __ofono_atom_get_registered(sim_atom))
                sim_watch(sim_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED, vc);
 
+       vc->emulator_watch = __ofono_modem_add_atom_watch(modem,
+                                               OFONO_ATOM_TYPE_EMULATOR,
+                                               emulator_watch, vc, NULL);
+
+       emulator_atom = __ofono_modem_find_atom(modem,
+                                               OFONO_ATOM_TYPE_EMULATOR);
+
+       if (emulator_atom && __ofono_atom_get_registered(emulator_atom))
+               emulator_watch(emulator_atom,
+                               OFONO_ATOM_WATCH_CONDITION_REGISTERED, vc);
+
        __ofono_atom_register(vc->atom, voicecall_unregister);
 }
 
-- 
1.6.3.3

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

Reply via email to