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