From: rajyalakshmi bommaraju <rajyalakshmi.bommaraju@intel.com>
To: ofono@ofono.org
Subject: Patch for voice call history plugin merge
Date: Tue, 18 May 2010 09:51:25 -0700 [thread overview]
Message-ID: <4BF2C58D.6090901@intel.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 423 bytes --]
Hi,
I have implemented voice call history plugin using memory mapped file ,
this implementation tested on meego images right now as an external
plugin to ofono. I am submitting the code here so that it can be merged and will be used as builtin plugin of ofono in future. Please review the patch and let
me know your decision and any changes that needs to be done for accepting it.
Thanks
Raji Bommaraju
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Merging-voice-call-history-plugin-implementation.patch --]
[-- Type: text/x-patch, Size: 15909 bytes --]
>From 6f9ac5dc8b6fe9bd9226cd63803bfcabd9978219 Mon Sep 17 00:00:00 2001
From: Raji Bommaraju <Rajyalakshmi Bommaraju>
Date: Tue, 18 May 2010 09:53:09 -0700
Subject: [PATCH] Merging voice call history plugin implementation
---
Makefile.am | 2 +
plugins/callhistory.c | 579 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 581 insertions(+), 0 deletions(-)
create mode 100644 plugins/callhistory.c
diff --git a/Makefile.am b/Makefile.am
index 7fd862f..d2f1aa1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -239,6 +239,8 @@ builtin_sources += plugins/palmpre.c
builtin_modules += ste
builtin_sources += plugins/ste.c
+builtin_modules += callhistory
+builtin_sources += plugins/callhistory.c
endif
if MAINTAINER_MODE
diff --git a/plugins/callhistory.c b/plugins/callhistory.c
new file mode 100644
index 0000000..3dce3c2
--- /dev/null
+++ b/plugins/callhistory.c
@@ -0,0 +1,579 @@
+/*
+ *
+ * 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 <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <glib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include <sys/mman.h>
+#include <semaphore.h>
+#include <fcntl.h>
+#include <ofono/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <ofono/types.h>
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/history.h>
+#include "gdbus.h"
+#include "common.h"
+
+#define HISTORY_FILE_PATH "/var/cache/callhistory/"
+#define HISTORY_FILE HISTORY_FILE_PATH"voicecallhistorydata"
+#define OFONO_MANAGER_PATH "/"
+#define PHONE_NUMBER_SIZE 64
+#define RECORD_SIZE 80
+#define HEADER_SIZE 16
+
+#ifdef NUM_VCALL_HISTORY_ENTRIES
+#define MAX_ITEMS NUM_VCALL_HISTORY_ENTRIES
+#else
+#define MAX_ITEMS 50
+#endif
+
+#define TOTAL_SIZE (MAX_ITEMS * RECORD_SIZE + HEADER_SIZE)
+
+enum VOICE_CALL_TYPE {
+ OUTGOING = 0,
+ INCOMING,
+ MISSED
+};
+
+typedef struct _FILEHEADER {
+ int head;
+ int tail;
+ int unread;
+ unsigned int lastid;
+} HistoryFileHeader;
+
+typedef struct _VOICEHISTORY {
+ int id;
+ char lineid[PHONE_NUMBER_SIZE];
+ short int calltype;
+ time_t starttime;
+ time_t endtime;
+} VoiceHistory;
+
+// Global Shared data
+typedef struct _SHARED
+{
+ HistoryFileHeader header;
+ void *dataMap;
+ sem_t mutex;
+ int temp_unread;
+ int temp_tail;
+} SharedData;
+
+static SharedData *shared_data = NULL;
+
+
+static void callhistory_emit_voice_history_changed(int );
+
+static int call_history_probe(struct ofono_history_context *context)
+{
+ DBG("History Probe for modem: %p", context->modem);
+ return 0;
+}
+
+static void call_history_remove(struct ofono_history_context *context)
+{
+ DBG("Example History Remove for modem: %p", context->modem);
+}
+
+static void clean_up()
+{
+ g_return_if_fail(shared_data!= NULL);
+
+ sem_wait(&(shared_data->mutex));
+ // unmap
+ munmap(shared_data->dataMap,TOTAL_SIZE);
+ sem_post(&(shared_data->mutex));
+
+ // remove semaphore
+ if (sem_destroy(&(shared_data->mutex)) < 0)
+ perror("sem_destroy failed");
+
+ g_free(shared_data);
+}
+
+
+static int init_sem()
+{
+ unsigned int value = 1;
+ g_return_val_if_fail(shared_data!= NULL,-1);
+
+ if (sem_init(&(shared_data->mutex), TRUE, value) < 0){
+ perror("sem_init failed");
+ return -1;
+ }
+ return 0;
+}
+
+static int init_header(void *dataPtr)
+{
+ int unread = 0;
+
+ g_return_val_if_fail((shared_data!=NULL), -1);
+ g_return_val_if_fail((dataPtr!=NULL), -1);
+ unread = (shared_data->header).unread;
+
+ sem_wait(&(shared_data->mutex));
+ memcpy(&(shared_data->header), (HistoryFileHeader *)(dataPtr),
+ HEADER_SIZE);
+
+ ofono_debug("Unread: %d, Header: %d, Tail: %d, serialno: %d\n",
+ unread,
+ (shared_data->header).head,
+ (shared_data->header).tail,
+ (shared_data->header).lastid);
+ sem_post(&(shared_data->mutex));
+ if (unread > 0){
+ callhistory_emit_voice_history_changed(unread);
+ }
+ return 0;
+}
+
+/**
+ * Creates file "callhistory"
+ */
+static gboolean init_file()
+{
+ int historyFile;
+ struct stat statbuf;
+ DIR *dirptr;
+ char *fill = NULL;
+
+ g_return_val_if_fail((shared_data!=NULL), FALSE);
+
+ if (!(dirptr = opendir(HISTORY_FILE_PATH)) ){
+ ofono_debug("%s: doesnt exist",HISTORY_FILE_PATH);
+ if (mkdir(HISTORY_FILE_PATH,
+ S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0){
+ perror("Error creating callhistory dir");
+ return FALSE;
+ }
+ }
+
+ if ((historyFile = open( HISTORY_FILE,
+ O_RDWR|O_CREAT|O_APPEND,
+ S_IRWXU))
+ < 0){
+ perror("Open file failed");
+ return FALSE;
+ }
+
+ if (stat( HISTORY_FILE,&statbuf) < -1){
+ perror("stat failed");
+ return FALSE;
+ }
+ ofono_debug("stat file: %d",(int) (statbuf.st_size));
+
+ if (statbuf.st_size == 0){
+ int byteswritten = 0;
+ //write header to the file
+ (shared_data->header).head=HEADER_SIZE;
+ (shared_data->header).tail=(shared_data->header).head;
+ (shared_data->header).unread=0;
+ ofono_debug("setting head: %d,tail: %d,unread: %d",
+ (shared_data->header).head,
+ (shared_data->header).tail,
+ (shared_data->header).unread);
+
+ // fill the file with zeros
+ ofono_debug("Trying to allocate %d size",TOTAL_SIZE);
+ fill = (char *) g_try_malloc0(TOTAL_SIZE);
+ if (!fill ){
+ ofono_debug("Error allocating init memory");
+ return FALSE;
+ }
+
+ // Predefine file size and fill with some data
+ bzero(fill,TOTAL_SIZE);
+ memcpy(fill,&(shared_data->header), HEADER_SIZE);
+
+ if ((byteswritten = write (historyFile,fill, TOTAL_SIZE)) <0){
+ ofono_debug("Error writing to file");
+ return FALSE;
+ }
+ g_free(fill);
+
+ statbuf.st_size = TOTAL_SIZE;
+ ofono_debug("History file %d size created \n",byteswritten);
+ }
+ // create semaphore
+ if (init_sem() < 0)
+ return FALSE;
+
+ sem_wait(&(shared_data->mutex));
+ shared_data->dataMap = mmap(( caddr_t)NULL,
+ statbuf.st_size,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_SHARED,
+ historyFile,
+ 0);
+ sem_post(&(shared_data->mutex));
+ if (shared_data->dataMap == (void *)(-1)){
+ perror("mmap falied");
+ return FALSE;
+ }
+
+ close(historyFile);
+
+ init_header(shared_data->dataMap);
+
+ return TRUE;
+}
+
+static void sync_mem_file(VoiceHistory *vcall){
+ void *writeMap = NULL;
+ int unread = 0;
+
+ g_return_if_fail(vcall != NULL);
+ g_return_if_fail(shared_data != NULL);
+ g_return_if_fail(shared_data->dataMap != NULL);
+
+ sem_wait(&(shared_data->mutex));
+
+ writeMap = shared_data->dataMap;
+ writeMap = writeMap + (shared_data->header).head;
+ vcall->id = (shared_data->header).lastid;
+ (shared_data->header).lastid++;
+ memcpy(writeMap, vcall, RECORD_SIZE);
+
+ // update header
+ ((shared_data->header).unread)++;
+ (shared_data->header).head += RECORD_SIZE;
+ if ((shared_data->header).lastid >= UINT_MAX)
+ (shared_data->header).lastid = 0;
+
+ unread = (shared_data->header).unread;
+
+ //header reaches end of file
+ if ((shared_data->header).head >= TOTAL_SIZE){
+ //reset head back to front
+ (shared_data->header).head = HEADER_SIZE;
+
+ ofono_debug("Header = %d, Tail=%d",
+ (shared_data->header).head,
+ (shared_data->header).tail);
+
+ if (unread >= MAX_ITEMS)
+ ofono_error("No one reading history data");
+ }
+
+ memcpy(shared_data->dataMap,&(shared_data->header),HEADER_SIZE);
+ msync(shared_data->dataMap, TOTAL_SIZE, MS_ASYNC);
+
+ sem_post(&(shared_data->mutex));
+
+ if (unread > 0)
+ callhistory_emit_voice_history_changed(unread);
+
+}
+
+/**
+ * call_history_call_ended:
+ * ofono calls this method with the call information
+ */
+
+static void call_history_call_ended(struct ofono_history_context *context,
+ const struct ofono_call *call,
+ time_t start,
+ time_t end)
+{
+ const char *from = "Unknown";
+ struct tm tmstart, tmend;
+ char sttime[128], endtime[128];
+ int fromlen = 0;
+ VoiceHistory vcall;
+
+ ofono_debug("Call Ended on modem: %p", context->modem);
+
+ if (call->type != 0)
+ return;
+ ofono_debug("Voice Call, %s",
+ call->direction ? "Incoming" : "Outgoing");
+
+ if (call->direction)
+ vcall.calltype = INCOMING;
+ else
+ vcall.calltype = OUTGOING;
+
+ if (call->clip_validity == 0)
+ from = phone_number_to_string(&call->phone_number);
+ fromlen = strlen(from);
+ strcpy(vcall.lineid, from);
+ vcall.lineid[fromlen] = '\0';
+
+ vcall.starttime = start;
+ gmtime_r(&start, &tmstart);
+ strftime(sttime, 127, "%a, %d %b %Y %H:%M:%S %z", &tmstart);
+ sttime[127] = '\0';
+
+ ofono_debug("StartTime: %s",sttime);
+
+ vcall.endtime = end;
+ gmtime_r(&end, &tmend);
+ strftime(endtime, 127, "%a, %d %b %Y %H:%M:%S %z", &tmend);
+ endtime[127] = '\0';
+ ofono_debug("EndTime: %s",endtime);
+
+ sync_mem_file(&vcall);
+}
+
+/**
+ * call_history_call_missed:
+ * ofono calls this method with the call information
+ */
+static void call_history_call_missed(struct ofono_history_context *context,
+ const struct ofono_call *call,
+ time_t when)
+{
+ const char *from = "Unknown";
+ struct tm mtime;
+ char sttime[128];
+ VoiceHistory vcall;
+ int fromlen = 0;
+
+ ofono_debug("Call Missed on modem: %p", context->modem);
+
+ if (call->type != 0)
+ return;
+
+ ofono_debug("Voice Call, Missed");
+ ofono_debug("Voice Call, %s",
+ call->direction ? "Incoming" : "Outgoing");
+
+ vcall.calltype = MISSED;
+
+ if (call->clip_validity == 0)
+ from = phone_number_to_string(&call->phone_number);
+
+ fromlen = strlen(from);
+ strncpy(vcall.lineid, from ,fromlen);
+ vcall.lineid[fromlen] = '\0';
+
+ vcall.starttime = when;
+
+ gmtime_r(&when, &mtime);
+ ofono_debug("From: %s", vcall.lineid);
+ strftime(sttime, 127, "%a, %d %b %Y %H:%M:%S %z", &mtime);
+ sttime[127] = '\0';
+ ofono_debug("Missed Time: %s", sttime);
+
+ vcall.endtime = when;
+
+ sync_mem_file(&vcall);
+}
+
+
+/* Start of DBus stuff */
+/* *************************************************************************
+ * Expose an interface, properties and signals for querying storage backend
+ * *************************************************************************/
+#define OFONO_CALL_HISTORY_INTERFACE OFONO_SERVICE".CallHistory"
+
+static void callhistory_emit_voice_history_changed(int userdata)
+{
+ int *valint = &userdata;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ g_dbus_emit_signal(conn,
+ OFONO_MANAGER_PATH,
+ OFONO_CALL_HISTORY_INTERFACE,
+ "VoiceHistoryChanged",
+ DBUS_TYPE_UINT32,
+ valint,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *call_history_set_voice_history_read(DBusConnection *conn,
+ DBusMessage *msg,
+ void *userdata)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ g_return_val_if_fail((shared_data!=NULL), NULL);
+
+ ofono_debug("Read ack received");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ sem_wait(&(shared_data->mutex));
+ shared_data->header.unread = (shared_data->header).unread -
+ shared_data->temp_unread;
+ shared_data->header.tail = shared_data->temp_tail;
+
+ // write to file
+ memcpy(shared_data->dataMap,&(shared_data->header),HEADER_SIZE);
+ sem_post(&(shared_data->mutex));
+ msync(shared_data->dataMap,TOTAL_SIZE, MS_ASYNC);
+ return reply;
+}
+
+static void read_data(VoiceHistory *data,int temp)
+{
+ void *readMap = NULL;
+ g_return_if_fail(shared_data != NULL);
+ g_return_if_fail(shared_data->dataMap != NULL);
+
+ // lock
+ sem_wait(&(shared_data->mutex));
+ readMap = shared_data->dataMap+temp;
+ // read a chunk into *data
+ memcpy(data, readMap,RECORD_SIZE);
+ shared_data->temp_unread++;
+ sem_post(&(shared_data->mutex));
+}
+
+static DBusMessage *call_history_get_voice_history(DBusConnection *conn,
+ DBusMessage *msg,
+ void *userdata)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array,struct_s;
+ int i;
+ char *lineid;
+ VoiceHistory data;
+ int unread = 0;
+
+ reply = dbus_message_new_method_return(msg);
+
+ if (!reply)
+ return NULL;
+ g_return_val_if_fail(shared_data!=NULL,NULL);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_UINT32_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_UINT16_AS_STRING
+ DBUS_TYPE_INT32_AS_STRING
+ DBUS_TYPE_INT32_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING
+ ,&array);
+
+ sem_wait(&(shared_data->mutex));
+ shared_data->temp_unread=0;
+ shared_data->temp_tail = (shared_data->header).tail;
+ unread = (shared_data->header).unread;
+ sem_post(&(shared_data->mutex));
+
+ for (i=0; i < unread; i++){
+ read_data(&data, shared_data->temp_tail);
+ lineid = data.lineid;
+ dbus_message_iter_open_container(&array, DBUS_TYPE_STRUCT,NULL,
+ &struct_s);
+ dbus_message_iter_append_basic(&struct_s, DBUS_TYPE_UINT32,
+ &(data.id));
+ dbus_message_iter_append_basic(&struct_s, DBUS_TYPE_STRING,
+ &(lineid));
+ dbus_message_iter_append_basic(&struct_s, DBUS_TYPE_UINT16,
+ &(data.calltype));
+ dbus_message_iter_append_basic(&struct_s, DBUS_TYPE_INT32,
+ &(data.starttime));
+ dbus_message_iter_append_basic(&struct_s, DBUS_TYPE_INT32,
+ &(data.endtime));
+ dbus_message_iter_close_container(&array, &struct_s);
+
+ shared_data->temp_tail = shared_data->temp_tail + RECORD_SIZE;
+
+ if (shared_data->temp_tail == TOTAL_SIZE){
+ ofono_debug ("End of Queue: %d",shared_data->temp_tail); // reset back to front
+ shared_data->temp_tail = HEADER_SIZE;
+ }
+ }
+ dbus_message_iter_close_container(&iter,&array);
+
+ return reply;
+}
+
+static GDBusMethodTable call_history_methods[] = {
+ { "GetVoiceHistory", "", "a(usqii)", call_history_get_voice_history },
+ { "SetVoiceHistoryRead", "", "", call_history_set_voice_history_read },
+ { }
+};
+
+static GDBusSignalTable call_history_signals[] = {
+ { "VoiceHistoryChanged","u" },
+ {}
+};
+
+/* End of DBus stuff */
+static struct ofono_history_driver call_history_driver = {
+ .name = "callhistory",
+ .probe = call_history_probe,
+ .remove = call_history_remove,
+ .call_ended = call_history_call_ended,
+ .call_missed = call_history_call_missed,
+};
+
+static int call_history_init(void)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+
+ if (!shared_data)
+ if (!(shared_data = g_try_new0(SharedData, 1)))
+ return -ENOMEM;
+
+
+ if (!g_dbus_register_interface(conn,
+ OFONO_MANAGER_PATH,
+ OFONO_CALL_HISTORY_INTERFACE,
+ call_history_methods,
+ call_history_signals,
+ NULL, /* Properties */
+ shared_data, /* Userdata */
+ NULL)) /* Destroy func */
+ return -EIO;
+
+ if (!init_file())
+ return -ENOENT;
+
+ return ofono_history_driver_register(&call_history_driver);
+}
+
+static void call_history_exit(void)
+{
+ clean_up();
+ ofono_history_driver_unregister(&call_history_driver);
+}
+
+OFONO_PLUGIN_DEFINE(callhistory, "Call History Plugin",
+ OFONO_VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
+ call_history_init, call_history_exit)
--
1.6.6.1
next reply other threads:[~2010-05-18 16:51 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-18 16:51 rajyalakshmi bommaraju [this message]
2010-06-02 18:33 ` Patch for voice call history plugin merge Denis Kenzior
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4BF2C58D.6090901@intel.com \
--to=rajyalakshmi.bommaraju@intel.com \
--cc=ofono@ofono.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.