On 11/03/2010 06:20 PM, Rajyalakshmi Bommaraju wrote:
> ---
> Makefile.am | 6 +
> plugins/history.c | 438 +++++++++++++++++++++++++++++++++++++++++++++
> plugins/history_agent.c | 453
> +++++++++++++++++++++++++++++++++++++++++++++++
> plugins/history_agent.h | 103 +++++++++++
You might want to separate this patch into a series of patches. Start
with the API definition in the oFono API documentation format. Then the
history_agent implementation. Then the actual history plugin
implementation.
> 4 files changed, 1000 insertions(+), 0 deletions(-)
> create mode 100755 plugins/history.c
> create mode 100644 plugins/history_agent.c
> create mode 100644 plugins/history_agent.h
>
> diff --git a/Makefile.am b/Makefile.am
> index cd17fa2..530c2de 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -286,6 +286,12 @@ builtin_sources += plugins/ste.c
>
> builtin_modules += caif
> builtin_sources += plugins/caif.c
> +
> +
> +builtin_modules += history
> +builtin_sources += plugins/history_agent.h
> +builtin_sources += plugins/history_agent.c
> +builtin_sources += plugins/history.c
> endif
>
> if MAINTAINER_MODE
> diff --git a/plugins/history.c b/plugins/history.c
> new file mode 100755
> index 0000000..f5d4ba0
> --- /dev/null
> +++ b/plugins/history.c
> @@ -0,0 +1,438 @@
> +/*
> + *
> + * oFono - Open Source Telephony
> + *
> + * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
> USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define OFONO_API_SUBJECT_TO_CHANGE
> +#include <errno.h>
> +
> +#include "gdbus/gdbus.h"
> +#include <ofono/history.h>
> +#include "plugins/history_agent.h"
> +#include "src/common.h"
> +
> +#define HISTORY_FILE_PATH "/var/cache/ofonohistory/"
> +#define HISTORY_FILE HISTORY_FILE_PATH"ofonohistorydata"
> +#define OFONO_MANAGER_PATH "/"
Please note that this is already defined in include/dbus.h
> +#define OFONO_HISTORY_INTERFACE "com.meego.TelephonyHistory"
Please don't hijack OFONO_ prefix for private enums / defines.
> +
> +struct ofono_history {
> + struct history_agent *current_agent;
> + int timeout;
> +} *history;
> +
> +
Please avoid double empty lines
> +static int history_plugin_probe(struct ofono_history_context *context)
> +{
> + DBG("History Probe for modem: %p", context->modem);
> + return 0;
> +}
> +
> +static void history_plugin_remove(struct ofono_history_context *context)
> +{
> + DBG("History Remove for modem: %p", context->modem);
> +}
> +
> +/**
> + * history_call_ended:
> + * ofono calls this method with the call information
> + */
> +
Remove this empty line here
> +static void history_plugin_call_ended(struct ofono_history_context *context,
> + const struct ofono_call *call,
> + time_t start,
> + time_t end)
> +{
> + struct ofono_modem *modem;
> + const char *path;
> + struct history *v = g_try_new0(struct history, 1);
There should be an empty line after a variable declaration block.
> + if (!v)
> + return;
> +
> + v->data.voice.type = VOICE;
> +
> + strcpy(v->data.voice.lineid, "Unknown");
> +
> + if (call->type != 0)
> + return;
> +
> + DBG("Voice Call, %s", call->direction ? "Incoming" : "Outgoing");
> + v->data.voice.type = call->direction;
> +
> + if (call->clip_validity == 0)
> + strcpy(v->data.voice.lineid,
> + phone_number_to_string(&call->phone_number));
> +
> + v->data.voice.start_time = start;
> + v->data.voice.end_time = end;
> +
> + DBG("Call Ended on modem: %p", context->modem);
> + modem = context->modem;
> + path = ofono_modem_get_path(modem);
> +
> + v->data.voice.modem_path = g_try_malloc0(strlen(path) + 1);
> + if (v->data.voice.modem_path)
> + strcpy(v->data.voice.modem_path, path);
> +
> + if (!history) {
> + g_free(v);
> + return;
> + }
> +
> + history_agent_report_voicecall(v, history->current_agent,
> + history->timeout);
> +}
> +
> +/**
> + * history_call_missed:
> + * ofono calls this method with the call information
> + */
> +
Remove the empty line here
> +static void history_plugin_call_missed(struct ofono_history_context *context,
> + const struct ofono_call *call,
> + time_t when)
> +{
> + struct ofono_modem *modem;
> + const char *modem_path;
> +
Preferred way would be to remove the empty line here
> + struct history *v = g_try_new0(struct history, 1);
and add an empty line here
> + if (!v)
> + return;
Empty line here, refer to rule M1 of doc/coding-style.txt
> + v->type = VOICE;
> +
> + strcpy(v->data.voice.lineid, "Unknown");
> +
> + if (call->type != 0)
> + return;
> +
> + v->type = MISSED;
> +
> + if (call->clip_validity == 0)
> + strcpy(v->data.voice.lineid,
> + phone_number_to_string(&call->phone_number));
> +
> + v->data.voice.start_time = when;
> +
> + v->data.voice.end_time = when;
> +
> + DBG("Call Missed on modem: %p", context->modem);
> + modem = context->modem;
> + modem_path = ofono_modem_get_path(modem);
> +
> + v->data.voice.modem_path = g_try_malloc0(strlen(modem_path) + 1);
> + if (v->data.voice.modem_path)
> + strcpy(v->data.voice.modem_path, modem_path);
Again, rule M1
> + if (!history) {
> + g_free(v);
> + return;
> + }
> +
> + history_agent_report_voicecall(v, history->current_agent,
> + history->timeout);
> +}
> +
> +static void history_plugin_sms_received(struct ofono_history_context
> *context,
> + const struct ofono_uuid *uuid,
> + const char *from,
> + const struct tm *remote,
> + const struct tm *local,
> + const char *text)
> +{
> + char buf[128];
> + struct ofono_modem *modem;
> + const char *modem_path;
> +
> + struct history *thistory = g_try_new0(struct history, 1);
And empty line here
> + if (!thistory)
> + return;
> +
> + thistory->data.text.type = TEXT;
> +
> + strcpy(thistory->data.text.uid, ofono_uuid_to_str(uuid));
> +
> + strftime(buf, 127, "%a %d %b %Y %H:%M:%S %z", local);
> + buf[127] = '\0';
> + DBG("Local Sent Time: %s", buf);
> +
> + thistory->data.text.localsenttime = *local;
> +
> + strftime(buf, 127, "%a %d %b %Y %H:%M:%S %z", remote);
> + buf[127] = '\0';
> + DBG("Remote Sent Time: %s", buf);
> + thistory->data.text.remotesenttime = *remote;
> +
> + DBG("Text: %s", text);
> +
> + thistory->data.text.message = (char *) g_try_malloc0(strlen(text) + 1);
> + strcpy(thistory->data.text.message, text);
> +
> + DBG("From: %s:", from);
> + strcpy(thistory->data.text.lineid, from);
> +
> + thistory->data.text.type = INCOMING;
> +
> + thistory->data.text.status = OFONO_HISTORY_SMS_STATUS_SUBMITTED;
> +
> + DBG("Incoming SMS on modem: %p", context->modem);
> + modem = context->modem;
> + modem_path = ofono_modem_get_path(modem);
> +
> + thistory->data.text.modem_path = g_try_malloc0(strlen(modem_path) + 1);
Rule M1...
> + if (thistory->data.text.modem_path)
> + strcpy(thistory->data.text.modem_path, modem_path);
> +
> + history_agent_report_textmessage(thistory, history->current_agent,
> + history->timeout);
> +}
> +
> +static void history_plugin_sms_send_status(
> + struct ofono_history_context *context,
> + const struct ofono_uuid *uuid,
> + time_t when,
> + enum ofono_history_sms_status s)
> +{
> + char buf[128];
> + struct ofono_modem *modem;
> + const char *modem_path;
> +
> + struct history *thistory = g_try_new0(struct history, 1);
An empty line here
> + if (!thistory)
> + return;
> +
> + thistory->type = TEXT;
> +
> + strcpy(thistory->data.text.uid, ofono_uuid_to_str(uuid));
> +
> + thistory->data.text.localsenttime = *(localtime(&when));
> + strftime(buf, 127, "%Y-%m-%dT%H:%M:%S%z",
> + &(thistory->data.text.localsenttime));
> + buf[127] = '\0';
> + thistory->data.text.type = OUTGOING;
> +
> + switch (s) {
> + case OFONO_HISTORY_SMS_STATUS_PENDING:
> + break;
> + case OFONO_HISTORY_SMS_STATUS_SUBMITTED:
> +
> + DBG("SMS %s submitted successfully", ofono_uuid_to_str(uuid));
> + DBG("Submission Time: %s", buf);
> +
> + thistory->data.text.status =
> + OFONO_HISTORY_SMS_STATUS_SUBMITTED;
> + break;
> + case OFONO_HISTORY_SMS_STATUS_SUBMIT_FAILED:
> +
> + DBG("SMS %s submitted successfully", ofono_uuid_to_str(uuid));
> + DBG("Failure Time: %s", buf);
> +
> + thistory->data.text.status =
> + OFONO_HISTORY_SMS_STATUS_SUBMIT_FAILED;
> + break;
> + default:
> + break;
> + };
> +
> + modem = context->modem;
> + modem_path = ofono_modem_get_path(modem);
> +
> + thistory->data.text.modem_path = g_try_malloc0(strlen(modem_path)
> + + 1);
> + if (thistory->data.text.modem_path)
> + strcpy(thistory->data.text.modem_path, modem_path);
> +
> + history_agent_report_textmessage(thistory, history->current_agent,
> + history->timeout);
> +}
> +
> +static void history_plugin_sms_send_pending(
> + struct ofono_history_context *context,
> + const struct ofono_uuid *uuid,
> + const char *to, time_t when,
> + const char *text)
> +{
> + char buf[128];
> + struct ofono_modem *modem;
> + const char *modem_path;
> +
> + struct history *thistory = g_try_new0(struct history, 1);
> + if (!thistory)
> + return;
> +
> + thistory->type = TEXT;
> +
> + DBG("To: %s:", to);
> + strcpy(thistory->data.text.lineid, to);
> +
> + DBG("SMS %s submitted successfully", ofono_uuid_to_str(uuid));
> + strcpy(thistory->data.text.uid, ofono_uuid_to_str(uuid));
> +
> + thistory->data.text.localsenttime = *(localtime(&when));
> + strftime(buf, 127, "%Y-%m-%dT%H:%M:%S%z",
> + &(thistory->data.text.localsenttime));
> + buf[127] = '\0';
> + DBG("Local Time: %s", buf);
> +
> + thistory->data.text.type = OUTGOING;
> +
> + DBG("Text: %s", text);
> + thistory->data.text.message = (char *) g_try_malloc0(strlen(text)
> + + 1);
> + if (thistory->data.text.message)
> + strcpy(thistory->data.text.message, text);
> +
> + thistory->data.text.status = OFONO_HISTORY_SMS_STATUS_PENDING;
> +
> + DBG("Sending SMS on modem: %p", context->modem);
> + modem = context->modem;
> + modem_path = ofono_modem_get_path(modem);
> +
> + thistory->data.text.modem_path = g_try_malloc0(strlen(modem_path)
> + + 1);
> + if (thistory->data.text.modem_path)
> + strcpy(thistory->data.text.modem_path, modem_path);
> +
> + history_agent_report_textmessage(thistory, history->current_agent,
> + history->timeout);
> +}
> +
> +static void history_notify(gpointer user_data)
> +{
> + struct ofono_history *ohistory = user_data;
> +
> + DBG("History Agent Removed");
> +
> + ohistory->current_agent = NULL;
> +}
> +
> +static DBusMessage *history_register_agent(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + const char *agent_path;
> + if (dbus_message_get_args(msg, NULL,
> + DBUS_TYPE_OBJECT_PATH, &agent_path,
> + DBUS_TYPE_INVALID) == FALSE)
> + return __ofono_error_invalid_args(msg);
> +
> + if (!__ofono_dbus_valid_object_path(agent_path))
> + return __ofono_error_invalid_format(msg);
> +
> + if (!history)
> + return __ofono_error_failed(msg);
> +
> + history->current_agent = history_agent_new(agent_path,
> + dbus_message_get_sender(msg),
> + FALSE);
> +
> + if (!history->current_agent)
> + return __ofono_error_failed(msg);
> +
> + DBG("History agent created");
> +
> + history_agent_set_removed_notify(history->current_agent,
> + history_notify, history);
> +
> + return dbus_message_new_method_return(msg);
> +}
> +
> +static DBusMessage *history_unregister_agent(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + const char *agent_path;
> +
> + const char *agent_bus = dbus_message_get_sender(msg);
> +
> + if (dbus_message_get_args(msg, NULL,
> + DBUS_TYPE_OBJECT_PATH, &agent_path,
> + DBUS_TYPE_INVALID) == FALSE)
> + return __ofono_error_invalid_args(msg);
> +
> + if (!history->current_agent)
> + return __ofono_error_failed(msg);
> +
> + if (!history_agent_matches(history->current_agent, agent_path,
> + agent_bus))
> + return __ofono_error_failed(msg);
> +
> + history_agent_free(history->current_agent);
> +
> + return dbus_message_new_method_return(msg);
> +}
> +
> +static GDBusMethodTable history_methods[] = {
> + { "RegisterAgent", "o", "", history_register_agent },
> + { "UnregisterAgent", "o", "", history_unregister_agent },
> + { }
> +};
> +
> +static struct ofono_history_driver history_driver = {
> + .name = "history plugin",
> + .probe = history_plugin_probe,
> + .remove = history_plugin_remove,
> + .call_ended = history_plugin_call_ended,
> + .call_missed = history_plugin_call_missed,
> + .sms_received = history_plugin_sms_received,
> + .sms_send_pending = history_plugin_sms_send_pending,
> + .sms_send_status = history_plugin_sms_send_status
> +};
> +
> +static int history_plugin_init(void)
> +{
> + DBusConnection *conn = ofono_dbus_get_connection();
> +
> + if (!g_dbus_register_interface(conn,
> + OFONO_MANAGER_PATH,
> + OFONO_HISTORY_INTERFACE,
> + history_methods,
> + NULL,
> + NULL, /* Properties */
> + NULL, /* Userdata */
> + NULL)) { /* Destroy func */
> + ofono_error("Could not create %s interface",
> + OFONO_HISTORY_INTERFACE);
> +
> + return -EIO;
> + }
> +
> + history = g_try_new0(struct ofono_history, 1);
> +
> + if (!history)
> + return -EIO;
> +
> + history->timeout = 600; /* 10 minutes */
> + return ofono_history_driver_register(&history_driver);
> +}
> +
> +static void history_plugin_exit(void)
> +{
> + DBusConnection *conn = ofono_dbus_get_connection();
> +
> + g_dbus_unregister_interface(conn, OFONO_MANAGER_PATH,
> + OFONO_HISTORY_INTERFACE);
> + if (history)
> + g_free(history);
> + ofono_history_driver_unregister(&history_driver);
> +}
> +
> +OFONO_PLUGIN_DEFINE(history, "History Plugin",
> + OFONO_VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
> + history_plugin_init, history_plugin_exit)
> diff --git a/plugins/history_agent.c b/plugins/history_agent.c
> new file mode 100644
> index 0000000..d4d55ec
> --- /dev/null
> +++ b/plugins/history_agent.c
> @@ -0,0 +1,453 @@
> +/*
> + *
> + * oFono - Open Source Telephony
> + *
> + * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
> USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define OFONO_API_SUBJECT_TO_CHANGE
> +#define MODEM_STRUCT_LEN 2
> +
> +#include "plugins/history_agent.h"
> +
> +#define OFONO_HISTORY_AGENT "com.meego.TelephonyHistoryAgent"
Again, please do not hijack OFONO_ prefix for your private defines.
> +#define ERROR_PREFIX OFONO_SERVICE ".Error"
> +#define FAILED_ERROR ERROR_PREFIX ".Failed"
> +
> +enum allowed_errors {
> + ALLOWED_ERROR_FAILED = 0x1
> +};
> +
> +struct history_agent {
> + char *path;
> + char *bus;
> + guint disconnect_watch;
> + ofono_bool_t remove_on_terminate;
> + ofono_destroy_func removed_cb;
> + void *removed_data;
> + DBusPendingCall *call;
> + void *user_data;
So in general this data structure is fine, however do keep in mind that
it is possible to perform only a single request at a time. If several
history events happen simultaneously, they need to be queued / buffered
by the caller.
I don't believe your current code is handling this possibility at all.
The other obvious thing that is missing is the lack of serialization /
deserialization of this queue, or the immediate submission of the events
to the agent when it is first registered.
> +};
> +
> +void history_agent_free(struct history_agent *agent)
> +{
> + DBusConnection *conn = ofono_dbus_get_connection();
> +
> + if (agent->disconnect_watch) {
> + history_agent_send_release(agent);
> + g_dbus_remove_watch(conn, agent->disconnect_watch);
> + agent->disconnect_watch = 0;
> + }
> +
> + if (agent->removed_cb)
> + agent->removed_cb(agent->removed_data);
> +
> + g_free(agent->path);
> + g_free(agent->bus);
> + g_free(agent);
> +}
> +
> +static void history_agent_disconnect_cb(DBusConnection *conn, void
> *user_data)
> +{
> + DBG("Agent exited without unregister");
> +
> + struct history_agent *agent = user_data;
> +
> + agent->disconnect_watch = 0;
> +
> + history_agent_free(agent);
> +}
> +
> +ofono_bool_t history_agent_matches(struct history_agent *agent,
> + const char *path, const char *sender)
> +{
> + return !strcmp(agent->path, path) && !strcmp(agent->bus, sender);
> +}
> +
> +struct history_agent *history_agent_new(const char *path, const char *sender,
> + ofono_bool_t remove_on_terminate)
Please note that remove_on_terminate is not really needed and should be
TRUE by default. This was specific to stkagent and should not be
propagated elsewhere.
> +{
> + DBusConnection *conn = ofono_dbus_get_connection();
> + struct history_agent *agent = g_try_new0(struct history_agent, 1);
En empty line here
> + if (!agent)
> + return NULL;
> +
> + agent->path = g_strdup(path);
> + agent->bus = g_strdup(sender);
> + agent->remove_on_terminate = remove_on_terminate;
> +
> + agent->disconnect_watch = g_dbus_add_disconnect_watch(conn, sender,
> + history_agent_disconnect_cb,
> + agent, NULL);
> + return agent;
> +}
> +
> +static int check_error(struct history_agent *agent, DBusMessage *reply,
> + int allowed_errors,
> + enum HISTORY_AGENT_RESULT *out_result)
> +{
> + DBusError err;
> + int result = 0;
> +
> + dbus_error_init(&err);
> +
> + if (dbus_set_error_from_message(&err, reply) == FALSE) {
> + *out_result = HISTORY_AGENT_RESULT_OK;
> + return 0;
> + }
> +
> + ofono_debug("HistoryAgent %s replied with error %s, %s",
> + agent->path, err.name, err.message);
> +
> + /* Timeout is always valid */
> + if (g_str_equal(err.name, DBUS_ERROR_NO_REPLY)) {
> + /* Send a Cancel() to the agent since its taking too long */
> + *out_result = HISTORY_AGENT_RESULT_TIMEOUT;
> + goto out;
> + }
> +
> + if ((allowed_errors & ALLOWED_ERROR_FAILED) &&
> + g_str_equal(err.name, FAILED_ERROR)) {
> + *out_result = HISTORY_AGENT_RESULT_FAILED;
> + goto out;
> + }
> +
> + result = -EINVAL;
> +out:
> + dbus_error_free(&err);
> + return result;
> +}
> +
> +static void history_agent_send_no_reply(struct history_agent *agent,
> + const char *method)
> +{
> + DBusConnection *conn = ofono_dbus_get_connection();
> + DBusMessage *message;
> +
> + message = dbus_message_new_method_call(agent->bus, agent->path,
> + OFONO_HISTORY_AGENT,
> + method);
> +
> + if (message == NULL)
> + return;
> +
> + dbus_message_set_no_reply(message, TRUE);
> +
> + g_dbus_send_message(conn, message);
> +}
> +
> +static void history_agent_data_free(void *data)
> +{
> + struct history *history = (struct history *)data;
An empty line here.
> + if (history->type == TEXT) {
> + g_free(history->data.text.message);
> + g_free(history->data.text.modem_path);
> + } else {
> + g_free(history->data.voice.modem_path);
> + }
And again please see rule M1 in doc/coding-style.txt
> + g_free(history);
> +}
> +
> +static const char *call_type_to_string(enum type tp)
> +{
> + switch (tp) {
> + case INCOMING:
> + return "incoming";
> + case OUTGOING:
> + return "outgoing";
> + case MISSED:
> + return "missed";
> + default:
> + return "unknown";
> + }
> +}
> +
> +static const char *status_to_string(enum ofono_history_sms_status status)
> +{
> + switch (status) {
> + case OFONO_HISTORY_SMS_STATUS_PENDING:
> + return "Pending";
> + case OFONO_HISTORY_SMS_STATUS_SUBMITTED:
> + return "Submitted";
> + case OFONO_HISTORY_SMS_STATUS_SUBMIT_FAILED:
> + return "Submit Failed";
> + case OFONO_HISTORY_SMS_STATUS_DELIVERED:
> + return "Delivered";
> + case OFONO_HISTORY_SMS_STATUS_DELIVER_FAILED:
> + return "Deliver Failed";
> + default:
> + return "unknown";
> + }
In general oFono APIs use lower caps and hyphens for values. Remember,
these are not translated. So this should be 'pending', 'submitted',
'submit-failed', 'delivered', 'delivery-failed', or something like that.
The 'unknown' state is pretty much useless.
> +}
> +
> +static void data_delivery_cb(DBusPendingCall *call, void *data)
> +{
> + struct history_agent *agent = data;
> + enum HISTORY_AGENT_RESULT result = -EINVAL;
> +
> + DBusMessage *reply = dbus_pending_call_steal_reply(call);
> +
> + if (check_error(agent, reply,
> + ALLOWED_ERROR_FAILED,
> + &result) == -EINVAL) {
> + g_print("Agent disappeared\n");
> + /* TODO - persist agent->user_data */
> + history_agent_data_free(agent->user_data);
> + }
> +
> + if (result == HISTORY_AGENT_RESULT_OK) {
> + g_print("Agent reply ok\n");
> + history_agent_data_free(agent->user_data);
> + }
> +
> + if (result == HISTORY_AGENT_RESULT_TIMEOUT) {
> + g_print("Reply timedout\n");
> + /* TODO - persist agent->user_data*/
> + history_agent_data_free(agent->user_data);
> + }
> +}
> +
> +static char **get_modem_struct(const char *path)
> +{
> + int i = 0;
> + char **ret;
> +
> + /* TODO - Figureout how to release this*/
> + ret = g_try_new0(char *, 3);
> + if (!ret)
> + return NULL;
> +
> + ret[i++] = g_strdup("Modem");
> + ret[i++] = g_strdup(path);
> +
> + return ret;
> +}
> +
> +static void append_texthistory_properties(struct text_history *h,
> + DBusMessageIter *array)
> +{
> + const char *localtm, *senttm;
> + static char localsenttm[128], rsenttime[128];
> + const char *phone;
> + const char *mesg;
> + const char *msgid;
> + DBusMessageIter dict;
> + char **modem_dict;
> +
> + dbus_message_iter_open_container(array, DBUS_TYPE_ARRAY,
> + OFONO_PROPERTIES_ARRAY_SIGNATURE,
> + &dict);
> +
> + strftime(localsenttm, 127, "%Y-%m-%dT%H:%M:%S%z",
> + (&h->localsenttime));
> + localsenttm[127] = '\0';
> + localtm = localsenttm;
> +
> + strftime(rsenttime, 127, "%Y-%m-%dT%H:%M:%S%z",
> + (&h->remotesenttime));
> + rsenttime[127] = '\0';
> + senttm = rsenttime;
> +
> + msgid = h->uid;
> +
> + ofono_dbus_dict_append(&dict, "Uid", DBUS_TYPE_STRING, &msgid);
> +
> + const char *type_str = call_type_to_string(h->type);
> +
> + ofono_dbus_dict_append(&dict, "Type",
> + DBUS_TYPE_STRING, &type_str);
> +
> + const char *status_str = status_to_string(h->status);
> +
> + ofono_dbus_dict_append(&dict, "Status",
> + DBUS_TYPE_STRING, &status_str);
> +
> + phone = h->lineid;
> + ofono_dbus_dict_append(&dict, "LineIdentification", DBUS_TYPE_STRING,
> + &phone);
> +
> + ofono_dbus_dict_append(&dict, "LocalSentTime", DBUS_TYPE_STRING,
> + &localtm);
> +
> + ofono_dbus_dict_append(&dict, "SentTime", DBUS_TYPE_STRING,
> + &senttm);
> + mesg = h->message;
> + ofono_dbus_dict_append(&dict, "Message", DBUS_TYPE_STRING,
> + &mesg);
> +
> + modem_dict = get_modem_struct(h->modem_path);
> +
> + ofono_dbus_dict_append_dict(&dict, "Information", DBUS_TYPE_STRING,
> + &modem_dict);
> +
> + dbus_message_iter_close_container(array, &dict);
> +}
> +
> +static void append_voicehistory_properties(struct voice_history *h,
> + DBusMessageIter *array)
> +{
> + const char *sttime, *entime;
> + static char starttime[128], endtime[128];
> + struct tm starttm, endtm;
> + const char *phone;
> + char **modem_dict;
> + DBusMessageIter dict;
> +
> + dbus_message_iter_open_container(array, DBUS_TYPE_ARRAY,
> + OFONO_PROPERTIES_ARRAY_SIGNATURE,
> + &dict);
> +
> + strftime(starttime, 127, "%Y-%m-%dT%H:%M:%S%z",
> + localtime_r(&h->start_time, &starttm));
> + starttime[127] = '\0';
> + sttime = starttime;
> +
> + strftime(endtime, 127, "%Y-%m-%dT%H:%M:%S%z",
> + localtime_r(&h->end_time, &endtm));
> + endtime[127] = '\0';
> + entime = endtime;
> +
> + ofono_dbus_dict_append(&dict, "Uid", DBUS_TYPE_UINT32, &h->uid);
> +
> + const char *type_str = call_type_to_string(h->type);
> +
> + ofono_dbus_dict_append(&dict, "Type",
> + DBUS_TYPE_STRING, &type_str);
> +
> + phone = h->lineid;
> + ofono_dbus_dict_append(&dict, "LineIdentification", DBUS_TYPE_STRING,
> + &phone);
> +
> + ofono_dbus_dict_append(&dict, "StartTime", DBUS_TYPE_STRING,
> + &sttime);
> +
> + ofono_dbus_dict_append(&dict, "EndTime", DBUS_TYPE_STRING,
> + &entime);
> +
> + modem_dict = get_modem_struct(h->modem_path);
> +
> + ofono_dbus_dict_append_dict(&dict, "Information", DBUS_TYPE_STRING,
> + &modem_dict);
> +
> + dbus_message_iter_close_container(array, &dict);
> +}
> +
> +int history_agent_report_voicecall(struct history *history,
> + struct history_agent *agent, int timeout)
> +{
> + if (!agent)
> + /* TODO persist history */
> + return -1;
> +
> + DBusMessage *msg ;
> + DBusMessageIter iter, array;
> + struct voice_history *vhistory = &(history->data.voice);
> + DBusConnection *conn = ofono_dbus_get_connection();
> +
> + msg = dbus_message_new_method_call(agent->bus,
> + agent->path,
> + OFONO_HISTORY_AGENT,
> + "ReportVoiceCall");
> + if (msg == NULL)
> + return -ENOMEM;
> +
> + dbus_message_iter_init_append(msg, &iter);
> +
> + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
> + DBUS_TYPE_ARRAY_AS_STRING
> + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
> + DBUS_TYPE_STRING_AS_STRING
> + DBUS_TYPE_VARIANT_AS_STRING
> + DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
> + &array);
> + append_voicehistory_properties(vhistory, &array);
> +
> + dbus_message_iter_close_container(&iter, &array);
> +
> + agent->user_data = (void *)history;
> +
> + if (dbus_connection_send_with_reply(conn, msg, &agent->call,
> + timeout) == FALSE ||
> + agent->call == NULL)
> + return -EIO;
> +
> + dbus_pending_call_set_notify(agent->call, data_delivery_cb,
> + agent, NULL);
> + return 0;
> +}
> +
> +
> +int history_agent_report_textmessage(struct history *history,
> + struct history_agent *agent, int timeout)
> +{
> + if (!agent)
> + /* TODO Persist history */
> + return -1;
> +
> + DBusMessage *msg ;
> + DBusMessageIter iter, array;
> + struct text_history *text_history = &(history->data.text);
> + DBusConnection *conn = ofono_dbus_get_connection();
> +
> + msg = dbus_message_new_method_call(agent->bus,
> + agent->path,
> + OFONO_HISTORY_AGENT,
> + "ReportTextMessage");
> + if (msg == NULL)
> + return -ENOMEM;
> +
> + dbus_message_iter_init_append(msg, &iter);
> +
> + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
> + DBUS_TYPE_ARRAY_AS_STRING
> + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
> + DBUS_TYPE_STRING_AS_STRING
> + DBUS_TYPE_VARIANT_AS_STRING
> + DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
> + &array);
> + append_texthistory_properties(text_history, &array);
> +
> + dbus_message_iter_close_container(&iter, &array);
> +
> + agent->user_data = (void *)history;
> +
> + if (dbus_connection_send_with_reply(conn, msg, &agent->call,
> + timeout) == FALSE ||
> + agent->call == NULL)
> + return -EIO;
> +
> + dbus_pending_call_set_notify(agent->call, data_delivery_cb,
> + agent, NULL);
> + return 0;
> +}
> +
> +void history_agent_send_release(struct history_agent *agent)
> +{
> + history_agent_send_no_reply(agent, "Release");
> +}
> +
> +void history_agent_set_removed_notify(struct history_agent *agent,
> + ofono_destroy_func destroy,
> + void *user_data)
> +{
> + agent->removed_cb = destroy;
> + agent->removed_data = user_data;
> +}
> diff --git a/plugins/history_agent.h b/plugins/history_agent.h
> new file mode 100644
> index 0000000..fe7049e
> --- /dev/null
> +++ b/plugins/history_agent.h
> @@ -0,0 +1,103 @@
> +/*
> + *
> + * oFono - Open Source Telephony
> + *
> + * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
> USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define OFONO_API_SUBJECT_TO_CHANGE
> +#include <errno.h>
> +#include <string.h>
> +
> +#include "gdbus/gdbus.h"
> +#include <ofono/dbus.h>
> +#include <ofono/history.h>
> +#include <ofono/log.h>
> +#include <ofono/types.h>
> +#include "src/ofono.h"
> +
> +#define PHONE_NUMBER_LENGTH 64
> +struct history_agent;
> +
> +enum history_type {
> + VOICE = 0,
> + TEXT
> +};
> +
> +struct voice_history {
> + guint32 uid;
> + guint8 type;
> + char lineid[PHONE_NUMBER_LENGTH];
> + time_t start_time;
> + time_t end_time;
> + char *modem_path;
> +};
> +
> +struct text_history {
> + char uid[OFONO_SHA1_UUID_LEN * 2 + 1];
> + guint8 type;
> + guint8 status;
> + char lineid[PHONE_NUMBER_LENGTH];
> + struct tm localsenttime;
> + struct tm remotesenttime;
> + char *message;
> + char *modem_path;
> +};
> +
> +struct history {
> + union {
> + struct voice_history voice;
> + struct text_history text;
> + } data;
> + enum history_type type;
> +};
> +
> +enum HISTORY_AGENT_RESULT {
> + HISTORY_AGENT_RESULT_OK,
> + HISTORY_AGENT_RESULT_FAILED,
> + HISTORY_AGENT_RESULT_TIMEOUT
> +};
> +
> +enum type {
> + OUTGOING = 0,
> + INCOMING,
> + MISSED
> +};
> +
> +struct history_agent *history_agent_new(const char *path, const char *sender,
> + ofono_bool_t remove_on_terminate);
> +
> +void history_agent_free(struct history_agent *agent);
> +
> +ofono_bool_t history_agent_matches(struct history_agent *agent,
> + const char *path, const char *sender);
> +
> +int history_agent_report_voicecall(struct history *vhistory,
> + struct history_agent *agent, int timeout);
> +
> +int history_agent_report_textmessage(struct history *history,
> + struct history_agent *agent, int timeout);
> +
> +void history_agent_send_release(struct history_agent *agent);
> +
> +void history_agent_set_removed_notify(struct history_agent *agent,
> + ofono_destroy_func destroy,
> + void *user_data);
Regards,
-Denis
_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono