---
 Makefile.am             |    6 +
 plugins/history.c       |  438 +++++++++++++++++++++++++++++++++++++++++++++
 plugins/history_agent.c |  453 +++++++++++++++++++++++++++++++++++++++++++++++
 plugins/history_agent.h |  103 +++++++++++
 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 "/"
+#define OFONO_HISTORY_INTERFACE "com.meego.TelephonyHistory"
+
+struct ofono_history {
+       struct history_agent *current_agent;
+       int timeout;
+} *history;
+
+
+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
+ */
+
+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);
+       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
+ */
+
+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;
+
+       struct history *v = g_try_new0(struct history, 1);
+       if (!v)
+               return;
+       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);
+       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);
+       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);
+       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);
+       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"
+#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;
+};
+
+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)
+{
+       DBusConnection *conn = ofono_dbus_get_connection();
+       struct history_agent *agent = g_try_new0(struct history_agent, 1);
+       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;
+       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);
+       }
+       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";
+       }
+}
+
+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);
-- 
1.6.3.3

_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to