--- /dev/null
+*.o
+*~
+.deps
+.dirstamp
+aclocal.m4
+autom4te.cache/
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+dialer/dialer
+install-sh
+libtool
+ltmain.sh
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+Makefile
+Makefile.in
+missing
+stamp-h1
+data/themes/*.edj
+ofono-efl-*.tar.*
--- /dev/null
+Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
+Guilherme Iscaro <iscaro@profusion.mobi>
--- /dev/null
+TO BE DEFINED BY CUSTOMER - Intel
--- /dev/null
+ACLOCAL_AMFLAGS = -I m4
+AM_MAKEFLAGS = --no-print-directory
+AM_CFLAGS = \
+ -DPACKAGE_DATA_DIR=\"$(pkgdatadir)/\" \
+ -DPACKAGE_BIN_DIR=\"$(bindir)\" \
+ -DPACKAGE_LIB_DIR=\"$(libdir)\" \
+ @EFL_CFLAGS@
+
+MAINTAINERCLEANFILES = \
+ aclocal.m4 \
+ compile \
+ config.guess \
+ config.h.in \
+ config.sub \
+ configure \
+ depcomp \
+ install-sh \
+ ltmain.sh \
+ Makefile.in \
+ missing \
+ mkinstalldirs
+
+bin_PROGRAMS = dialer/dialer
+
+dialer_dialer_LDADD = @EFL_LIBS@
+dialer_dialer_SOURCES = \
+ dialer/main.c \
+ dialer/log.h \
+ dialer/ofono.c \
+ dialer/ofono.h \
+ dialer/rc.c \
+ dialer/rc.h \
+ dialer/gui.c \
+ dialer/gui.h \
+ dialer/keypad.c \
+ dialer/keypad.h \
+ dialer/callscreen.c \
+ dialer/callscreen.h
+
+# Themes are compiled with edje_cc given by user (cross-compile)
+EDJE_CC = @edje_cc@
+EDJE_FLAGS_VERBOSE_ =
+EDJE_FLAGS_VERBOSE_0 =
+EDJE_FLAGS_VERBOSE_1 = -v
+EDJE_FLAGS = $(EDJE_FLAGS_VERBOSE_$(V)) -id $(top_srcdir)/data/themes/images -fd $(top_srcdir)/data/fonts
+
+filesdir = $(pkgdatadir)/themes
+files_DATA = data/themes/default.edj
+
+EXTRA_DIST = data/themes/default.edc
+
+AM_V_EDJ = $(am__v_EDJ_$(V))
+am__v_EDJ_ = $(am__v_EDJ_$(AM_DEFAULT_VERBOSITY))
+am__v_EDJ_0 = @echo " EDJ " $@;
+
+data/themes/default.edj: $(top_builddir)/Makefile $(top_srcdir)/data/themes/default.edc
+ $(MKDIR_P) $(top_builddir)/data/themes
+ $(AM_V_EDJ)$(EDJE_CC) $(EDJE_FLAGS) \
+ $(top_srcdir)/data/themes/default.edc \
+ $(top_builddir)/data/themes/default.edj
+
+clean-local:
+ rm -f $(top_builddir)/data/themes/default.edj
--- /dev/null
+Connection Manager
+******************
+
+Copyright (C) 2012 Intel Corporation. All rights reserved.
+
+
+ABOUT
+=====
+
+Graphical User Interface for oFono using EFL (Enlightenment Foundation
+Libraries) to be used with Tizen platform.
+
+
+DEBUGGING
+=========
+
+To help debug, the following environment variables could be set:
+
+ EINA_LOG_LEVEL=4
+ toggles debug (level=4) of whole EFL
+
+ EINA_LOG_LEVELS=dialer:4
+ toggles debug of dialer logging domain.
+
+ EINA_LOG_ABORT=1
+ make it abort on critical errors.
+
+ EINA_LOG_ABORT_LEVEL=2
+ make it also abort on errors.
+
+ EINA_LOG_BACKTRACE=2
+ make it produce backtraces whenever a log level is reached.
--- /dev/null
+#!/bin/sh
+
+autoreconf -f -i
+
+if [ -z "$NOCONFIGURE" ]; then
+ ./configure "$@"
+fi
--- /dev/null
+AC_PREREQ([2.60])
+AC_INIT([ofono-efl], [1])
+
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+AM_CONFIG_HEADER([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AM_MAINTAINER_MODE
+
+PKG_PROG_PKG_CONFIG
+
+COMPILER_FLAGS
+
+AC_LANG_C
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_C___ATTRIBUTE__
+
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+PKG_CHECK_MODULES([EFL],
+ [
+ elementary
+ edbus
+ dbus-1
+ ])
+
+EFL_WITH_BIN([edje], [edje-cc], [edje_cc])
+
+with_max_log_level="EINA_LOG_LEVEL_DBG"
+AC_ARG_WITH(maximum-log-level,
+ [AC_HELP_STRING([--with-maximum-log-level=NUMBER],
+ [limit log level, any call to EINA_LOG() with values greater than this will be compiled out, ignoring runtime settings, but saving function calls.])],
+ [with_max_log_level="${withval}"], [:])
+AC_DEFINE_UNQUOTED(EINA_LOG_LEVEL_MAXIMUM, ${with_max_log_level}, [if set, logging is limited to this amount.])
+
+AC_CONFIG_FILES([
+Makefile
+])
+
+AC_OUTPUT
--- /dev/null
+collections {
+ group {
+ name: "elm/layout/dialer/main";
+ parts {
+ part {
+ name: "bg";
+ type: RECT;
+ mouse_events: 0;
+ description {
+ state: "default" 0.0;
+ color: 0 0 0 255;
+ }
+ }
+
+ part {
+ name: "elm.swallow.keypad";
+ type: SWALLOW;
+ description {
+ state: "default" 0.0;
+ rel2.relative: 1.0 0.9;
+ }
+ }
+
+ }
+ }
+
+ group {
+ name: "elm/layout/dialer/keypad";
+ parts {
+ part {
+ name: "elm.text.display";
+ type: TEXT;
+ mouse_events: 0;
+ scale: 1;
+ description {
+ state: "default" 0.0;
+ color: 220 220 220 255;
+ rel2 {
+ relative: 1.0 0.0;
+ offset: -1.0 100;
+ }
+ text {
+ text: "+1 (12) 3456-7890";
+ font: "Verdana";
+ size: 42;
+ size_range: 16 42;
+ fit: 1 1;
+ align: 0.5 0.5;
+ ellipsis: 1.0;
+ }
+ }
+ }
+
+ part {
+ name: "bg.buttons";
+ type: RECT;
+ mouse_events: 0;
+ description {
+ state: "default" 0.0;
+ color: 0 0 0 255;
+ rel1 {
+ relative: 0.0 1.0;
+ to_y: "elm.text.display";
+ }
+ }
+ }
+
+#define BUTTON(id, label, sub, r1, r2) \
+ part { \
+ name: "button."##id; \
+ type: RECT; \
+ mouse_events: 1; \
+ description { \
+ state: "default" 0.0; \
+ color: 96 96 96 255; \
+ rel1 { \
+ to: "bg.buttons"; \
+ relative: r1; \
+ } \
+ rel2 { \
+ to: "bg.buttons"; \
+ relative: r2; \
+ offset: -2 -2; \
+ } \
+ } \
+ description { \
+ state: "pressed" 0.0; \
+ inherit: "default" 0.0; \
+ color: 128 128 128 255; \
+ } \
+ } \
+ part { \
+ name: "label."##id; \
+ type: TEXT; \
+ effect: SHADOW; \
+ mouse_events: 0; \
+ description { \
+ state: "default" 0.0; \
+ color: 220 220 220 255; \
+ color3: 32 32 32 128; \
+ rel1.to: "button."##id; \
+ rel2 { \
+ to: "button."##id; \
+ relative: 1.0 0.8; \
+ } \
+ text { \
+ text: label; \
+ font: "Verdana:style=Bold"; \
+ size: 36; \
+ align: 0.5 0.5; \
+ } \
+ } \
+ description { \
+ state: "pressed" 0.0; \
+ inherit: "default" 0.0; \
+ color: 255 255 255 255; \
+ } \
+ } \
+ part { \
+ name: "sub."##id; \
+ type: TEXT; \
+ mouse_events: 0; \
+ description { \
+ state: "default" 0.0; \
+ color: 180 180 180 255; \
+ rel1 { \
+ to: "button."##id; \
+ relative: 0.0 0.5; \
+ offset: 0 2; \
+ } \
+ rel2.to: "button."##id; \
+ text { \
+ text: sub; \
+ font: "Verdana:style=Bold"; \
+ size: 16; \
+ align: 0.5 0.5; \
+ } \
+ } \
+ } \
+ programs { \
+ program { \
+ signal: "mouse,up,1"; \
+ source: "button."##id; \
+ action: SIGNAL_EMIT "released,"##id "keypad"; \
+ after: "show_up_"##id; \
+ } \
+ program { \
+ name: "show_up_"##id; \
+ action: STATE_SET "default" 0.0; \
+ transition: DECELERATE 0.1; \
+ target: "button."##id; \
+ target: "label."##id; \
+ target: "sub."##id; \
+ } \
+ program { \
+ signal: "mouse,down,1"; \
+ source: "button."##id; \
+ after: "show_down_"##id; \
+ action: SIGNAL_EMIT "pressed,"##id "keypad"; \
+ } \
+ program { \
+ name: "show_down_"##id; \
+ action: STATE_SET "pressed" 0.0; \
+ transition: ACCELERATE 0.3; \
+ target: "button."##id; \
+ target: "label."##id; \
+ target: "sub."##id; \
+ } \
+ program { \
+ signal: "mouse,clicked,1"; \
+ source: "button."##id; \
+ action: SIGNAL_EMIT "clicked,"##id "keypad"; \
+ } \
+ }
+
+ BUTTON("1", "1", "", 0.000 0.0, 0.333 0.2);
+ BUTTON("2", "2", "ABC", 0.333 0.0, 0.666 0.2);
+ BUTTON("3", "3", "DEF", 0.666 0.0, 1.000 0.2);
+
+ BUTTON("4", "4", "GHI", 0.000 0.2, 0.333 0.4);
+ BUTTON("5", "5", "JKL", 0.333 0.2, 0.666 0.4);
+ BUTTON("6", "6", "MNO", 0.666 0.2, 1.000 0.4);
+
+ BUTTON("7", "7", "PQRS", 0.000 0.4, 0.333 0.6);
+ BUTTON("8", "8", "TUV", 0.333 0.4, 0.666 0.6);
+ BUTTON("9", "9", "WXYZ", 0.666 0.4, 1.000 0.6);
+
+ BUTTON("star", "*", "", 0.000 0.6, 0.333 0.8);
+ BUTTON("0", "0", "+", 0.333 0.6, 0.666 0.8);
+ BUTTON("hash", "#", "", 0.666 0.6, 1.000 0.8);
+
+ /* TODO: better special buttons */
+ BUTTON("save", "Save", "", 0.000 0.8, 0.333 1.0);
+ BUTTON("call", "Call", "", 0.333 0.8, 0.666 1.0);
+ BUTTON("backspace", "<", "", 0.666 0.8, 1.000 1.0);
+#undef BUTTON
+ }
+ }
+
+ group {
+ name: "elm/layout/dialer/call";
+ parts {
+ part {
+ name: "bg";
+ type: RECT;
+ mouse_events: 0;
+ description {
+ state: "default" 0.0;
+ color: 0 0 0 255;
+ }
+ }
+
+ part {
+ name: "elm.text.name";
+ type: TEXT;
+ mouse_events: 0;
+ scale: 1;
+ description {
+ state: "default" 0.0;
+ color: 220 220 220 255;
+ rel1.offset: 15 15;
+ rel2 {
+ relative: 1.0 0.0;
+ offset: -16 70;
+ }
+ text {
+ text: "Gustavo Barbieri";
+ font: "Verdana";
+ size: 42;
+ size_range: 16 42;
+ fit: 1 1;
+ align: 0.0 0.5;
+ ellipsis: 0.0;
+ }
+ }
+ }
+
+ part {
+ name: "elm.text.status";
+ type: TEXT;
+ mouse_events: 0;
+ scale: 1;
+ description {
+ state: "default" 0.0;
+ color: 128 128 128 255;
+ rel1 {
+ relative: 0.0 1.0;
+ to: "elm.text.name";
+ }
+ rel2 {
+ to: "elm.text.name";
+ relative: 1.0 1.0;
+ offset: -1.0 30;
+ }
+ text {
+ text: "calling...";
+ font: "Verdana";
+ size: 18;
+ min: 0 1;
+ align: 0.0 1.0;
+ ellipsis: 0.0;
+ }
+ }
+ }
+
+ part {
+ name: "bg.buttons";
+ type: RECT;
+ mouse_events: 0;
+ description {
+ state: "default" 0.0;
+ color: 16 16 16 255;
+ rel1 {
+ relative: 0.0 1.0;
+ offset: 0 -100;
+ }
+ }
+ }
+ part {
+ name: "area.hangup";
+ type: RECT;
+ mouse_events: 0;
+ description {
+ state: "default" 0.0;
+ color: 0 0 0 0;
+ rel1 {
+ to: "bg.buttons";
+ relative: 0.0 0.0;
+ offset: 15 15;
+ }
+ rel2 {
+ to: "bg.buttons";
+ relative: 0.5 1.0;
+ offset: -16 -16;
+ }
+ }
+ description {
+ state: "full" 0.0;
+ inherit: "default" 0.0;
+ rel2 {
+ to: "bg.buttons";
+ relative: 1.0 1.0;
+ offset: -16 -16;
+ }
+ }
+ }
+ part {
+ name: "button.hangup";
+ type: RECT;
+ mouse_events: 1;
+ description {
+ state: "default" 0.0;
+ color: 160 32 32 255;
+ rel1.to: "area.hangup";
+ rel2.to: "area.hangup";
+ }
+ description {
+ state: "pressed" 0.0;
+ inherit: "default" 0.0;
+ color: 160 32 32 128;
+ }
+ }
+ part {
+ name: "label.hangup";
+ type: TEXT;
+ effect: SHADOW;
+ mouse_events: 0;
+ description {
+ state: "default" 0.0;
+ color: 220 220 220 255;
+ color3: 32 32 32 128;
+ rel1.to: "button.hangup";
+ rel2.to: "button.hangup";
+ text {
+ text: "Hangup";
+ font: "Verdana:style=Bold";
+ size: 36;
+ align: 0.5 0.5;
+ }
+ }
+ description {
+ state: "pressed" 0.0;
+ inherit: "default" 0.0;
+ color: 255 255 255 255;
+ }
+ }
+ programs {
+ program {
+ signal: "mouse,up,1";
+ source: "button.hangup";
+ action: SIGNAL_EMIT "released,hangup" "call";
+ after: "show_up_hangup";
+ }
+ program {
+ name: "show_up_hangup";
+ action: STATE_SET "default" 0.0;
+ transition: DECELERATE 0.1;
+ target: "button.hangup";
+ target: "label.hangup";
+ }
+ program {
+ signal: "mouse,down,1";
+ source: "button.hangup";
+ after: "show_down_hangup";
+ action: SIGNAL_EMIT "pressed,hangup" "call";
+ }
+ program {
+ name: "show_down_hangup";
+ action: STATE_SET "pressed" 0.0;
+ transition: ACCELERATE 0.3;
+ target: "button.hangup";
+ target: "label.hangup";
+ }
+ program {
+ signal: "mouse,clicked,1";
+ source: "button.hangup";
+ action: SIGNAL_EMIT "clicked,hangup" "call";
+ }
+ }
+
+
+ part {
+ name: "clipper.answer";
+ type: RECT;
+ mouse_events: 0;
+ description {
+ state: "default" 0.0;
+ }
+ description {
+ state: "hidden" 0.0;
+ color: 255 255 255 0;
+ visible: 0;
+ }
+ }
+ part {
+ name: "button.answer";
+ type: RECT;
+ mouse_events: 1;
+ clip_to: "clipper.answer";
+ description {
+ state: "default" 0.0;
+ color: 32 160 32 255;
+ rel1 {
+ to: "bg.buttons";
+ relative: 0.5 0.0;
+ offset: 15 15;
+ }
+ rel2 {
+ to: "bg.buttons";
+ relative: 1.0 1.0;
+ offset: -16 -16;
+ }
+ }
+ description {
+ state: "pressed" 0.0;
+ inherit: "default" 0.0;
+ color: 160 32 32 128;
+ }
+ }
+ part {
+ name: "label.answer";
+ type: TEXT;
+ effect: SHADOW;
+ mouse_events: 0;
+ clip_to: "clipper.answer";
+ description {
+ state: "default" 0.0;
+ color: 220 220 220 255;
+ color3: 32 32 32 128;
+ rel1.to: "button.answer";
+ rel2.to: "button.answer";
+ text {
+ text: "Answer";
+ font: "Verdana:style=Bold";
+ size: 36;
+ align: 0.5 0.5;
+ }
+ }
+ description {
+ state: "pressed" 0.0;
+ inherit: "default" 0.0;
+ color: 255 255 255 255;
+ }
+ }
+ programs {
+ program {
+ signal: "mouse,up,1";
+ source: "button.answer";
+ action: SIGNAL_EMIT "released,answer" "call";
+ after: "show_up_answer";
+ }
+ program {
+ name: "show_up_answer";
+ action: STATE_SET "default" 0.0;
+ transition: DECELERATE 0.1;
+ target: "button.answer";
+ target: "label.answer";
+ }
+ program {
+ signal: "mouse,down,1";
+ source: "button.answer";
+ after: "show_down_answer";
+ action: SIGNAL_EMIT "pressed,answer" "call";
+ }
+ program {
+ name: "show_down_answer";
+ action: STATE_SET "pressed" 0.0;
+ transition: ACCELERATE 0.3;
+ target: "button.answer";
+ target: "label.answer";
+ }
+ program {
+ signal: "mouse,clicked,1";
+ source: "button.answer";
+ action: SIGNAL_EMIT "clicked,answer" "call";
+ }
+ }
+
+ programs {
+ program {
+ signal: "hide,answer";
+ source: "call";
+ action: STATE_SET "hidden" 0.0;
+ target: "clipper.answer";
+ }
+ program {
+ signal: "hide,answer";
+ source: "call";
+ action: STATE_SET "full" 0.0;
+ target: "area.hangup";
+ }
+
+ program {
+ signal: "show,answer";
+ source: "call";
+ action: STATE_SET "default" 0.0;
+ target: "clipper.answer";
+ }
+ program {
+ signal: "show,answer";
+ source: "call";
+ action: STATE_SET "default" 0.0;
+ target: "area.hangup";
+ }
+ }
+ }
+ }
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Elementary.h>
+
+#include "log.h"
+#include "gui.h"
+#include "ofono.h"
+
+typedef struct _Callscreen
+{
+ Evas_Object *self;
+ OFono_Call *in_use;
+ Eina_List *calls;
+ struct {
+ const char *number;
+ Evas_Object *popup;
+ } disconnected;
+} Callscreen;
+
+static void _call_in_use_update(Callscreen *ctx)
+{
+ const Eina_List *n;
+ OFono_Call *c, *found = NULL;
+ OFono_Call_State found_state = OFONO_CALL_STATE_DISCONNECTED;
+ static const int state_priority[] = {
+ [OFONO_CALL_STATE_DISCONNECTED] = 0,
+ [OFONO_CALL_STATE_ACTIVE] = 6,
+ [OFONO_CALL_STATE_HELD] = 1,
+ [OFONO_CALL_STATE_DIALING] = 5,
+ [OFONO_CALL_STATE_ALERTING] = 4,
+ [OFONO_CALL_STATE_INCOMING] = 3,
+ [OFONO_CALL_STATE_WAITING] = 2
+ };
+
+ if (ctx->in_use)
+ return;
+
+ EINA_LIST_FOREACH(ctx->calls, n, c) {
+ OFono_Call_State state = ofono_call_state_get(c);
+
+ DBG("compare %p (%d) to %p (%d)", found, found_state,
+ c, state);
+ if (state_priority[state] > state_priority[found_state]) {
+ found_state = state;
+ found = c;
+ }
+ }
+
+ if (!found) {
+ DBG("No calls usable");
+ return;
+ }
+
+ DBG("found=%p, state=%d", found, found_state);
+ ctx->in_use = found;
+ gui_call_enter();
+}
+
+static void _call_disconnected_done(Callscreen *ctx)
+{
+ if (!ctx->calls)
+ gui_call_exit();
+ else
+ _call_in_use_update(ctx);
+}
+
+static void _popup_close(void *data, Evas_Object *o __UNUSED__, void *event __UNUSED__)
+{
+ Callscreen *ctx = data;
+
+ evas_object_del(ctx->disconnected.popup);
+ ctx->disconnected.popup = NULL;
+
+ eina_stringshare_replace(&ctx->disconnected.number, NULL);
+
+ _call_disconnected_done(ctx);
+}
+
+static void _popup_redial(void *data, Evas_Object *o __UNUSED__, void *event __UNUSED__)
+{
+ Callscreen *ctx = data;
+
+ ofono_dial(ctx->disconnected.number, NULL, NULL, NULL);
+ _popup_close(ctx, NULL, NULL);
+}
+
+static void _call_disconnected_show(Callscreen *ctx, OFono_Call *c,
+ const char *reason)
+{
+ Evas_Object *p, *bt;
+ const char *number, *title;
+ char msg[1024];
+
+ DBG("ctx=%p, call=%p, previous=%s, disconnected=%p (%s)",
+ ctx, ctx->in_use, ctx->disconnected.number, c, reason);
+
+ if ((ctx->in_use) && (ctx->in_use != c))
+ return;
+ ctx->in_use = NULL;
+
+ if ((strcmp(reason, "local") == 0) || (strcmp(reason, "remote") == 0)) {
+ _call_disconnected_done(ctx);
+ return;
+ }
+
+ number = ofono_call_line_id_get(c);
+ if ((!number) || (number[0] == '\0')) {
+ _call_disconnected_done(ctx);
+ return;
+ }
+
+ if (ctx->disconnected.number)
+ return;
+
+ if (strcmp(reason, "network") == 0)
+ title = "Network Disconnected!";
+ else
+ title = "Disconnected!";
+
+ snprintf(msg, sizeof(msg), "Try to redial %s", number);
+
+ eina_stringshare_replace(&ctx->disconnected.number, number);
+
+ ctx->disconnected.popup = p = elm_popup_add(ctx->self);
+ evas_object_size_hint_weight_set(p, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ elm_object_part_text_set(p, "title,text", title);
+ elm_object_text_set(p, msg);
+
+ bt = elm_button_add(p);
+ elm_object_text_set(bt, "Close");
+ elm_object_part_content_set(p, "button1", bt);
+ evas_object_smart_callback_add(bt, "clicked", _popup_close, ctx);
+
+ bt = elm_button_add(p);
+ elm_object_text_set(bt, "Redial");
+ elm_object_part_content_set(p, "button2", bt);
+ evas_object_smart_callback_add(bt, "clicked", _popup_redial, ctx);
+
+ evas_object_show(p);
+}
+
+static void _on_pressed(void *data, Evas_Object *obj __UNUSED__,
+ const char *emission, const char *source __UNUSED__)
+{
+ Callscreen *ctx = data;
+ DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->in_use, emission);
+
+ EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "pressed,"));
+ emission += strlen("pressed,");
+
+}
+
+static void _on_released(void *data, Evas_Object *obj __UNUSED__,
+ const char *emission,
+ const char *source __UNUSED__)
+{
+ Callscreen *ctx = data;
+ DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->in_use, emission);
+
+ EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "released,"));
+ emission += strlen("released,");
+
+}
+
+static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
+ const char *emission, const char *source __UNUSED__)
+{
+ Callscreen *ctx = data;
+ DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->in_use, emission);
+
+ EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
+ emission += strlen("clicked,");
+
+ if (strcmp(emission, "hangup") == 0) {
+ if (ctx->in_use)
+ ofono_call_hangup(ctx->in_use, NULL, NULL);
+ } else if (strcmp(emission, "answer") == 0) {
+ if (ctx->in_use)
+ ofono_call_answer(ctx->in_use, NULL, NULL);
+ }
+}
+
+static void _call_added(void *data, OFono_Call *c)
+{
+ Callscreen *ctx = data;
+ DBG("ctx=%p, call=%p, added=%p", ctx, ctx->in_use, c);
+ ctx->calls = eina_list_append(ctx->calls, c);
+ if ((!ctx->in_use) && (ofono_call_state_valid_check(c))) {
+ ctx->in_use = c;
+ gui_call_enter();
+ }
+}
+
+static void _call_removed(void *data, OFono_Call *c)
+{
+ Callscreen *ctx = data;
+ DBG("ctx=%p, call=%p, removed=%p", ctx, ctx->in_use, c);
+ ctx->calls = eina_list_remove(ctx->calls, c);
+ _call_disconnected_show(ctx, c, "local");
+}
+
+static void _call_changed(void *data, OFono_Call *c)
+{
+ Callscreen *ctx = data;
+ OFono_Call_State state;
+ const char *contact, *status, *signal = "hide,answer";
+
+ DBG("ctx=%p, call=%p, changed=%p", ctx, ctx->in_use, c);
+
+ _call_in_use_update(ctx);
+ if (ctx->in_use != c)
+ return;
+
+ contact = ofono_call_name_get(c);
+ if ((!contact) || (contact[0] == '\0'))
+ contact = ofono_call_line_id_get(c);
+
+ state = ofono_call_state_get(c);
+ switch (state) {
+ case OFONO_CALL_STATE_DISCONNECTED:
+ status = "Disconnected";
+ break;
+ case OFONO_CALL_STATE_ACTIVE:
+ status = "Active";
+ break;
+ case OFONO_CALL_STATE_HELD:
+ status = "Held";
+ break;
+ case OFONO_CALL_STATE_DIALING:
+ status = "Dialing...";
+ break;
+ case OFONO_CALL_STATE_ALERTING:
+ status = "Alerting...";
+ break;
+ case OFONO_CALL_STATE_INCOMING:
+ status = "Incoming...";
+ signal = "show,answer";
+ break;
+ case OFONO_CALL_STATE_WAITING:
+ status = "Waiting...";
+ break;
+ default:
+ status = "?";
+ }
+
+ elm_object_part_text_set(ctx->self, "elm.text.name", contact);
+ elm_object_part_text_set(ctx->self, "elm.text.status", status);
+ elm_object_signal_emit(ctx->self, signal, "call");
+
+ if (state == OFONO_CALL_STATE_DISCONNECTED)
+ _call_disconnected_show(ctx, c, "local");
+}
+
+static void _call_disconnected(void *data, OFono_Call *c, const char *reason)
+{
+ Callscreen *ctx = data;
+ DBG("ctx=%p, call=%p, disconnected=%p (%s)",
+ ctx, ctx->in_use, c, reason);
+
+ EINA_SAFETY_ON_NULL_RETURN(reason);
+ _call_disconnected_show(ctx, c, reason);
+}
+
+static void _on_del(void *data, Evas *e __UNUSED__,
+ Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+ Callscreen *ctx = data;
+
+ ofono_call_added_cb_set(NULL, NULL);
+ ofono_call_removed_cb_set(NULL, NULL);
+ ofono_call_changed_cb_set(NULL, NULL);
+ ofono_call_disconnected_cb_set(NULL, NULL);
+
+ eina_stringshare_del(ctx->disconnected.number);
+
+ eina_list_free(ctx->calls);
+ free(ctx);
+}
+
+Evas_Object *callscreen_add(Evas_Object *parent) {
+ Callscreen *ctx;
+ Evas_Object *obj = gui_layout_add(parent, "call");
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+
+ ctx = calloc(1, sizeof(Callscreen));
+ ctx->self = obj;
+
+ evas_object_data_set(obj, "callscreen.ctx", ctx);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
+ _on_del, ctx);
+ elm_object_signal_callback_add(obj, "pressed,*", "call",
+ _on_pressed, ctx);
+ elm_object_signal_callback_add(obj, "released,*", "call",
+ _on_released, ctx);
+ elm_object_signal_callback_add(obj, "clicked,*", "call",
+ _on_clicked, ctx);
+
+ elm_object_part_text_set(obj, "elm.text.name", "");
+ elm_object_part_text_set(obj, "elm.text.status", "");
+
+ ofono_call_added_cb_set(_call_added, ctx);
+ ofono_call_removed_cb_set(_call_removed, ctx);
+ ofono_call_changed_cb_set(_call_changed, ctx);
+ ofono_call_disconnected_cb_set(_call_disconnected, ctx);
+
+ return obj;
+}
--- /dev/null
+#ifndef _EFL_OFONO_CALLSCREEN_H__
+#define _EFL_OFONO_CALLSCREEN_H__ 1
+
+#include "ofono.h"
+
+Evas_Object *callscreen_add(Evas_Object *parent);
+void callscreen_call_add(Evas_Object *obj, OFono_Call *call);
+
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Elementary.h>
+
+#include "log.h"
+#include "gui.h"
+#include "keypad.h"
+#include "callscreen.h"
+
+static Evas_Object *win = NULL;
+static Evas_Object *kp = NULL;
+static Evas_Object *cs = NULL;
+static Evas_Object *flip = NULL;
+static char def_theme[PATH_MAX] = "";
+
+/* XXX elm_flip should just do the right thing, but it does not */
+static Eina_Bool in_call = EINA_FALSE;
+static Eina_Bool in_flip_anim = EINA_FALSE;
+
+Evas_Object *gui_layout_add(Evas_Object *parent, const char *style)
+{
+ Evas_Object *layout = elm_layout_add(parent);
+ if (!elm_layout_theme_set(layout, "layout", "dialer", style)) {
+ CRITICAL("No theme for 'elm/layout/dialer/%s' at %s",
+ style, def_theme);
+ evas_object_del(layout);
+ return NULL;
+ }
+ return layout;
+}
+
+static void _popup_close(void *data, Evas_Object *bt __UNUSED__, void *event __UNUSED__)
+{
+ Evas_Object *popup = data;
+ evas_object_del(popup);
+}
+
+void gui_simple_popup(const char *title, const char *message)
+{
+ Evas_Object *p = elm_popup_add(win);
+ Evas_Object *bt;
+
+ evas_object_size_hint_weight_set(p, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ elm_object_text_set(p, message);
+ elm_object_part_text_set(p, "title,text", title);
+
+ bt = elm_button_add(p);
+ elm_object_text_set(bt, "Close");
+ elm_object_part_content_set(p, "button1", bt);
+ evas_object_smart_callback_add(bt, "clicked", _popup_close, p);
+ evas_object_show(p);
+}
+
+void gui_activate(void)
+{
+ elm_win_raise(win);
+ elm_win_activate(win);
+ evas_object_show(win);
+}
+
+void gui_number_set(const char *number, Eina_Bool auto_dial)
+{
+ /* TODO: show keypad */
+ keypad_number_set(kp, number, auto_dial);
+}
+
+void gui_call_enter(void)
+{
+ if (in_call)
+ return;
+ in_call = EINA_TRUE;
+ if (in_flip_anim)
+ return;
+ in_flip_anim = EINA_TRUE;
+ elm_flip_go(flip, ELM_FLIP_ROTATE_Y_CENTER_AXIS);
+}
+
+void gui_call_exit(void)
+{
+ if (!in_call)
+ return;
+ in_call = EINA_FALSE;
+ if (in_flip_anim)
+ return;
+ in_flip_anim = EINA_TRUE;
+ elm_flip_go(flip, ELM_FLIP_ROTATE_Y_CENTER_AXIS);
+}
+
+static void _gui_call_sync(void *data __UNUSED__, Evas_Object *o __UNUSED__,
+ void *event_info __UNUSED__)
+{
+ Eina_Bool showing_call = !elm_flip_front_visible_get(flip);
+
+ if (showing_call ^ in_call) {
+ DBG("Flip back to sync");
+ elm_flip_go(flip, ELM_FLIP_ROTATE_Y_CENTER_AXIS);
+ }
+ in_flip_anim = EINA_FALSE;
+}
+
+Eina_Bool gui_init(void)
+{
+ Evas_Object *lay, *obj;
+
+ /* dialer should never, ever quit */
+ elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_NONE);
+
+ elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
+ elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
+ elm_app_info_set(gui_init, "ofono-efl", "themes/default.edj");
+
+ snprintf(def_theme, sizeof(def_theme), "%s/themes/default.edj",
+ elm_app_data_dir_get());
+
+ elm_theme_extension_add(NULL, def_theme);
+ elm_theme_overlay_add(NULL, def_theme);
+
+ win = elm_win_util_standard_add("ofono-dialer", "oFono Dialer");
+ EINA_SAFETY_ON_NULL_RETURN_VAL(win, EINA_FALSE);
+ elm_win_autodel_set(win, EINA_FALSE);
+
+ flip = elm_flip_add(win);
+ evas_object_size_hint_weight_set(flip,
+ EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(flip, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_win_resize_object_add(win, flip);
+ evas_object_smart_callback_add(flip, "animate,done",
+ _gui_call_sync, NULL);
+ evas_object_show(flip);
+
+ lay = gui_layout_add(win, "main");
+ EINA_SAFETY_ON_NULL_RETURN_VAL(lay, EINA_FALSE);
+ evas_object_size_hint_weight_set(lay,
+ EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(lay, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_object_part_content_set(flip, "front", lay);
+ evas_object_show(lay);
+
+ kp = obj = keypad_add(win);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
+ elm_object_part_content_set(lay, "elm.swallow.keypad", obj);
+
+ cs = obj = callscreen_add(win);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
+ evas_object_size_hint_weight_set(obj,
+ EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_object_part_content_set(flip, "back", obj);
+ evas_object_show(obj);
+
+ /* TODO: make it match better with Tizen: icon and other properties */
+ evas_object_resize(win, 480, 800);
+
+ /* do not show it yet, RC will check if it should be visible or not */
+ return EINA_TRUE;
+}
+
+void gui_shutdown(void)
+{
+}
--- /dev/null
+#ifndef _EFL_OFONO_GUI_H__
+#define _EFL_OFONO_GUI_H__ 1
+
+Evas_Object *gui_layout_add(Evas_Object *parent, const char *style);
+
+void gui_simple_popup(const char *title, const char *message);
+
+void gui_activate(void);
+void gui_number_set(const char *number, Eina_Bool auto_dial);
+
+void gui_call_enter(void);
+void gui_call_exit(void);
+
+Eina_Bool gui_init(void);
+void gui_shutdown(void);
+
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Elementary.h>
+
+#include "log.h"
+#include "gui.h"
+#include "ofono.h"
+
+/* timeout to change keys into modified, like 0 -> + */
+#define MOD_TIMEOUT (1.0)
+
+/* timeouts to repeat key while pressed */
+#define REP_TIMEOUT_INIT (0.3)
+#define REP_TIMEOUT (0.2)
+
+typedef struct _Keypad
+{
+ Evas_Object *self;
+ Eina_Strbuf *number;
+ Ecore_Timer *mod_timeout;
+ Ecore_Timer *rep_timeout;
+} Keypad;
+
+/* TODO: find a configurable way to format the number.
+ * Right now it's: 1-234-567-8901 as per
+ * http://en.wikipedia.org/wiki/Local_conventions_for_writing_telephone_numbers#North_America
+ *
+ * TODO: when contacts are integrated, look up the contact for that number
+ * and display it as elm.text.contact. Also send "contact,show/hide".
+ */
+static void _number_display(Keypad *ctx)
+{
+ size_t i, slen = eina_strbuf_length_get(ctx->number);
+ const char *src = eina_strbuf_string_get(ctx->number);
+ Eina_Strbuf *d;
+
+ if ((!src) || (slen < 1)) {
+ elm_object_part_text_set(ctx->self, "elm.text.display", "");
+ return;
+ }
+
+ if ((slen <= 4) || (slen > 12))
+ goto show_verbatim;
+
+ if ((slen == 12) && (src[0] != '+'))
+ goto show_verbatim;
+
+ for (i = 0; i < slen; i++) {
+ if ((src[i] < '0') || (src[i] > '9')) {
+ if ((src[i] == '+') && (i == 0))
+ continue;
+ goto show_verbatim;
+ }
+ }
+
+ d = eina_strbuf_new();
+ eina_strbuf_append_length(d, src, slen);
+ eina_strbuf_insert_char(d, '-', slen - 4);
+ if (slen > 7) {
+ eina_strbuf_insert_char(d, '-', slen - 7);
+ if ((slen > 10) && (src[slen - 11] != '+'))
+ eina_strbuf_insert_char(d, '-', slen - 10);
+ }
+
+
+ elm_object_part_text_set(ctx->self, "elm.text.display",
+ eina_strbuf_string_get(d));
+ eina_strbuf_free(d);
+ return;
+
+show_verbatim:
+ elm_object_part_text_set(ctx->self, "elm.text.display", src);
+}
+
+
+static void _imei_show(void)
+{
+ const char *imei = ofono_modem_serial_get();
+ gui_simple_popup("IMEI Request", imei ? imei : "No modem");
+ INF("Show IMEI: %s", imei);
+}
+
+static void _pin_reply(void *data, OFono_Error error)
+{
+ const char *title = data;
+ const char *msg;
+ switch (error) {
+ case OFONO_ERROR_NONE:
+ msg = "Success";
+ break;
+ case OFONO_ERROR_INVALID_ARGS:
+ msg = "Invalid Arguments";
+ break;
+ case OFONO_ERROR_INVALID_FORMAT:
+ msg = "Invalid Format";
+ break;
+ default:
+ msg = "Failed";
+ }
+
+ gui_simple_popup(title, msg);
+ if (error == OFONO_ERROR_NONE)
+ INF("%s", title);
+ else
+ ERR("%s", title);
+}
+
+static void _change_pin(const char *what, const char *old, const char *new)
+{
+ DBG("ask change of %s from %s to %s", what, old, new);
+ ofono_modem_change_pin(what, old, new, _pin_reply, "PIN Change");
+}
+
+static void _reset_pin(const char *what, const char *old, const char *new)
+{
+ DBG("ask reset of %s using %s to %s", what, old, new);
+ ofono_modem_reset_pin(what, old, new, _pin_reply, "PIN Reset");
+}
+
+static void _parse_pin(const char *str, char **old, char **new)
+{
+ const char *p1, *p2, *p3;
+ int len1, len2, len3;
+
+ p1 = strchr(str, '*');
+ if (!p1)
+ goto error;
+
+ p2 = strchr(p1 + 1, '*');
+ if (!p2)
+ goto error;
+
+ p3 = strchr(p2 + 1, '#');
+ if (!p3)
+ goto error;
+
+ len1 = p1 - str;
+ len2 = p2 - (p1 + 1);
+ len3 = p3 - (p2 + 1);
+
+ if ((len2 != len3) || (memcmp(p1 + 1, p2 + 1, len2) != 0)) {
+ ERR("New PIN code check failed: '%.*s' '%.*s'",
+ len2, p1 + 1,
+ len3, p2 + 1);
+ goto error;
+ }
+
+ *old = strndup(str, len1);
+ *new = strndup(p1 + 1, len2);
+
+ return;
+
+error:
+ ERR("Invalid PIN change format: %s", str);
+}
+
+static Eina_Bool _handle_if_mmi(Keypad *ctx)
+{
+ const char *str = eina_strbuf_string_get(ctx->number);
+ size_t len = eina_strbuf_length_get(ctx->number);
+
+ if (!str)
+ return EINA_FALSE;
+
+ if (len < sizeof("*#06#") - 1)
+ return EINA_FALSE;
+
+ if (str[0] != '*')
+ return EINA_FALSE;
+ if (str[len - 1] != '#')
+ return EINA_FALSE;
+
+ DBG("Possible MMI code: %s", str);
+
+ str++;
+ len -= 2;
+
+ if (strcmp(str, "#06#") == 0) {
+ _imei_show();
+ eina_strbuf_reset(ctx->number);
+ _number_display(ctx);
+ return EINA_TRUE;
+ } else if (strncmp(str, "*0", 2) == 0) {
+ const char *what = NULL, *p = str + 2;
+ char *old = NULL, *new = NULL;
+ void (*action)(const char *, const char *, const char *) = NULL;
+
+ if (*p == '4') {
+ /* MMI codes to change PIN:
+ * - **04*OLD_PIN*NEW_PIN*NEW_PIN#
+ * - **042*OLD-PIN2*NEW_PIN2*NEW_PIN2#
+ */
+ p++;
+ action = _change_pin;
+ if (*p == '*') {
+ what = "pin";
+ p++;
+ } else if (strncmp(p, "2*", 2) == 0) {
+ what = "pin2";
+ p += 2;
+ }
+
+ if (what)
+ _parse_pin(p, &old, &new);
+ } else if (*p == '5') {
+ /* MMI codes to reset PIN:
+ * - **05*PIN_UNBLOCKING_KEY*NEW_PIN*NEW_PIN#
+ * - **052*PIN2_UNBLOCKING_KEY*NEW_PIN2*NEW_PIN2#
+ */
+ p++;
+ action = _reset_pin;
+ if (*p == '*') {
+ what = "pin";
+ p++;
+ } else if (strncmp(p, "2*", 2) == 0) {
+ what = "pin2";
+ p += 2;
+ }
+
+ if (what)
+ _parse_pin(p, &old, &new);
+ }
+
+ DBG("PIN management '%s' what=%s, old=%s, new=%s",
+ str, what, old, new);
+ if (action && what && old && new) {
+ action(what, old, new);
+ eina_strbuf_reset(ctx->number);
+ _number_display(ctx);
+ }
+
+ free(old);
+ free(new);
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+static void _dial_reply(void *data, OFono_Error err,
+ OFono_Call *call __UNUSED__)
+{
+ Keypad *ctx = data;
+
+ if (err != OFONO_ERROR_NONE) {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "Could not call: %s",
+ eina_strbuf_string_get(ctx->number));
+ gui_simple_popup("Error", buf);
+ }
+}
+
+static void _dial(Keypad *ctx)
+{
+ const char *number = eina_strbuf_string_get(ctx->number);
+
+ INF("call %s", number);
+ ofono_dial(number, NULL, _dial_reply, ctx);
+}
+
+static void _ss_initiate_reply(void *data, OFono_Error err, const char *str)
+{
+ Keypad *ctx = data;
+
+ DBG("e=%d, str=%s", err, str);
+ if ((err == OFONO_ERROR_NOT_RECOGNIZED) ||
+ (err == OFONO_ERROR_INVALID_FORMAT))
+ _dial(ctx);
+ else if (err == OFONO_ERROR_OFFLINE)
+ gui_simple_popup("Offline", "System is offline!");
+ else if (err != OFONO_ERROR_NONE) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "Could not complete.<br>Error #%d",
+ err);
+ gui_simple_popup("Error", buf);
+ } else
+ gui_simple_popup(NULL, str);
+}
+
+/* Procedure as ofono/doc/mmi-codes.txt:
+ * - send number to SupplementaryServices.Initiate()
+ * - if NotRecognized is returned, then forward VoiceCallManager.Dial()
+ */
+static void _call(Keypad *ctx)
+{
+ const char *number = eina_strbuf_string_get(ctx->number);
+ int len = eina_strbuf_length_get(ctx->number);
+
+ INF("calling %s...", number);
+
+ if ((len > 0) && (number[len - 1] == '#'))
+ ofono_ss_initiate(number, _ss_initiate_reply, ctx);
+ else
+ _dial(ctx);
+}
+
+static Eina_Bool _on_mod_timeout(void *data)
+{
+ Keypad *ctx = data;
+ size_t len = eina_strbuf_length_get(ctx->number);
+
+ if (len > 0) {
+ const char *str = eina_strbuf_string_get(ctx->number);
+ if (str[len - 1] == '0') {
+ eina_strbuf_remove(ctx->number, len - 1, len);
+ eina_strbuf_append_char(ctx->number, '+');
+ _number_display(ctx);
+ }
+ }
+
+ ctx->mod_timeout = NULL;
+ return EINA_FALSE;
+}
+
+static Eina_Bool _on_rep_timeout(void *data)
+{
+ Keypad *ctx = data;
+ size_t len = eina_strbuf_length_get(ctx->number);
+
+ if (len > 0) {
+ eina_strbuf_remove(ctx->number, len - 1, len);
+ _number_display(ctx);
+ }
+
+ if (len == 1) {
+ ctx->rep_timeout = NULL;
+ return EINA_FALSE;
+ }
+
+ ecore_timer_interval_set(ctx->rep_timeout, REP_TIMEOUT);
+ return EINA_TRUE;
+}
+
+static void _on_pressed(void *data, Evas_Object *obj __UNUSED__,
+ const char *emission, const char *source __UNUSED__)
+{
+ Keypad *ctx = data;
+ DBG("ctx=%p, signal: %s", ctx, emission);
+
+ EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "pressed,"));
+ emission += strlen("pressed,");
+
+ if ((emission[0] >= '0') && (emission[0] <= '9')) {
+ eina_strbuf_append_char(ctx->number, emission[0]);
+ _number_display(ctx);
+
+ if (emission[0] == '0') {
+ if (ctx->mod_timeout)
+ ecore_timer_del(ctx->mod_timeout);
+ ctx->mod_timeout = ecore_timer_add(MOD_TIMEOUT,
+ _on_mod_timeout, ctx);
+ }
+
+ } else if (strcmp(emission, "backspace") == 0) {
+ size_t len = eina_strbuf_length_get(ctx->number);
+ if (len > 0) {
+ eina_strbuf_remove(ctx->number, len - 1, len);
+ _number_display(ctx);
+ if (len > 1) {
+ if (ctx->rep_timeout)
+ ecore_timer_del(ctx->rep_timeout);
+ ctx->rep_timeout = ecore_timer_add(
+ REP_TIMEOUT_INIT, _on_rep_timeout, ctx);
+ }
+ }
+
+ } else if (strcmp(emission, "star") == 0) {
+ eina_strbuf_append_char(ctx->number, '*');
+ _number_display(ctx);
+ } else if (strcmp(emission, "hash") == 0) {
+ eina_strbuf_append_char(ctx->number, '#');
+ _number_display(ctx);
+ }
+
+ _handle_if_mmi(ctx);
+}
+
+static void _on_released(void *data, Evas_Object *obj __UNUSED__,
+ const char *emission,
+ const char *source __UNUSED__)
+{
+ Keypad *ctx = data;
+ DBG("ctx=%p, signal: %s", ctx, emission);
+
+ EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "released,"));
+ emission += strlen("released,");
+
+ if (ctx->mod_timeout) {
+ if (emission[0] != '0')
+ ERR("Expected '0' but got '%s' instead", emission);
+ ecore_timer_del(ctx->mod_timeout);
+ ctx->mod_timeout = NULL;
+ }
+
+ if (ctx->rep_timeout) {
+ if (strcmp(emission, "backspace") != 0)
+ ERR("Expected 'backspace' but got '%s' instead",
+ emission);
+ ecore_timer_del(ctx->rep_timeout);
+ ctx->rep_timeout = NULL;
+ }
+}
+
+static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
+ const char *emission, const char *source __UNUSED__)
+{
+ Keypad *ctx = data;
+ DBG("ctx=%p, signal: %s", ctx, emission);
+
+ EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
+ emission += strlen("clicked,");
+
+ if (strcmp(emission, "call") == 0) {
+ _call(ctx);
+ } else if (strcmp(emission, "save") == 0) {
+ ERR("TODO save contact %s!",
+ eina_strbuf_string_get(ctx->number));
+ }
+}
+
+static void _on_del(void *data, Evas *e __UNUSED__,
+ Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+ Keypad *ctx = data;
+
+ if (ctx->mod_timeout)
+ ecore_timer_del(ctx->mod_timeout);
+ if (ctx->rep_timeout)
+ ecore_timer_del(ctx->rep_timeout);
+
+ eina_strbuf_free(ctx->number);
+ free(ctx);
+}
+
+Evas_Object *keypad_add(Evas_Object *parent) {
+ Keypad *ctx;
+ Evas_Object *obj = gui_layout_add(parent, "keypad");
+ EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+
+ ctx = calloc(1, sizeof(Keypad));
+ ctx->self = obj;
+ ctx->number = eina_strbuf_new();
+
+ evas_object_data_set(obj, "keypad.ctx", ctx);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
+ _on_del, ctx);
+ elm_object_signal_callback_add(obj, "pressed,*", "keypad",
+ _on_pressed, ctx);
+ elm_object_signal_callback_add(obj, "released,*", "keypad",
+ _on_released, ctx);
+ elm_object_signal_callback_add(obj, "clicked,*", "keypad",
+ _on_clicked, ctx);
+
+ elm_object_part_text_set(obj, "elm.text.display", "");
+
+ return obj;
+}
+
+void keypad_number_set(Evas_Object *obj, const char *number,
+ Eina_Bool auto_dial)
+{
+ Keypad *ctx;
+ EINA_SAFETY_ON_NULL_RETURN(obj);
+ EINA_SAFETY_ON_NULL_RETURN(number);
+
+ ctx = evas_object_data_get(obj, "keypad.ctx");
+ EINA_SAFETY_ON_NULL_RETURN(ctx);
+
+ eina_strbuf_reset(ctx->number);
+ eina_strbuf_append(ctx->number, number);
+ _number_display(ctx);
+ if (auto_dial)
+ _call(ctx);
+}
--- /dev/null
+#ifndef _EFL_OFONO_KEYPAD_H__
+#define _EFL_OFONO_KEYPAD_H__ 1
+
+Evas_Object *keypad_add(Evas_Object *parent);
+void keypad_number_set(Evas_Object *obj, const char *number, Eina_Bool do_auto);
+
+#endif
--- /dev/null
+#ifndef _EFL_OFONO_LOG_H__
+#define _EFL_OFONO_LOG_H__ 1
+
+extern int _log_domain;
+extern int _app_exit_code;
+
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_domain, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
+
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Elementary.h>
+#ifndef ELM_LIB_QUICKLAUNCH
+
+#include "log.h"
+#include "ofono.h"
+#include "gui.h"
+#include "rc.h"
+
+#include <Ecore_Getopt.h>
+
+static const Ecore_Getopt options = {
+ PACKAGE_NAME,
+ "%prog [options]",
+ PACKAGE_VERSION,
+ "(C) 2012 Intel Corporation",
+ "GPL-2" /* TODO: check license with Intel */,
+ "Phone Dialer using oFono and EFL.",
+ EINA_FALSE,
+ {ECORE_GETOPT_STORE_STR('m', "modem", "Modem object path in oFono."),
+ ECORE_GETOPT_STORE_UINT('a', "api", "oFono modem API mask."),
+ ECORE_GETOPT_VERSION('V', "version"),
+ ECORE_GETOPT_COPYRIGHT('C', "copyright"),
+ ECORE_GETOPT_LICENSE('L', "license"),
+ ECORE_GETOPT_HELP('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+int _log_domain = -1;
+int _app_exit_code = EXIT_SUCCESS;
+
+EAPI int elm_main(int argc, char **argv)
+{
+ int args;
+ char *modem_path = NULL;
+ unsigned int modem_api = 0;
+ Eina_Bool quit_option = EINA_FALSE;
+ Ecore_Getopt_Value values[] = {
+ ECORE_GETOPT_VALUE_STR(modem_path),
+ ECORE_GETOPT_VALUE_UINT(modem_api),
+ ECORE_GETOPT_VALUE_BOOL(quit_option),
+ ECORE_GETOPT_VALUE_BOOL(quit_option),
+ ECORE_GETOPT_VALUE_BOOL(quit_option),
+ ECORE_GETOPT_VALUE_BOOL(quit_option),
+ ECORE_GETOPT_VALUE_NONE
+ };
+
+ _log_domain = eina_log_domain_register("dialer", NULL);
+ if (_log_domain < 0)
+ {
+ EINA_LOG_CRIT("Could not create log domain 'dialer'.");
+ elm_shutdown();
+ return EXIT_FAILURE;
+ }
+
+ args = ecore_getopt_parse(&options, values, argc, argv);
+ if (args < 0)
+ {
+ ERR("Could not parse command line options.");
+ _app_exit_code = EXIT_FAILURE;
+ goto end;
+ }
+ if (quit_option)
+ goto end;
+
+ if (!rc_init()) {
+ CRITICAL("Could not setup remote control via DBus.");
+ _app_exit_code = EXIT_FAILURE;
+ goto end;
+ }
+
+ if (!ofono_init()) {
+ CRITICAL("Could not setup ofono");
+ _app_exit_code = EXIT_FAILURE;
+ goto end_rc;
+ }
+
+ if (modem_path) {
+ INF("User-defined modem path: %s", modem_path);
+ ofono_modem_path_wanted_set(modem_path);
+ }
+
+ if (modem_api) {
+ INF("User-defined modem API mask: %#x", modem_api);
+ ofono_modem_api_require(modem_api);
+ }
+
+ if (!gui_init()) {
+ CRITICAL("Could not setup graphical user interface");
+ _app_exit_code = EXIT_FAILURE;
+ goto end_ofono;
+ }
+
+ INF("Entering main loop");
+ elm_run();
+ INF("Quit main loop");
+
+ gui_shutdown();
+
+end_ofono:
+ ofono_shutdown();
+end_rc:
+ rc_shutdown();
+end:
+ elm_shutdown();
+
+ return _app_exit_code;
+}
+
+#endif
+ELM_MAIN()
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Elementary.h>
+
+#include "ofono.h"
+#include "log.h"
+
+typedef struct _OFono_Modem OFono_Modem;
+typedef struct _OFono_Bus_Object OFono_Bus_Object;
+
+static const char bus_name[] = "org.ofono";
+
+static E_DBus_Connection *bus_conn = NULL;
+static char *bus_id = NULL;
+static Eina_Hash *modems = NULL;
+static OFono_Modem *modem_selected = NULL;
+static const char *modem_path_wanted = NULL;
+static unsigned int modem_api_mask = (OFONO_API_SIM |
+ OFONO_API_VOICE |
+ OFONO_API_MSG |
+ OFONO_API_STK |
+ OFONO_API_CALL_FW);
+static E_DBus_Signal_Handler *sig_modem_added = NULL;
+static E_DBus_Signal_Handler *sig_modem_removed = NULL;
+static E_DBus_Signal_Handler *sig_modem_prop_changed = NULL;
+static DBusPendingCall *pc_get_modems = NULL;
+
+static void (*connected_cb)(void *) = NULL;
+static const void *connected_cb_data = NULL;
+
+static void (*disconnected_cb)(void *) = NULL;
+static const void *disconnected_cb_data = NULL;
+
+static void (*call_added_cb)(void *, OFono_Call *) = NULL;
+static const void *call_added_cb_data = NULL;
+
+static void (*call_removed_cb)(void *, OFono_Call *) = NULL;
+static const void *call_removed_cb_data = NULL;
+
+static void (*call_changed_cb)(void *, OFono_Call *) = NULL;
+static const void *call_changed_cb_data = NULL;
+
+static void (*call_disconnected_cb)(void *, OFono_Call *, const char *) = NULL;
+static const void *call_disconnected_cb_data = NULL;
+
+#define OFONO_SERVICE "org.ofono"
+
+#define OFONO_PREFIX OFONO_SERVICE "."
+#define OFONO_MODEM_IFACE "Modem"
+#define OFONO_MANAGER_IFACE "Manager"
+#define OFONO_SIM_IFACE "SimManager"
+#define OFONO_NETREG_IFACE "NetworkRegistration"
+#define OFONO_VOICE_IFACE "VoiceCallManager"
+#define OFONO_MSG_IFACE "MessageManager"
+#define OFONO_MSG_WAITING_IFACE "MessageWaiting"
+#define OFONO_SMART_MSG_IFACE "SmartMessaging"
+#define OFONO_STK_IFACE "SimToolkit"
+
+#define OFONO_CALL_FW_IFACE "CallForwarding"
+#define OFONO_CALL_VOL_IFACE "CallVolume"
+#define OFONO_CALL_METER_IFACE "CallMeter"
+#define OFONO_CALL_SET_IFACE "CallSettings"
+#define OFONO_CALL_BAR_IFACE "CallBarring"
+#define OFONO_SUPPL_SERV_IFACE "SupplementaryServices"
+#define OFONO_TXT_TEL_IFACE "TextTelephony"
+#define OFONO_CELL_BROAD_IFACE "CellBroadcast"
+#define OFONO_CONNMAN_IFACE "ConnectionManager"
+#define OFONO_PUSH_NOTIF_IFACE "PushNotification"
+#define OFONO_PHONEBOOK_IFACE "Phonebook"
+#define OFONO_ASN_IFACE "AssistedSatelliteNavigation"
+
+static const struct API_Interface_Map {
+ unsigned int bit;
+ const char *name;
+ size_t namelen;
+} api_iface_map[] = {
+#define MAP(bit, name) {bit, name, sizeof(name) - 1}
+ MAP(OFONO_API_SIM, OFONO_SIM_IFACE),
+ MAP(OFONO_API_NETREG, OFONO_NETREG_IFACE),
+ MAP(OFONO_API_VOICE, OFONO_VOICE_IFACE),
+ MAP(OFONO_API_MSG, OFONO_MSG_IFACE),
+ MAP(OFONO_API_MSG_WAITING, OFONO_MSG_WAITING_IFACE),
+ MAP(OFONO_API_SMART_MSG, OFONO_SMART_MSG_IFACE),
+ MAP(OFONO_API_STK, OFONO_STK_IFACE),
+ MAP(OFONO_API_CALL_FW, OFONO_CALL_FW_IFACE),
+ MAP(OFONO_API_CALL_VOL, OFONO_CALL_VOL_IFACE),
+ MAP(OFONO_API_CALL_METER, OFONO_CALL_METER_IFACE),
+ MAP(OFONO_API_CALL_SET, OFONO_CALL_SET_IFACE),
+ MAP(OFONO_API_CALL_BAR, OFONO_CALL_BAR_IFACE),
+ MAP(OFONO_API_SUPPL_SERV, OFONO_SUPPL_SERV_IFACE),
+ MAP(OFONO_API_TXT_TEL, OFONO_TXT_TEL_IFACE),
+ MAP(OFONO_API_CELL_BROAD, OFONO_CELL_BROAD_IFACE),
+ MAP(OFONO_API_CONNMAN, OFONO_CONNMAN_IFACE),
+ MAP(OFONO_API_PUSH_NOTIF, OFONO_PUSH_NOTIF_IFACE),
+ MAP(OFONO_API_PHONEBOOK, OFONO_PHONEBOOK_IFACE),
+ MAP(OFONO_API_ASN, OFONO_ASN_IFACE),
+#undef MAP
+ {0, NULL, 0}
+};
+
+static Eina_Bool _dbus_bool_get(DBusMessageIter *itr)
+{
+ dbus_bool_t val;
+ dbus_message_iter_get_basic(itr, &val);
+ return val;
+}
+
+static const struct Error_Map {
+ OFono_Error id;
+ const char *name;
+ size_t namelen;
+} error_map[] = {
+#define MAP(id, name) {id, name, sizeof(name) - 1}
+ MAP(OFONO_ERROR_FAILED, "Failed"),
+ MAP(OFONO_ERROR_DOES_NOT_EXIST, "DoesNotExist"),
+ MAP(OFONO_ERROR_IN_PROGRESS, "InProgress"),
+ MAP(OFONO_ERROR_IN_USE, "InUse"),
+ MAP(OFONO_ERROR_INVALID_ARGS, "InvalidArguments"),
+ MAP(OFONO_ERROR_INVALID_FORMAT, "InvalidFormat"),
+ MAP(OFONO_ERROR_ACCESS_DENIED, "AccessDenied"),
+ MAP(OFONO_ERROR_ATTACH_IN_PROGRESS, "AttachInProgress"),
+ MAP(OFONO_ERROR_INCORRECT_PASSWORD, "IncorrectPassword"),
+ MAP(OFONO_ERROR_NOT_ACTIVE, "NotActive"),
+ MAP(OFONO_ERROR_NOT_ALLOWED, "NotAllowed"),
+ MAP(OFONO_ERROR_NOT_ATTACHED, "NotAttached"),
+ MAP(OFONO_ERROR_NOT_AVAILABLE, "NotAvailable"),
+ MAP(OFONO_ERROR_NOT_FOUND, "NotFound"),
+ MAP(OFONO_ERROR_NOT_IMPLEMENTED, "NotImplemented"),
+ MAP(OFONO_ERROR_NOT_RECOGNIZED, "NotRecognized"),
+ MAP(OFONO_ERROR_NOT_REGISTERED, "NotRegistered"),
+ MAP(OFONO_ERROR_NOT_SUPPORTED, "NotSupported"),
+ MAP(OFONO_ERROR_SIM_NOT_READY, "SimNotReady"),
+ MAP(OFONO_ERROR_STK, "SimToolkit"),
+ MAP(OFONO_ERROR_TIMEDOUT, "Timedout"),
+#undef MAP
+ {0, NULL, 0}
+};
+
+static OFono_Error _ofono_error_parse(const char *name)
+{
+ size_t namelen, prefixlen = sizeof(OFONO_PREFIX) - 1;
+ const struct Error_Map *itr;
+
+ /* whenever interfaces are not there due modem being offline */
+ if (strcmp(name, "org.freedesktop.DBus.Error.UnknownMethod") == 0)
+ return OFONO_ERROR_OFFLINE;
+
+ if (strncmp(name, OFONO_PREFIX, prefixlen) != 0)
+ return OFONO_ERROR_FAILED;
+
+ name += prefixlen;
+ namelen = strlen(name);
+ for (itr = error_map; itr->name != NULL; itr++)
+ if ((itr->namelen == namelen) &&
+ (memcmp(name, itr->name, namelen) == 0))
+ return itr->id;
+
+ return OFONO_ERROR_FAILED;
+}
+
+typedef struct _OFono_Simple_Cb_Context
+{
+ OFono_Simple_Cb cb;
+ const void *data;
+} OFono_Simple_Cb_Context;
+
+static void _ofono_simple_reply(void *data, DBusMessage *msg __UNUSED__,
+ DBusError *err)
+{
+ OFono_Simple_Cb_Context *ctx = data;
+ OFono_Error e = OFONO_ERROR_NONE;
+
+ if (dbus_error_is_set(err)) {
+ DBG("%s: %s", err->name, err->message);
+ e = _ofono_error_parse(err->name);
+ }
+
+ if (ctx)
+ ctx->cb((void *)ctx->data, e);
+}
+
+typedef struct _OFono_String_Cb_Context
+{
+ OFono_String_Cb cb;
+ const void *data;
+ const char *name;
+ char *(*convert)(DBusMessage *msg);
+} OFono_String_Cb_Context;
+
+static void _ofono_string_reply(void *data, DBusMessage *msg, DBusError *err)
+{
+ OFono_String_Cb_Context *ctx = data;
+ OFono_Error e = OFONO_ERROR_NONE;
+ char *str = NULL;
+
+ if (dbus_error_is_set(err)) {
+ DBG("%s: %s", err->name, err->message);
+ e = _ofono_error_parse(err->name);
+ } else {
+ str = ctx->convert(msg);
+ if (!str)
+ e = OFONO_ERROR_NOT_SUPPORTED;
+ }
+
+ if (ctx->cb)
+ ctx->cb((void *)ctx->data, e, str);
+ else
+ DBG("%s %s", ctx->name, str);
+
+ free(str);
+}
+
+struct _OFono_Pending
+{
+ EINA_INLIST;
+ DBusPendingCall *pending;
+ E_DBus_Method_Return_Cb cb;
+ void *data;
+ void *owner;
+};
+
+struct _OFono_Bus_Object
+{
+ const char *path;
+ Eina_Inlist *dbus_pending; /* of OFono_Pending */
+ Eina_List *dbus_signals; /* of E_DBus_Signal_Handler */
+};
+
+static void _bus_object_free(OFono_Bus_Object *o)
+{
+ E_DBus_Signal_Handler *sh;
+
+ eina_stringshare_del(o->path);
+
+ while (o->dbus_pending) {
+ ofono_pending_cancel(
+ EINA_INLIST_CONTAINER_GET(o->dbus_pending,
+ OFono_Pending));
+ }
+
+ EINA_LIST_FREE(o->dbus_signals, sh)
+ e_dbus_signal_handler_del(bus_conn, sh);
+
+ free(o);
+}
+
+static void _bus_object_message_send_reply(void *data, DBusMessage *reply,
+ DBusError *err)
+{
+ OFono_Pending *p = data;
+ OFono_Bus_Object *o = p->owner;
+
+ if (p->cb)
+ p->cb(p->data, reply, err);
+
+ o->dbus_pending = eina_inlist_remove(o->dbus_pending,
+ EINA_INLIST_GET(p));
+ free(p);
+}
+
+static OFono_Pending *_bus_object_message_send(OFono_Bus_Object *o,
+ DBusMessage *msg,
+ E_DBus_Method_Return_Cb cb,
+ void *data)
+{
+ OFono_Pending *p;
+ EINA_SAFETY_ON_NULL_GOTO(o, error);
+ EINA_SAFETY_ON_NULL_GOTO(msg, error);
+
+ p = calloc(1, sizeof(OFono_Pending));
+ EINA_SAFETY_ON_NULL_GOTO(p, error);
+
+ p->owner = o;
+ p->cb = cb;
+ p->data = data;
+
+ p->pending = e_dbus_message_send(
+ bus_conn, msg, _bus_object_message_send_reply, -1, p);
+ EINA_SAFETY_ON_NULL_GOTO(p->pending, error_send);
+
+ o->dbus_pending = eina_inlist_append(o->dbus_pending,
+ EINA_INLIST_GET(p));
+ return p;
+
+error_send:
+ free(p);
+error:
+ if (cb) {
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_set_error(&err, "Failed", "call setup failed.");
+ cb(data, NULL, &err);
+ }
+ return NULL;
+}
+
+void ofono_pending_cancel(OFono_Pending *p)
+{
+ OFono_Bus_Object *o;
+
+ EINA_SAFETY_ON_NULL_RETURN(p);
+
+ o = p->owner;
+ o->dbus_pending = eina_inlist_remove(o->dbus_pending,
+ EINA_INLIST_GET(p));
+
+ if (p->cb) {
+ DBusError err;
+
+ dbus_error_init(&err);
+ dbus_set_error(&err, "Canceled",
+ "Pending method call was canceled.");
+ p->cb(p->data, NULL, &err);
+ }
+ dbus_pending_call_cancel(p->pending);
+ free(p);
+}
+
+static void _bus_object_signal_listen(OFono_Bus_Object *o, const char *iface,
+ const char *name, E_DBus_Signal_Cb cb,
+ void *data)
+{
+ E_DBus_Signal_Handler *sh = e_dbus_signal_handler_add(
+ bus_conn, bus_id, o->path, iface, name, cb, data);
+ EINA_SAFETY_ON_NULL_RETURN(sh);
+
+ o->dbus_signals = eina_list_append(o->dbus_signals, sh);
+}
+
+struct _OFono_Call
+{
+ OFono_Bus_Object base;
+ const char *line_id;
+ const char *incoming_line;
+ const char *name;
+ OFono_Call_State state;
+ Eina_Bool multiparty : 1;
+ Eina_Bool emergency : 1;
+};
+
+struct _OFono_Modem
+{
+ OFono_Bus_Object base;
+ const char *name;
+ const char *serial;
+ Eina_Hash *calls;
+ unsigned int interfaces;
+ unsigned char strength;
+ unsigned char data_strength;
+ Eina_Bool ignored : 1;
+ Eina_Bool powered : 1;
+ Eina_Bool online : 1;
+ Eina_Bool roaming : 1;
+};
+
+static OFono_Call *_call_new(const char *path)
+{
+ OFono_Call *c = calloc(1, sizeof(OFono_Call));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+
+ c->base.path = eina_stringshare_add(path);
+ EINA_SAFETY_ON_NULL_GOTO(c->base.path, error_path);
+
+ return c;
+
+error_path:
+ free(c);
+ return NULL;
+}
+
+static void _call_free(OFono_Call *c)
+{
+ DBG("c=%p %s", c, c->base.path);
+
+ if (call_removed_cb)
+ call_removed_cb((void *)call_removed_cb_data, c);
+
+ eina_stringshare_del(c->line_id);
+ eina_stringshare_del(c->incoming_line);
+ eina_stringshare_del(c->name);
+
+ _bus_object_free(&c->base);
+}
+
+static OFono_Call_State _call_state_parse(const char *str)
+{
+ if (strcmp(str, "active") == 0)
+ return OFONO_CALL_STATE_ACTIVE;
+ else if (strcmp(str, "held") == 0)
+ return OFONO_CALL_STATE_HELD;
+ else if (strcmp(str, "dialing") == 0)
+ return OFONO_CALL_STATE_DIALING;
+ else if (strcmp(str, "alerting") == 0)
+ return OFONO_CALL_STATE_ALERTING;
+ else if (strcmp(str, "incoming") == 0)
+ return OFONO_CALL_STATE_INCOMING;
+ else if (strcmp(str, "waiting") == 0)
+ return OFONO_CALL_STATE_WAITING;
+ else if (strcmp(str, "disconnected") == 0)
+ return OFONO_CALL_STATE_DISCONNECTED;
+
+ ERR("unknown call state: %s", str);
+ return OFONO_CALL_STATE_DISCONNECTED;
+}
+
+static void _call_property_update(OFono_Call *c, const char *key,
+ DBusMessageIter *value)
+{
+ if (strcmp(key, "LineIdentification") == 0) {
+ const char *str;
+ dbus_message_iter_get_basic(value, &str);
+ DBG("%s LineIdentification %s", c->base.path, str);
+ eina_stringshare_replace(&c->line_id, str);
+ } else if (strcmp(key, "IncomingLine") == 0) {
+ const char *str;
+ dbus_message_iter_get_basic(value, &str);
+ DBG("%s IncomingLine %s", c->base.path, str);
+ eina_stringshare_replace(&c->incoming_line, str);
+ } else if (strcmp(key, "State") == 0) {
+ const char *str;
+ OFono_Call_State state;
+ dbus_message_iter_get_basic(value, &str);
+ state = _call_state_parse(str);
+ DBG("%s State %s (%d)", c->base.path, str, state);
+ c->state = state;
+ } else if (strcmp(key, "Name") == 0) {
+ const char *str;
+ dbus_message_iter_get_basic(value, &str);
+ DBG("%s Name %s", c->base.path, str);
+ eina_stringshare_replace(&c->name, str);
+ } else if (strcmp(key, "Multiparty") == 0) {
+ dbus_bool_t v;
+ dbus_message_iter_get_basic(value, &v);
+ DBG("%s Multiparty %d", c->base.path, v);
+ c->multiparty = v;
+ } else if (strcmp(key, "Emergency") == 0) {
+ dbus_bool_t v;
+ dbus_message_iter_get_basic(value, &v);
+ DBG("%s Emergency %d", c->base.path, v);
+ c->emergency = v;
+ } else
+ DBG("%s %s (unused property)", c->base.path, key);
+}
+
+static void _call_property_changed(void *data, DBusMessage *msg)
+{
+ OFono_Call *c = data;
+ DBusMessageIter iter, value;
+ const char *key;
+
+ if (!msg || !dbus_message_iter_init(msg, &iter)) {
+ ERR("Could not handle message %p", msg);
+ return;
+ }
+
+ DBG("path=%s", c->base.path);
+
+ dbus_message_iter_get_basic(&iter, &key);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+ _call_property_update(c, key, &value);
+
+ if (call_changed_cb)
+ call_changed_cb((void *)call_changed_cb_data, c);
+}
+
+static void _call_disconnect_reason(void *data, DBusMessage *msg)
+{
+ OFono_Call *c = data;
+ DBusError err;
+ const char *reason;
+
+ if (!msg) {
+ ERR("No message");
+ return;
+ }
+
+ DBG("path=%s", c->base.path);
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &reason,
+ DBUS_TYPE_INVALID)) {
+ ERR("Could not get DisconnectReason arguments: %s: %s",
+ err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+
+ if (call_disconnected_cb)
+ call_disconnected_cb((void *)call_disconnected_cb_data, c,
+ reason);
+}
+
+static void _call_add(OFono_Modem *m, const char *path, DBusMessageIter *prop)
+{
+ OFono_Call *c;
+
+ DBG("path=%s", path);
+
+ c = eina_hash_find(m->calls, path);
+ if (c) {
+ DBG("Call already exists %p (%s)", c, path);
+ goto update_properties;
+ }
+
+ c = _call_new(path);
+ EINA_SAFETY_ON_NULL_RETURN(c);
+ eina_hash_add(m->calls, c->base.path, c);
+
+ _bus_object_signal_listen(&c->base,
+ OFONO_PREFIX "VoiceCall",
+ "DisconnectReason",
+ _call_disconnect_reason, c);
+ _bus_object_signal_listen(&c->base,
+ OFONO_PREFIX "VoiceCall",
+ "PropertyChanged",
+ _call_property_changed, c);
+
+ if (call_added_cb)
+ call_added_cb((void *)call_added_cb_data, c);
+
+update_properties:
+ if (!prop)
+ return;
+ for (; dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY;
+ dbus_message_iter_next(prop)) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(prop, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ _call_property_update(c, key, &value);
+ }
+
+ if (call_changed_cb)
+ call_changed_cb((void *)call_changed_cb_data, c);
+}
+
+static void _call_remove(OFono_Modem *m, const char *path)
+{
+ DBG("path=%s", path);
+ eina_hash_del_by_key(m->calls, path);
+}
+
+static void _call_added(void *data, DBusMessage *msg)
+{
+ OFono_Modem *m = data;
+ DBusMessageIter iter, properties;
+ const char *path;
+
+ if (!msg || !dbus_message_iter_init(msg, &iter)) {
+ ERR("Could not handle message %p", msg);
+ return;
+ }
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &properties);
+
+ _call_add(m, path, &properties);
+}
+
+static void _call_removed(void *data, DBusMessage *msg)
+{
+ OFono_Modem *m = data;
+ DBusError err;
+ const char *path;
+
+ if (!msg) {
+ ERR("Could not handle message %p", msg);
+ return;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
+ &path, NULL)) {
+ ERR("Could not get CallRemoved arguments: %s: %s",
+ err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+
+ _call_remove(m, path);
+}
+
+OFono_Pending *ofono_call_hangup(OFono_Call *c, OFono_Simple_Cb cb,
+ const void *data)
+{
+ OFono_Simple_Cb_Context *ctx = NULL;
+ OFono_Pending *p;
+ DBusMessage *msg;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+
+ if (cb) {
+ ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
+ EINA_SAFETY_ON_NULL_GOTO(ctx, error);
+ ctx->cb = cb;
+ ctx->data = data;
+ }
+
+ msg = dbus_message_new_method_call(
+ bus_id, c->base.path, OFONO_PREFIX "VoiceCall", "Hangup");
+ if (!msg)
+ goto error;
+
+ INF("Hangup(%s)", c->base.path);
+ p = _bus_object_message_send(&c->base, msg, _ofono_simple_reply, ctx);
+ dbus_message_unref(msg);
+ return p;
+
+error:
+ if (cb)
+ cb((void *)data, OFONO_ERROR_FAILED);
+ free(ctx);
+ return NULL;
+}
+
+OFono_Pending *ofono_call_answer(OFono_Call *c, OFono_Simple_Cb cb,
+ const void *data)
+{
+ OFono_Simple_Cb_Context *ctx = NULL;
+ OFono_Pending *p;
+ DBusMessage *msg;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+
+ if (cb) {
+ ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
+ EINA_SAFETY_ON_NULL_GOTO(ctx, error);
+ ctx->cb = cb;
+ ctx->data = data;
+ }
+
+ msg = dbus_message_new_method_call(
+ bus_id, c->base.path, OFONO_PREFIX "VoiceCall", "Answer");
+ if (!msg)
+ goto error;
+
+ INF("Answer(%s)", c->base.path);
+ p = _bus_object_message_send(&c->base, msg, _ofono_simple_reply, ctx);
+ dbus_message_unref(msg);
+ return p;
+
+error:
+ if (cb)
+ cb((void *)data, OFONO_ERROR_FAILED);
+ free(ctx);
+ return NULL;
+}
+
+OFono_Call_State ofono_call_state_get(const OFono_Call *c)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(c, OFONO_CALL_STATE_DISCONNECTED);
+ return c->state;
+}
+
+const char *ofono_call_name_get(const OFono_Call *c)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+ return c->name;
+}
+
+const char *ofono_call_line_id_get(const OFono_Call *c)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+ return c->line_id;
+}
+
+static OFono_Modem *_modem_selected_get(void)
+{
+ OFono_Modem *found_path = NULL, *found_api = NULL, *m;
+ unsigned int online = 0, powered = 0;
+ Eina_Iterator *itr;
+
+ if (modem_selected)
+ return modem_selected;
+
+ itr = eina_hash_iterator_data_new(modems);
+ EINA_ITERATOR_FOREACH(itr, m) {
+ if (m->ignored)
+ continue;
+
+ if (m->online)
+ online++;
+ if (m->powered)
+ powered++;
+
+ if ((modem_path_wanted) && (!found_path)) {
+ DBG("m=%s, wanted=%s", m->base.path, modem_path_wanted);
+ if (m->base.path == modem_path_wanted) {
+ found_path = m;
+ break;
+ }
+ }
+
+ if (!found_api) {
+ DBG("m=%#x, mask=%#x", m->interfaces, modem_api_mask);
+ if ((m->interfaces & modem_api_mask) == modem_api_mask)
+ found_api = m;
+ }
+ }
+ eina_iterator_free(itr);
+
+ INF("found_path=%s, found_api=%s, wanted_path=%s, api_mask=%#x",
+ found_path ? found_path->base.path : "",
+ found_api ? found_api->base.path: "",
+ modem_path_wanted ? modem_path_wanted : "",
+ modem_api_mask);
+
+ if (!powered)
+ ERR("No modems powered! Run connman or test/enable-modem");
+ if (!online)
+ WRN("No modems online! Run connman or test/online-modem");
+
+ modem_selected = found_path ? found_path : found_api;
+ return modem_selected;
+}
+
+static void _ofono_calls_get_reply(void *data, DBusMessage *msg,
+ DBusError *err)
+{
+ OFono_Modem *m = data;
+ DBusMessageIter array, dict;
+
+ if (!msg) {
+ if (err)
+ ERR("%s: %s", err->name, err->message);
+ else
+ ERR("No message");
+ return;
+ }
+
+ eina_hash_free_buckets(m->calls);
+
+ if (!dbus_message_iter_init(msg, &array)) {
+ ERR("Could not get calls");
+ return;
+ }
+
+ dbus_message_iter_recurse(&array, &dict);
+ for (; dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT;
+ dbus_message_iter_next(&dict)) {
+ DBusMessageIter value, properties;
+ const char *path;
+
+ dbus_message_iter_recurse(&dict, &value);
+ dbus_message_iter_get_basic(&value, &path);
+
+ dbus_message_iter_next(&value);
+ dbus_message_iter_recurse(&value, &properties);
+
+ _call_add(m, path, &properties);
+ }
+}
+
+static void _modem_calls_load(OFono_Modem *m)
+{
+ DBusMessage *msg = dbus_message_new_method_call(
+ bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE,
+ "GetCalls");
+
+ DBG("Get calls of %s", m->base.path);
+ _bus_object_message_send(&m->base, msg, _ofono_calls_get_reply, m);
+ dbus_message_unref(msg);
+}
+
+static OFono_Modem *_modem_new(const char *path)
+{
+ OFono_Modem *m = calloc(1, sizeof(OFono_Modem));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
+
+ m->base.path = eina_stringshare_add(path);
+ EINA_SAFETY_ON_NULL_GOTO(m->base.path, error_path);
+
+ m->calls = eina_hash_string_small_new(EINA_FREE_CB(_call_free));
+ EINA_SAFETY_ON_NULL_GOTO(m->calls, error_calls);
+
+ return m;
+
+error_calls:
+ eina_stringshare_del(m->base.path);
+error_path:
+ free(m);
+ return NULL;
+}
+
+static void _modem_free(OFono_Modem *m)
+{
+ DBG("m=%p %s", m, m->base.path);
+
+ if (modem_selected == m)
+ modem_selected = NULL;
+
+ eina_stringshare_del(m->name);
+ eina_stringshare_del(m->serial);
+
+ eina_hash_free(m->calls);
+
+ _bus_object_free(&m->base);
+}
+
+static unsigned int _modem_interfaces_extract(DBusMessageIter *array)
+{
+ DBusMessageIter entry;
+ unsigned int interfaces = 0;
+
+ dbus_message_iter_recurse(array, &entry);
+ for (; dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING;
+ dbus_message_iter_next(&entry)) {
+ const struct API_Interface_Map *itr;
+ const char *name;
+ size_t namelen;
+
+ dbus_message_iter_get_basic(&entry, &name);
+
+ if (strncmp(name, OFONO_PREFIX, strlen(OFONO_PREFIX)) != 0)
+ continue;
+
+ name += strlen(OFONO_PREFIX);
+ namelen = strlen(name);
+
+ DBG("interface: %s", name);
+ for (itr = api_iface_map; itr->name != NULL; itr++) {
+ if ((itr->namelen == namelen) &&
+ (memcmp(itr->name, name, namelen) == 0)) {
+ interfaces |= itr->bit;
+ break;
+ }
+ }
+ if (itr->name == NULL)
+ WRN("ignored %s", name);
+ }
+
+ return interfaces;
+}
+
+static void _modem_property_update(OFono_Modem *m, const char *key,
+ DBusMessageIter *value)
+{
+ if (strcmp(key, "Powered") == 0) {
+ m->powered = _dbus_bool_get(value);
+ DBG("%s Powered %d", m->base.path, m->powered);
+ } else if (strcmp(key, "Online") == 0) {
+ m->online = _dbus_bool_get(value);
+ DBG("%s Online %d", m->base.path, m->online);
+ } else if (strcmp(key, "Interfaces") == 0) {
+ unsigned int ifaces = _modem_interfaces_extract(value);
+ DBG("%s Interfaces 0x%02x", m->base.path, ifaces);
+ if (m->interfaces != ifaces) {
+ m->interfaces = ifaces;
+
+ if (modem_selected && modem_path_wanted &&
+ modem_selected->base.path != modem_path_wanted)
+ modem_selected = NULL;
+ }
+ } else if (strcmp(key, "Serial") == 0) {
+ const char *serial;
+ dbus_message_iter_get_basic(value, &serial);
+ DBG("%s Serial %s", m->base.path, serial);
+ eina_stringshare_replace(&m->serial, serial);
+ } else if (strcmp(key, "Type") == 0) {
+ const char *type;
+ dbus_message_iter_get_basic(value, &type);
+ DBG("%s Type %s", m->base.path, type);
+ m->ignored = strcmp(type, "hardware") != 0;
+ } else
+ DBG("%s %s (unused property)", m->base.path, key);
+}
+
+static void _modem_add(const char *path, DBusMessageIter *prop)
+{
+ OFono_Modem *m;
+
+ DBG("path=%s", path);
+
+ m = eina_hash_find(modems, path);
+ if (m) {
+ DBG("Modem already exists %p (%s)", m, path);
+ goto update_properties;
+ }
+
+ m = _modem_new(path);
+ EINA_SAFETY_ON_NULL_RETURN(m);
+ eina_hash_add(modems, m->base.path, m);
+
+ _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_VOICE_IFACE,
+ "CallAdded", _call_added, m);
+ _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_VOICE_IFACE,
+ "CallRemoved", _call_removed, m);
+
+ /* TODO: do we need to listen to BarringActive or Forwarded? */
+
+ if (modem_selected && modem_path_wanted &&
+ modem_selected->base.path != modem_path_wanted)
+ modem_selected = NULL;
+
+update_properties:
+ if (!prop)
+ return;
+ for (; dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY;
+ dbus_message_iter_next(prop)) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(prop, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ _modem_property_update(m, key, &value);
+ }
+
+ if (m->interfaces & OFONO_API_VOICE)
+ _modem_calls_load(m);
+}
+
+static void _modem_remove(const char *path)
+{
+ DBG("path=%s", path);
+ eina_hash_del_by_key(modems, path);
+}
+
+static void _ofono_modems_get_reply(void *data __UNUSED__, DBusMessage *msg,
+ DBusError *err)
+{
+ DBusMessageIter array, dict;
+
+ pc_get_modems = NULL;
+
+ if (!msg) {
+ if (err)
+ ERR("%s: %s", err->name, err->message);
+ else
+ ERR("No message");
+ return;
+ }
+
+ EINA_SAFETY_ON_NULL_RETURN(modems);
+ eina_hash_free_buckets(modems);
+
+ if (!dbus_message_iter_init(msg, &array)) {
+ ERR("Could not get modems");
+ return;
+ }
+
+ dbus_message_iter_recurse(&array, &dict);
+ for (; dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT;
+ dbus_message_iter_next(&dict)) {
+ DBusMessageIter value, properties;
+ const char *path;
+
+ dbus_message_iter_recurse(&dict, &value);
+ dbus_message_iter_get_basic(&value, &path);
+
+ dbus_message_iter_next(&value);
+ dbus_message_iter_recurse(&value, &properties);
+
+ _modem_add(path, &properties);
+ }
+}
+
+static void _modem_added(void *data __UNUSED__, DBusMessage *msg)
+{
+ DBusMessageIter iter, properties;
+ const char *path;
+
+ if (!msg || !dbus_message_iter_init(msg, &iter)) {
+ ERR("Could not handle message %p", msg);
+ return;
+ }
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &properties);
+
+ _modem_add(path, &properties);
+}
+
+static void _modem_removed(void *data __UNUSED__, DBusMessage *msg)
+{
+ DBusError err;
+ const char *path;
+
+ if (!msg) {
+ ERR("Could not handle message %p", msg);
+ return;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
+ &path, NULL)) {
+ ERR("Could not get ModemRemoved arguments: %s: %s",
+ err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+
+ _modem_remove(path);
+}
+
+static void _modem_property_changed(void *data __UNUSED__, DBusMessage *msg)
+{
+ const char *path;
+ OFono_Modem *m;
+ DBusMessageIter iter, value;
+ const char *key;
+
+ if (!msg || !dbus_message_iter_init(msg, &iter)) {
+ ERR("Could not handle message %p", msg);
+ return;
+ }
+
+ path = dbus_message_get_path(msg);
+ DBG("path=%s", path);
+
+ m = eina_hash_find(modems, path);
+ if (!m) {
+ DBG("Modem is unknown (%s)", path);
+ return;
+ }
+
+ dbus_message_iter_get_basic(&iter, &key);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+ _modem_property_update(m, key, &value);
+}
+
+static void _modems_load(void)
+{
+ DBusMessage *msg = dbus_message_new_method_call(
+ bus_id, "/", OFONO_PREFIX OFONO_MANAGER_IFACE, "GetModems");
+
+ if (pc_get_modems)
+ dbus_pending_call_cancel(pc_get_modems);
+
+ DBG("Get modems");
+ pc_get_modems = e_dbus_message_send(
+ bus_conn, msg, _ofono_modems_get_reply, -1, NULL);
+ dbus_message_unref(msg);
+}
+
+static void _ofono_connected(const char *id)
+{
+ free(bus_id);
+ bus_id = strdup(id);
+
+ sig_modem_added = e_dbus_signal_handler_add(
+ bus_conn, bus_id, "/",
+ OFONO_PREFIX OFONO_MANAGER_IFACE,
+ "ModemAdded",
+ _modem_added, NULL);
+
+ sig_modem_removed = e_dbus_signal_handler_add(
+ bus_conn, bus_id, "/",
+ OFONO_PREFIX OFONO_MANAGER_IFACE,
+ "ModemRemoved",
+ _modem_removed, NULL);
+
+ sig_modem_prop_changed = e_dbus_signal_handler_add(
+ bus_conn, bus_id, NULL,
+ OFONO_PREFIX OFONO_MODEM_IFACE,
+ "PropertyChanged",
+ _modem_property_changed, NULL);
+
+ _modems_load();
+
+ if (connected_cb)
+ connected_cb((void *)connected_cb_data);
+}
+
+static void _ofono_disconnected(void)
+{
+ eina_hash_free_buckets(modems);
+
+ if (sig_modem_added) {
+ e_dbus_signal_handler_del(bus_conn, sig_modem_added);
+ sig_modem_added = NULL;
+ }
+
+ if (sig_modem_removed) {
+ e_dbus_signal_handler_del(bus_conn, sig_modem_removed);
+ sig_modem_removed = NULL;
+ }
+
+ if (sig_modem_prop_changed) {
+ e_dbus_signal_handler_del(bus_conn, sig_modem_prop_changed);
+ sig_modem_prop_changed = NULL;
+ }
+
+ if (bus_id) {
+ if (disconnected_cb)
+ disconnected_cb((void *)disconnected_cb_data);
+
+ free(bus_id);
+ bus_id = NULL;
+ }
+}
+
+static void _name_owner_changed(void *data __UNUSED__, DBusMessage *msg)
+{
+ DBusError err;
+ const char *name, *from, *to;
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &from,
+ DBUS_TYPE_STRING, &to,
+ DBUS_TYPE_INVALID)) {
+ ERR("Could not get NameOwnerChanged arguments: %s: %s",
+ err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+
+ if (strcmp(name, bus_name) != 0)
+ return;
+
+ DBG("NameOwnerChanged %s from=%s to=%s", name, from, to);
+
+ if (from[0] == '\0' && to[0] != '\0') {
+ INF("oFono appeared as %s", to);
+ _ofono_connected(to);
+ } else if (from[0] != '\0' && to[0] == '\0') {
+ INF("oFono disappeared from %s", from);
+ _ofono_disconnected();
+ }
+}
+
+static void _ofono_get_name_owner(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
+{
+ DBusMessageIter itr;
+ const char *id;
+
+ if (!msg) {
+ if (err)
+ ERR("%s: %s", err->name, err->message);
+ else
+ ERR("No message");
+ return;
+ }
+
+ dbus_message_iter_init(msg, &itr);
+ dbus_message_iter_get_basic(&itr, &id);
+ if (!id || id[0] == '\0') {
+ ERR("No name owner fo %s!", bus_name);
+ return;
+ }
+
+ INF("oFono bus id: %s", id);
+ _ofono_connected(id);
+}
+
+OFono_Pending *ofono_modem_change_pin(const char *what, const char *old,
+ const char *new, OFono_Simple_Cb cb,
+ const void *data)
+{
+ OFono_Simple_Cb_Context *ctx = NULL;
+ OFono_Error err = OFONO_ERROR_OFFLINE;
+ OFono_Pending *p;
+ DBusMessage *msg;
+ OFono_Modem *m = _modem_selected_get();
+ EINA_SAFETY_ON_NULL_GOTO(m, error);
+ EINA_SAFETY_ON_NULL_GOTO(what, error);
+ EINA_SAFETY_ON_NULL_GOTO(old, error);
+ EINA_SAFETY_ON_NULL_GOTO(new, error);
+
+ if ((m->interfaces & OFONO_API_SIM) == 0)
+ goto error;
+ err = OFONO_ERROR_FAILED;
+
+ if (cb) {
+ ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
+ EINA_SAFETY_ON_NULL_GOTO(ctx, error);
+ ctx->cb = cb;
+ ctx->data = data;
+ }
+
+ msg = dbus_message_new_method_call(
+ bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE,
+ "ChangePin");
+ if (!msg)
+ goto error;
+
+ if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
+ DBUS_TYPE_STRING, &old,
+ DBUS_TYPE_STRING, &new,
+ DBUS_TYPE_INVALID))
+ goto error_message;
+
+ INF("ChangePin(%s, %s, %s)", what, old, new);
+ p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
+ dbus_message_unref(msg);
+ return p;
+
+error_message:
+ dbus_message_unref(msg);
+error:
+ if (cb)
+ cb((void *)data, err);
+ free(ctx);
+ return NULL;
+}
+
+OFono_Pending *ofono_modem_reset_pin(const char *what, const char *puk,
+ const char *new, OFono_Simple_Cb cb,
+ const void *data)
+{
+ OFono_Simple_Cb_Context *ctx = NULL;
+ OFono_Error err = OFONO_ERROR_OFFLINE;
+ OFono_Pending *p;
+ DBusMessage *msg;
+ OFono_Modem *m = _modem_selected_get();
+ EINA_SAFETY_ON_NULL_GOTO(m, error);
+ EINA_SAFETY_ON_NULL_GOTO(what, error);
+ EINA_SAFETY_ON_NULL_GOTO(puk, error);
+ EINA_SAFETY_ON_NULL_GOTO(new, error);
+
+ if ((m->interfaces & OFONO_API_SIM) == 0)
+ goto error;
+ err = OFONO_ERROR_FAILED;
+
+ if (cb) {
+ ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
+ EINA_SAFETY_ON_NULL_GOTO(ctx, error);
+ ctx->cb = cb;
+ ctx->data = data;
+ }
+
+ msg = dbus_message_new_method_call(
+ bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE, "ResetPin");
+ if (!msg)
+ goto error;
+
+ if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
+ DBUS_TYPE_STRING, &puk,
+ DBUS_TYPE_STRING, &new,
+ DBUS_TYPE_INVALID))
+ goto error_message;
+
+ INF("ResetPin(%s, %s, %s)", what, puk, new);
+ p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
+ dbus_message_unref(msg);
+ return p;
+
+error_message:
+ dbus_message_unref(msg);
+error:
+ if (cb)
+ cb((void *)data, err);
+ free(ctx);
+ return NULL;
+}
+
+static char *_ss_initiate_convert_ussd(const char *type __UNUSED__,
+ DBusMessageIter *itr)
+{
+ const char *ussd_response;
+
+ if (dbus_message_iter_get_arg_type(itr) != DBUS_TYPE_STRING) {
+ ERR("Invalid type: %c (expected: %c)",
+ dbus_message_iter_get_arg_type(itr), DBUS_TYPE_STRING);
+ return NULL;
+ }
+ dbus_message_iter_get_basic(itr, &ussd_response);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ussd_response, NULL);
+ return strdup(ussd_response);
+}
+
+static void _ss_initiate_cb_dict_convert(Eina_Strbuf *buf,
+ DBusMessageIter *dict)
+{
+ for (; dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY;
+ dbus_message_iter_next(dict)) {
+ DBusMessageIter e, v;
+ const char *key, *value;
+
+ dbus_message_iter_recurse(dict, &e);
+ dbus_message_iter_get_basic(&e, &key);
+
+ dbus_message_iter_next(&e);
+ dbus_message_iter_recurse(&e, &v);
+ dbus_message_iter_get_basic(&v, &value);
+
+ eina_strbuf_append_printf(buf, " %s=%s<br>",
+ key, value);
+ }
+}
+
+static char *_ss_initiate_convert_call1(const char *type, DBusMessageIter *itr)
+{
+ DBusMessageIter array, dict;
+ const char *ss_op, *service;
+ Eina_Strbuf *buf;
+ char *str;
+
+ dbus_message_iter_recurse(itr, &array);
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
+ ERR("Invalid type: %c (expected: %c)",
+ dbus_message_iter_get_arg_type(&array),
+ DBUS_TYPE_STRING);
+ return NULL;
+ }
+ dbus_message_iter_get_basic(&array, &ss_op);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
+
+ if (!dbus_message_iter_next(&array)) {
+ ERR("Missing %s service", type);
+ return NULL;
+ }
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
+ ERR("Invalid type: %c (expected: %c)",
+ dbus_message_iter_get_arg_type(&array),
+ DBUS_TYPE_STRING);
+ return NULL;
+ }
+ dbus_message_iter_get_basic(&array, &service);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(service, NULL);
+
+ if (!dbus_message_iter_next(&array)) {
+ ERR("Missing %s information", type);
+ return NULL;
+ }
+
+ buf = eina_strbuf_new();
+ eina_strbuf_append_printf(buf, "<b>%s %s=%s</b><br><br>",
+ type, ss_op, service);
+
+ dbus_message_iter_recurse(&array, &dict);
+ _ss_initiate_cb_dict_convert(buf, &dict);
+
+ str = eina_strbuf_string_steal(buf);
+ eina_strbuf_free(buf);
+ return str;
+}
+
+static char *_ss_initiate_convert_call_waiting(const char *type,
+ DBusMessageIter *itr)
+{
+ DBusMessageIter array, dict;
+ const char *ss_op;
+ Eina_Strbuf *buf;
+ char *str;
+
+ dbus_message_iter_recurse(itr, &array);
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
+ ERR("Invalid type: %c (expected: %c)",
+ dbus_message_iter_get_arg_type(&array),
+ DBUS_TYPE_STRING);
+ return NULL;
+ }
+ dbus_message_iter_get_basic(&array, &ss_op);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
+
+ if (!dbus_message_iter_next(&array)) {
+ ERR("Missing %s information", type);
+ return NULL;
+ }
+
+ buf = eina_strbuf_new();
+ eina_strbuf_append_printf(buf, "<b>%s %s</b><br><br>",
+ type, ss_op);
+
+ dbus_message_iter_recurse(&array, &dict);
+ _ss_initiate_cb_dict_convert(buf, &dict);
+
+ str = eina_strbuf_string_steal(buf);
+ eina_strbuf_free(buf);
+ return str;
+}
+
+static char *_ss_initiate_convert_call2(const char *type,
+ DBusMessageIter *itr)
+{
+ DBusMessageIter array;
+ const char *ss_op, *status;
+ Eina_Strbuf *buf;
+ char *str;
+
+ dbus_message_iter_recurse(itr, &array);
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
+ ERR("Invalid type: %c (expected: %c)",
+ dbus_message_iter_get_arg_type(&array),
+ DBUS_TYPE_STRING);
+ return NULL;
+ }
+ dbus_message_iter_get_basic(&array, &ss_op);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
+
+ if (!dbus_message_iter_next(&array)) {
+ ERR("Missing %s status", type);
+ return NULL;
+ }
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
+ ERR("Invalid type: %c (expected: %c)",
+ dbus_message_iter_get_arg_type(&array),
+ DBUS_TYPE_STRING);
+ return NULL;
+ }
+ dbus_message_iter_get_basic(&array, &status);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(status, NULL);
+
+ buf = eina_strbuf_new();
+ eina_strbuf_append_printf(buf, "<b>%s:</b><br><br>%s=%s",
+ type, ss_op, status);
+
+ str = eina_strbuf_string_steal(buf);
+ eina_strbuf_free(buf);
+ return str;
+}
+
+static const struct SS_Initiate_Convert_Map {
+ const char *type;
+ size_t typelen;
+ char *(*convert)(const char *type, DBusMessageIter *itr);
+} ss_initiate_convert_map[] = {
+#define MAP(type, conv) {type, sizeof(type) - 1, conv}
+ MAP("USSD", _ss_initiate_convert_ussd),
+ MAP("CallBarring", _ss_initiate_convert_call1),
+ MAP("CallForwarding", _ss_initiate_convert_call1),
+ MAP("CallWaiting", _ss_initiate_convert_call_waiting),
+ MAP("CallingLinePresentation", _ss_initiate_convert_call2),
+ MAP("ConnectedLinePresentation", _ss_initiate_convert_call2),
+ MAP("CallingLineRestriction", _ss_initiate_convert_call2),
+ MAP("ConnectedLineRestriction", _ss_initiate_convert_call2),
+#undef MAP
+ {NULL, 0, NULL}
+};
+
+static char *_ss_initiate_convert(DBusMessage *msg)
+{
+ DBusMessageIter array, variant;
+ const struct SS_Initiate_Convert_Map *citr;
+ const char *type = NULL;
+ size_t typelen;
+
+ if (!dbus_message_iter_init(msg, &array))
+ goto error;
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
+ ERR("Invalid type for first argument: %c (expected: %c)",
+ dbus_message_iter_get_arg_type(&array),
+ DBUS_TYPE_STRING);
+ goto error;
+ }
+ dbus_message_iter_get_basic(&array, &type);
+ if (!type) {
+ ERR("Couldn't get SupplementaryServices.Initiate type");
+ goto error;
+ }
+ DBG("type: %s", type);
+
+ if (!dbus_message_iter_next(&array)) {
+ ERR("Couldn't get SupplementaryServices.Initiate payload");
+ goto error;
+ }
+ dbus_message_iter_recurse(&array, &variant);
+
+ typelen = strlen(type);
+ for (citr = ss_initiate_convert_map; citr->type != NULL; citr++) {
+ if ((citr->typelen == typelen) &&
+ (memcmp(citr->type, type, typelen) == 0)) {
+ return citr->convert(type, &variant);
+ }
+ }
+ ERR("Could not convert SupplementaryServices.Initiate type %s", type);
+
+error:
+ return NULL;
+}
+
+OFono_Pending *ofono_ss_initiate(const char *command, OFono_String_Cb cb, const void *data)
+{
+ OFono_String_Cb_Context *ctx = NULL;
+ OFono_Error err = OFONO_ERROR_OFFLINE;
+ OFono_Pending *p;
+ DBusMessage *msg;
+ OFono_Modem *m = _modem_selected_get();
+ EINA_SAFETY_ON_NULL_GOTO(m, error);
+ EINA_SAFETY_ON_NULL_GOTO(command, error);
+
+ if ((m->interfaces & OFONO_API_SUPPL_SERV) == 0)
+ goto error;
+ err = OFONO_ERROR_FAILED;
+
+ ctx = calloc(1, sizeof(OFono_String_Cb_Context));
+ EINA_SAFETY_ON_NULL_GOTO(ctx, error);
+ ctx->cb = cb;
+ ctx->data = data;
+ ctx->name = OFONO_PREFIX OFONO_SUPPL_SERV_IFACE ".Initiate";
+ ctx->convert = _ss_initiate_convert;
+
+ msg = dbus_message_new_method_call(
+ bus_id, m->base.path, OFONO_PREFIX OFONO_SUPPL_SERV_IFACE,
+ "Initiate");
+ if (!msg)
+ goto error;
+
+ if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &command,
+ DBUS_TYPE_INVALID))
+ goto error_message;
+
+ INF("SupplementaryServices.Initiate(%s)", command);
+ p = _bus_object_message_send(&m->base, msg, _ofono_string_reply, ctx);
+ dbus_message_unref(msg);
+ return p;
+
+error_message:
+ dbus_message_unref(msg);
+error:
+ if (cb)
+ cb((void *)data, err, NULL);
+ free(ctx);
+ return NULL;
+}
+
+typedef struct _OFono_Call_Cb_Context
+{
+ OFono_Call_Cb cb;
+ OFono_Modem *modem;
+ const void *data;
+ const char *name;
+} OFono_Call_Cb_Context;
+
+static void _ofono_dial_reply(void *data, DBusMessage *msg, DBusError *err)
+{
+ OFono_Call_Cb_Context *ctx = data;
+ OFono_Call *c = NULL;
+ OFono_Error oe = OFONO_ERROR_NONE;
+
+ if (!msg) {
+ DBG("%s: %s", err->name, err->message);
+ oe = _ofono_error_parse(err->name);
+ } else {
+ DBusError e;
+ const char *path;
+ dbus_error_init(&e);
+ if (!dbus_message_get_args(msg, &e, DBUS_TYPE_OBJECT_PATH,
+ &path, DBUS_TYPE_INVALID)) {
+ ERR("Could not get Dial reply: %s: %s",
+ e.name, e.message);
+ dbus_error_free(&e);
+ oe = OFONO_ERROR_FAILED;
+ } else {
+ c = eina_hash_find(ctx->modem->calls, path);
+ if (!c) {
+ _call_add(ctx->modem, path, NULL);
+ c = eina_hash_find(ctx->modem->calls, path);
+ }
+ if (!c) {
+ ERR("Could not find call %s", path);
+ oe = OFONO_ERROR_FAILED;
+ }
+ }
+ }
+
+ if (ctx->cb)
+ ctx->cb((void *)ctx->data, oe, c);
+}
+
+OFono_Pending *ofono_dial(const char *number, const char *hide_callerid,
+ OFono_Call_Cb cb, const void *data)
+{
+ OFono_Call_Cb_Context *ctx = NULL;
+ OFono_Error err = OFONO_ERROR_OFFLINE;
+ OFono_Pending *p;
+ DBusMessage *msg;
+ OFono_Modem *m = _modem_selected_get();
+ EINA_SAFETY_ON_NULL_GOTO(m, error);
+
+
+ if ((m->interfaces & OFONO_API_VOICE) == 0)
+ goto error;
+ err = OFONO_ERROR_FAILED;
+
+ if (!hide_callerid)
+ hide_callerid = "";
+
+ ctx = calloc(1, sizeof(OFono_Call_Cb_Context));
+ EINA_SAFETY_ON_NULL_GOTO(ctx, error);
+ ctx->cb = cb;
+ ctx->data = data;
+ ctx->name = OFONO_PREFIX OFONO_VOICE_IFACE ".Dial";
+ ctx->modem = m;
+
+ msg = dbus_message_new_method_call(
+ bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE, "Dial");
+ if (!msg)
+ goto error;
+
+ if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &number,
+ DBUS_TYPE_STRING, &hide_callerid,
+ DBUS_TYPE_INVALID))
+ goto error_message;
+
+ INF("Dial(%s, %s)", number, hide_callerid);
+ p = _bus_object_message_send(&m->base, msg, _ofono_dial_reply, ctx);
+ dbus_message_unref(msg);
+ return p;
+
+error_message:
+ dbus_message_unref(msg);
+error:
+ if (cb)
+ cb((void *)data, err, NULL);
+ free(ctx);
+ return NULL;
+}
+
+const char *ofono_modem_serial_get(void)
+{
+ OFono_Modem *m = _modem_selected_get();
+ EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
+ return m->serial;
+}
+
+void ofono_modem_api_require(unsigned int api_mask)
+{
+ if (modem_api_mask == api_mask)
+ return;
+ modem_api_mask = api_mask;
+ modem_selected = NULL;
+}
+
+void ofono_modem_path_wanted_set(const char *path)
+{
+ if (eina_stringshare_replace(&modem_path_wanted, path))
+ modem_selected = NULL;
+}
+
+void ofono_connected_cb_set(void (*cb)(void *data), const void *data)
+{
+ connected_cb = cb;
+ connected_cb_data = data;
+}
+
+void ofono_disconnected_cb_set(void (*cb)(void *data), const void *data)
+{
+ disconnected_cb = cb;
+ disconnected_cb_data = data;
+}
+
+void ofono_call_added_cb_set(void (*cb)(void *data, OFono_Call *call),
+ const void *data)
+{
+ call_added_cb = cb;
+ call_added_cb_data = data;
+}
+
+void ofono_call_removed_cb_set(void (*cb)(void *data, OFono_Call *call),
+ const void *data)
+{
+ call_removed_cb = cb;
+ call_removed_cb_data = data;
+}
+
+void ofono_call_changed_cb_set(void (*cb)(void *data, OFono_Call *call),
+ const void *data)
+{
+ call_changed_cb = cb;
+ call_changed_cb_data = data;
+}
+
+void ofono_call_disconnected_cb_set(void (*cb)(void *data, OFono_Call *call, const char *reason),
+ const void *data)
+{
+ call_disconnected_cb = cb;
+ call_disconnected_cb_data = data;
+}
+
+Eina_Bool ofono_init(void)
+{
+ if (!elm_need_e_dbus()) {
+ CRITICAL("Elementary does not support DBus.");
+ return EINA_FALSE;
+ }
+
+ bus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
+ if (!bus_conn) {
+ CRITICAL("Could not get DBus System Bus");
+ return EINA_FALSE;
+ }
+
+ modems = eina_hash_string_small_new(EINA_FREE_CB(_modem_free));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(modems, EINA_FALSE);
+
+ e_dbus_signal_handler_add(bus_conn, E_DBUS_FDO_BUS, E_DBUS_FDO_PATH,
+ E_DBUS_FDO_INTERFACE,
+ "NameOwnerChanged",
+ _name_owner_changed, NULL);
+
+ e_dbus_get_name_owner(bus_conn, bus_name, _ofono_get_name_owner, NULL);
+
+ return EINA_TRUE;
+}
+
+void ofono_shutdown(void)
+{
+ if (pc_get_modems) {
+ dbus_pending_call_cancel(pc_get_modems);
+ pc_get_modems = NULL;
+ }
+
+ _ofono_disconnected();
+ eina_stringshare_replace(&modem_path_wanted, NULL);
+
+ eina_hash_free(modems);
+ modems = NULL;
+}
--- /dev/null
+#ifndef _EFL_OFONO_H__
+#define _EFL_OFONO_H__
+
+typedef enum
+{
+ OFONO_API_SIM = (1 << 0),
+ OFONO_API_NETREG = (1 << 1),
+ OFONO_API_VOICE = (1 << 2),
+ OFONO_API_MSG = (1 << 3),
+ OFONO_API_MSG_WAITING = (1 << 4),
+ OFONO_API_SMART_MSG = (1 << 5),
+ OFONO_API_STK = (1 << 6),
+ OFONO_API_CALL_FW = (1 << 7),
+ OFONO_API_CALL_VOL = (1 << 8),
+ OFONO_API_CALL_METER = (1 << 9),
+ OFONO_API_CALL_SET = (1 << 10),
+ OFONO_API_CALL_BAR = (1 << 11),
+ OFONO_API_SUPPL_SERV = (1 << 12),
+ OFONO_API_TXT_TEL = (1 << 13),
+ OFONO_API_CELL_BROAD = (1 << 14),
+ OFONO_API_CONNMAN = (1 << 15),
+ OFONO_API_PUSH_NOTIF = (1 << 16),
+ OFONO_API_PHONEBOOK = (1 << 17),
+ OFONO_API_ASN = (1 << 18)
+} OFono_API;
+
+typedef enum
+{
+ OFONO_ERROR_NONE = 0,
+ OFONO_ERROR_FAILED,
+ OFONO_ERROR_DOES_NOT_EXIST,
+ OFONO_ERROR_IN_PROGRESS,
+ OFONO_ERROR_IN_USE,
+ OFONO_ERROR_INVALID_ARGS,
+ OFONO_ERROR_INVALID_FORMAT,
+ OFONO_ERROR_ACCESS_DENIED,
+ OFONO_ERROR_ATTACH_IN_PROGRESS,
+ OFONO_ERROR_INCORRECT_PASSWORD,
+ OFONO_ERROR_NOT_ACTIVE,
+ OFONO_ERROR_NOT_ALLOWED,
+ OFONO_ERROR_NOT_ATTACHED,
+ OFONO_ERROR_NOT_AVAILABLE,
+ OFONO_ERROR_NOT_FOUND,
+ OFONO_ERROR_NOT_IMPLEMENTED,
+ OFONO_ERROR_NOT_RECOGNIZED,
+ OFONO_ERROR_NOT_REGISTERED,
+ OFONO_ERROR_NOT_SUPPORTED,
+ OFONO_ERROR_SIM_NOT_READY,
+ OFONO_ERROR_STK,
+ OFONO_ERROR_TIMEDOUT,
+ OFONO_ERROR_OFFLINE
+} OFono_Error;
+
+typedef enum
+{
+ OFONO_CALL_STATE_DISCONNECTED = 0,
+ OFONO_CALL_STATE_ACTIVE,
+ OFONO_CALL_STATE_HELD,
+ OFONO_CALL_STATE_DIALING,
+ OFONO_CALL_STATE_ALERTING,
+ OFONO_CALL_STATE_INCOMING,
+ OFONO_CALL_STATE_WAITING
+} OFono_Call_State;
+
+typedef struct _OFono_Call OFono_Call;
+typedef struct _OFono_Pending OFono_Pending;
+
+typedef void (*OFono_Simple_Cb)(void *data, OFono_Error error);
+typedef void (*OFono_String_Cb)(void *data, OFono_Error error, const char *str);
+typedef void (*OFono_Call_Cb)(void *data, OFono_Error error, OFono_Call *call);
+
+
+/* Voice Call: */
+OFono_Pending *ofono_call_hangup(OFono_Call *c, OFono_Simple_Cb cb,
+ const void *data);
+OFono_Pending *ofono_call_answer(OFono_Call *c, OFono_Simple_Cb cb,
+ const void *data);
+
+OFono_Call_State ofono_call_state_get(const OFono_Call *c);
+const char *ofono_call_name_get(const OFono_Call *c);
+const char *ofono_call_line_id_get(const OFono_Call *c);
+
+#define ofono_call_state_valid_check(c) \
+ (ofono_call_state_get(c) != OFONO_CALL_STATE_DISCONNECTED)
+
+void ofono_call_added_cb_set(void (*cb)(void *data, OFono_Call *call),
+ const void *data);
+void ofono_call_removed_cb_set(void (*cb)(void *data, OFono_Call *call),
+ const void *data);
+void ofono_call_changed_cb_set(void (*cb)(void *data, OFono_Call *call),
+ const void *data);
+void ofono_call_disconnected_cb_set(void (*cb)(void *data, OFono_Call *call, const char *reason),
+ const void *data);
+
+/* Modem: */
+const char *ofono_modem_serial_get(void);
+
+OFono_Pending *ofono_modem_change_pin(const char *what, const char *old, const char *new,
+ OFono_Simple_Cb cb, const void *data);
+OFono_Pending *ofono_modem_reset_pin(const char *what, const char *puk, const char *new,
+ OFono_Simple_Cb cb, const void *data);
+
+OFono_Pending *ofono_ss_initiate(const char *command, OFono_String_Cb cb, const void *data);
+
+OFono_Pending *ofono_dial(const char *number, const char *hide_callerid,
+ OFono_Call_Cb cb, const void *data);
+
+/* Setup: */
+void ofono_modem_api_require(unsigned int api_mask);
+void ofono_modem_path_wanted_set(const char *path);
+
+/* TODO: unique listener or multiple? set x add */
+void ofono_connected_cb_set(void (*cb)(void *data), const void *data);
+void ofono_disconnected_cb_set(void (*cb)(void *data), const void *data);
+
+void ofono_pending_cancel(OFono_Pending *pending);
+
+Eina_Bool ofono_init(void);
+void ofono_shutdown(void);
+
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Elementary.h>
+
+#include "log.h"
+#include "gui.h"
+
+static E_DBus_Connection *bus_conn = NULL;
+static E_DBus_Object *bus_obj = NULL;
+static E_DBus_Interface *bus_iface = NULL;
+
+#define RC_SERVICE "org.tizen.dialer"
+#define RC_IFACE "org.tizen.dialer.Control"
+#define RC_PATH "/"
+
+static DBusMessage *
+_rc_activate(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
+{
+ INF("Remotely activated!");
+ gui_activate();
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *
+_rc_dial(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
+{
+ DBusError err;
+ dbus_bool_t do_auto;
+ const char *number;
+
+ dbus_error_init(&err);
+ dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &number,
+ DBUS_TYPE_BOOLEAN, &do_auto, DBUS_TYPE_INVALID);
+ if (dbus_error_is_set(&err)) {
+ ERR("Could not parse message: %s: %s", err.name, err.message);
+ return dbus_message_new_error(msg, err.name, err.message);
+ }
+
+ INF("dial '%s' auto=%d!", number, do_auto);
+ gui_activate();
+ gui_number_set(number, do_auto);
+ return dbus_message_new_method_return(msg);
+}
+
+static void _rc_object_register(void)
+{
+ bus_obj = e_dbus_object_add(bus_conn, RC_PATH, NULL);
+ if (!bus_obj) {
+ CRITICAL("Could not create "RC_PATH" DBus object.");
+ return;
+ }
+ bus_iface = e_dbus_interface_new(RC_IFACE);
+ e_dbus_object_interface_attach(bus_obj, bus_iface);
+
+#define IF_ADD(name, par, ret, cb) \
+ e_dbus_interface_method_add(bus_iface, name, par, ret, cb)
+
+ IF_ADD("Activate", "", "", _rc_activate);
+ IF_ADD("Dial", "sb", "", _rc_dial);
+#undef IF_ADD
+}
+
+static void _rc_activate_existing_reply(void *data __UNUSED__,
+ DBusMessage *msg __UNUSED__,
+ DBusError *err)
+{
+ if (dbus_error_is_set(err)) {
+ CRITICAL("Failed to activate existing dialer: %s: %s",
+ err->name, err->message);
+ _app_exit_code = EXIT_FAILURE;
+ ecore_main_loop_quit();
+ return;
+ }
+
+ INF("Activated the existing dialer!");
+ ecore_main_loop_quit();
+}
+
+static void _rc_activate_existing(void)
+{
+ DBusMessage *msg = dbus_message_new_method_call(
+ RC_SERVICE, RC_PATH, RC_IFACE, "Activate");
+ e_dbus_message_send(bus_conn, msg, _rc_activate_existing_reply,
+ -1, NULL);
+ dbus_message_unref(msg);
+}
+
+static void _rc_request_name_reply(void *data __UNUSED__, DBusMessage *msg,
+ DBusError *err)
+{
+ DBusError e;
+ dbus_uint32_t t;
+
+ if (!msg) {
+ if (err)
+ WRN("%s: %s", err->name, err->message);
+ else
+ WRN("No message");
+ _rc_activate_existing();
+ return;
+ }
+
+ dbus_error_init(&e);
+ dbus_message_get_args(msg, &e, DBUS_TYPE_UINT32, &t, DBUS_TYPE_INVALID);
+ if (t == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ _rc_object_register();
+ gui_activate();
+ } else {
+ WRN("Dialer already running! Activate it!");
+ _rc_activate_existing();
+ }
+}
+
+Eina_Bool rc_init(void)
+{
+ if (!elm_need_e_dbus()) {
+ CRITICAL("Elementary does not support DBus.");
+ return EINA_FALSE;
+ }
+
+ bus_conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+ if (!bus_conn) {
+ CRITICAL("Could not get DBus System Bus");
+ return EINA_FALSE;
+ }
+
+ e_dbus_request_name(bus_conn, RC_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ _rc_request_name_reply, NULL);
+ return EINA_TRUE;
+}
+
+void rc_shutdown(void)
+{
+ if (bus_obj)
+ e_dbus_object_free(bus_obj);
+ if (bus_iface)
+ e_dbus_interface_unref(bus_iface);
+ bus_conn = NULL;
+}
--- /dev/null
+#ifndef _EFL_OFONO_RC_H__
+#define _EFL_OFONO_RC_H__ 1
+
+Eina_Bool rc_init(void);
+void rc_shutdown(void);
+
+#endif
--- /dev/null
+dnl Copyright (C) 2004-2008 Kim Woelders
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+dnl Originally snatched from somewhere...
+
+dnl Macro for checking if the compiler supports __attribute__
+
+dnl Usage: AC_C___ATTRIBUTE__
+dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__
+dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is
+dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused))
+dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is
+dnl defined to nothing.
+
+AC_DEFUN([AC_C___ATTRIBUTE__],
+[
+
+AC_MSG_CHECKING([for __attribute__])
+
+AC_CACHE_VAL([ac_cv___attribute__],
+ [AC_TRY_COMPILE(
+ [
+#include <stdlib.h>
+
+int func(int x);
+int foo(int x __attribute__ ((unused)))
+{
+ exit(1);
+}
+ ],
+ [],
+ [ac_cv___attribute__="yes"],
+ [ac_cv___attribute__="no"]
+ )])
+
+AC_MSG_RESULT($ac_cv___attribute__)
+
+if test "x${ac_cv___attribute__}" = "xyes" ; then
+ AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__])
+ AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused])
+ else
+ AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused])
+fi
+
+])
+
+dnl End of ac_attribute.m4
--- /dev/null
+dnl Copyright (C) 2010 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that check if a binary is built or not
+
+dnl Usage: EFL_ENABLE_BIN(binary)
+dnl Call AC_SUBST(BINARY_PRG) (BINARY is the uppercase of binary, - being transformed into _)
+dnl Define have_binary (- is transformed into _)
+dnl Define conditional BUILD_BINARY (BINARY is the uppercase of binary, - being transformed into _)
+
+AC_DEFUN([EFL_ENABLE_BIN],
+[
+
+m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl
+m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl
+
+have_[]m4_defn([DOWN])="yes"
+
+dnl configure option
+
+AC_ARG_ENABLE([$1],
+ [AC_HELP_STRING([--disable-$1], [disable building of ]DOWN)],
+ [
+ if test "x${enableval}" = "xyes" ; then
+ have_[]m4_defn([DOWN])="yes"
+ else
+ have_[]m4_defn([DOWN])="no"
+ fi
+ ])
+
+AC_MSG_CHECKING([whether to build ]DOWN[ binary])
+AC_MSG_RESULT([$have_[]m4_defn([DOWN])])
+
+if test "x$have_[]m4_defn([DOWN])" = "xyes"; then
+ UP[]_PRG=DOWN[${EXEEXT}]
+fi
+
+AC_SUBST(UP[]_PRG)
+
+AM_CONDITIONAL(BUILD_[]UP, test "x$have_[]m4_defn([DOWN])" = "xyes")
+
+AS_IF([test "x$have_[]m4_defn([DOWN])" = "xyes"], [$2], [$3])
+
+])
+
+
+dnl Macro that check if a binary is built or not
+
+dnl Usage: EFL_WITH_BIN(package, binary, default_value)
+dnl Call AC_SUBST(_binary) (_binary is the lowercase of binary, - being transformed into _ by default, or the value set by the user)
+
+AC_DEFUN([EFL_WITH_BIN],
+[
+
+m4_pushdef([DOWN], m4_translit([[$2]], [-A-Z], [_a-z]))dnl
+
+dnl configure option
+
+AC_ARG_WITH([$2],
+ [AC_HELP_STRING([--with-$2=PATH], [specify a specific path to ]DOWN[ @<:@default=$3@:>@])],
+ [_efl_with_binary=${withval}],
+ [_efl_with_binary=$(pkg-config --variable=prefix $1)/bin/$3])
+
+DOWN=${_efl_with_binary}
+AC_MSG_NOTICE(DOWN[ set to ${_efl_with_binary}])
+
+with_binary_[]m4_defn([DOWN])=${_efl_with_binary}
+
+AC_SUBST(DOWN)
+
+])