All of lore.kernel.org
 help / color / mirror / Atom feed
* Patch for voice call history plugin merge
@ 2010-05-18 16:51 rajyalakshmi bommaraju
  2010-06-02 18:33 ` Denis Kenzior
  0 siblings, 1 reply; 2+ messages in thread
From: rajyalakshmi bommaraju @ 2010-05-18 16:51 UTC (permalink / raw)
  To: ofono

[-- 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


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: Patch for voice call history plugin merge
  2010-05-18 16:51 Patch for voice call history plugin merge rajyalakshmi bommaraju
@ 2010-06-02 18:33 ` Denis Kenzior
  0 siblings, 0 replies; 2+ messages in thread
From: Denis Kenzior @ 2010-06-02 18:33 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 3040 bytes --]

Hi Raji,

> 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.

A few general comments:
- Please submit your patches using git send-email so that they can be 
commented on inline.  This ensures that many other eyes will look at your 
patches.
- Before submitting your patches, make sure to run checkpatch.pl from the 
latest kernel to check for style issues.  Running checkpatch.pl locally gives 
me over 100 errors with your submission.
- You have to give a much better explanation for what exactly you're doing 
with the code.  For instance, why are semaphores used to protect writing of 
the call history file?  Who are you protecting from?  Give an overview of at 
least several sized paragraphs, the more the better.  Assume that nobody has 
an idea about what you're trying to accomplish and you have to educate them.

Other style issues to watch out for:
+// Global Shared data
+typedef struct _SHARED
+{
+	HistoryFileHeader header;
+	void *dataMap;
+	sem_t mutex;
+	int temp_unread;
+	int temp_tail;
+} SharedData;
+

oFono does not use CamelCase for structures, simply use struct file_header {} 
or similar.  We also don't use // style comments.

+static SharedData *shared_data = NULL;
+
+

Double empty lines are a big no no, get rid of them.

+static void callhistory_emit_voice_history_changed(int );
+

forward declarations should be avoided, particularly for static functions

+	if (unread > 0){
+		callhistory_emit_voice_history_changed(unread);
+	}

Braces for single-statement if/while/for blocks are not to be used

+         	if (!fill ){
+             		ofono_debug("Error allocating init memory");
+             		return FALSE;
+		}
+        

These lines contain mixed tab / space indentation.  Only tabs are to be used 
for indentation.

The if statement should be preceded and followed by an empty line.

+	// create semaphore
+	if (init_sem() < 0)
+		return FALSE; 
+

The return statement contains a space@the end.  All maintainers have git 
settings that will complain loudly when we try to apply such patches.  There 
are many more occurrences of this and all of them need to be fixed.

Add:

[apply]
        whitespace = error

to your gitconfig and make sure your patch applies cleanly before submitting.

+	if (unread > 0)
+		callhistory_emit_voice_history_changed(unread);
+    	
+}

Empty lines at the end of blocks are not required

For other style issues, if in doubt check existing code, it is quite 
consistent.  In general the code won't be looked at in detail until it 
conforms to the style guide.

Please fixup all these issues and resubmit.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-06-02 18:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-18 16:51 Patch for voice call history plugin merge rajyalakshmi bommaraju
2010-06-02 18:33 ` Denis Kenzior

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.