Patch for merging voice call history plugin implementation
Hi, I have implemented voice call history plugin using memory mapped file , the implementation tested on meego images right now as an external plugin to ofono. I am submitting the code here so that it works as builtin plugin for ofono in future. Please review the patch and let me know if your decision. Thanks Raji Bommaraju From df8e20421beae9d0e988f506c750b5351466806f Mon Sep 17 00:00:00 2001 From: Raji Bommaraju Rajyalakshmi Bommaraju Date: Mon, 17 May 2010 11:08:58 -0700 Subject: [PATCH] Merging callhistory plugin implementation --- Makefile.am |3 + plugins/callhistory.c | 579 + 2 files changed, 582 insertions(+), 0 deletions(-) create mode 100644 plugins/callhistory.c diff --git a/Makefile.am b/Makefile.am index 7fd862f..71d2440 100644 --- a/Makefile.am +++ b/Makefile.am @@ -239,6 +239,9 @@ 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 000..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_PATHvoicecallhistorydata +#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
[PATCH] Added implementation for ReportVoiceCall, ReportTextMessage, Release methods and related code.Please take a look and give me feedback on the code quality , thinks that need to be changed
--- 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 000..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_PATHofonohistorydata +#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:
File Structure for persisting history in a disk file (Comments please)
Hello, I want to use the following file structure for persisting history in a disk file. Can you please send me your feedback about it. Thanks Raji Bommaraju _File structure for History Persistance_ History information will be stored in a disk file. The file will have a File Header consisting of Bytes Stored and Head for writing the next record.Each record stored will have record header and record data, record header has record type and size of the record (For Text messages the records will have variable length message data resulting in variable length records) hence this record structure is used. *File Format:* |File Header| Data | File Header (8 bytes): |Bytes stored | Head| 048 *Data:* |Record|Record|.etc *Record:* |Record Header|Actual data| *Record Header:* Record Type: 1byte (voice call history - 0, text history- 1) Size : Integer Actual data: Will be voice call or text message information ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono
Re: Please comment on callhistory API
Marcel, Marcel Holtmann wrote: Hi Raji, org.ofono.History will be the main adapter interface and org.ofono.CallHistoryAgent the callhistory agent and org.ofono.SmsHistoryAgent as the sms history agent. I want to seperate the two agents so that sms app will expose sms history agent and dialer will register and expose callhistory agent. Then it will be clear which agent is interested in which history, vs one org.ofono.HistoryAgent exposing ReportCall and ReportTextMessage methods. In the later case adapter needs to flush both smshistory and callsistory onto two agents even though agents are not interested only in type of history. actually not really. So why does the dialer and SMS application need to register for the history? Isn't that going to be stored central in Tracker or something similar. Should not be Tracker or some Tracker helper be registering the agent? No, Dialer and Sms applications are the ones that read and stores locally, this will probably move to tracker eventually. So I dont think we can assume that there is going to be a tracker agent. I might be wrong, but does it really make sense to separate it on this level? I am thinking by separating the applications will only register and get data they are interested in. so Denis and I had a long chat about this. And essentially the history agent concept is not really something that we should maintain long term. We need be able to Tracker to listen on the D-Bus system bus and have oFono history plugin send data directly to Tracker. The history plugin should track if Tracker is running or not. If not spool. Otherwise send data to Tracker directly. Everything else is a pretty much complicated design. However for a short term solution, you could do a history agent concept as part of a MeeGo specific plugin. So use org.ofono as D-Bus service name and com.meego.TelephonyHistory and com.meego.TelephonyHistoryAgent as interface names. The main object path is / since are not going to make this based on a per modem. Two method calls in the agent a) ReportVoiceCall a) ReportTextMessage and that is it in. In the info dict include the Modem property which points to the modem object this information originates from. For outgoing TextMessages, ofono updates the history plugin in two method calls, first all the text message history related properties msg id, message , local received time,actual sent time, lineid and status='Pending' and in another method ofono updates plugin with the status. Earlier design, I sent out history record with pending status and when I received status update I used 'property changed' signal for status update. But I use 'uint32,variant' type which is not consistent with the current ofono property changed signal type. My questions, 1) Are you ok with using signal for status update, this lets us send out history as soon as we receive them if the agent is running 2) If we want to avoid signal, then we can store the outgoing text message record until we receive the status update from ofono, combine them and send out in case of agent running. In case of agent not running we do this anyway. Updated API is below. History hierarchy Service : org.ofono Interface : com.meego.TelephonyHistory Object path : / Methods void RegisterAgent (objectpath) RegisterAgent method registers the agent object path. Methods on this agent will be called if history needs to push data. Possible Errors: [service].Error.InvalidArguments [service].Error.InvalidFormat [service].Error.InUse void UnregisterAgent (objectpath) UnregisterAgent method unregister the already registered agent object path. Possible Errors: [service].Error.InvalidArguments [service].Error.InvalidFormat [service].Error.InUse HistoryAgent hierarchy == Service Name : Unique Name Interface : com.meego.TelephonyHistoryAgent Objectpath : Freely definable Methods void ReportTextMessage( array{dict}) This method gets called by ofono to deliver an array of records. Each record is represented as a dictionary, all the dict properties are described in the Properties section. Possible Errors: [service].Error.Failed void ReportVoiceCall( array{dict}) This method gets called by ofono to deliver an array of records. Each record is represented as a dictionary, all the dict properties are described in the Properties section. Possible Errors: [service].Error.Failed void Release() Cleans up agent, assumes that agent is already unregistered, so not needed to unregister. Properties == uint32 Uid [Read Only] Integer representing the internal representation of histroy message id. string Type [Read Only] string representing the type of the history message. Type can be one of the following three alternatives. outgoing - it is an outgoing history message incoming - it
Re: Please comment on callhistory API
Marcel, Marcel Holtmann wrote: Hi Raji, this is the second time I have to remind you to not top post. Next time I will ignore your email. Just a friendly reminder to follow proper mailing list etiquette. org.ofono.History will be the main adapter interface and org.ofono.CallHistoryAgent the callhistory agent and org.ofono.SmsHistoryAgent as the sms history agent. I want to seperate the two agents so that sms app will expose sms history agent and dialer will register and expose callhistory agent. Then it will be clear which agent is interested in which history, vs one org.ofono.HistoryAgent exposing ReportCall and ReportTextMessage methods. In the later case adapter needs to flush both smshistory and callsistory onto two agents even though agents are not interested only in type of history. actually not really. So why does the dialer and SMS application need to register for the history? Isn't that going to be stored central in Tracker or something similar. Should not be Tracker or some Tracker helper be registering the agent? No, Dialer and Sms applications are the ones that read and stores locally, this will probably move to tracker eventually. So I dont think we can assume that there is going to be a tracker agent. I might be wrong, but does it really make sense to separate it on this level? I am thinking by separating the applications will only register and get data they are interested in. so Denis and I had a long chat about this. And essentially the history agent concept is not really something that we should maintain long term. We need be able to Tracker to listen on the D-Bus system bus and have oFono history plugin send data directly to Tracker. The history plugin should track if Tracker is running or not. If not spool. Otherwise send data to Tracker directly. Everything else is a pretty much complicated design. However for a short term solution, you could do a history agent concept as part of a MeeGo specific plugin. So use org.ofono as D-Bus service name and com.meego.TelephonyHistory and com.meego.TelephonyHistoryAgent as interface names. The main object path is / since are not going to make this based on a per modem. Two method calls in the agent a) ReportVoiceCall a) ReportTextMessage and that is it in. In the info dict include the Modem property which points to the modem object this information originates from. For outgoing TextMessages, ofono updates the history plugin in two method calls, first all the text message history related properties msg id, message , local received time,actual sent time, lineid and status='Pending' and in another method ofono updates plugin with the status. Earlier design, I sent out history record with pending status and when I received status update I used 'property changed' signal for status update. But I use 'uint32,variant' type which is not consistent with the current ofono property changed signal type. My questions, 1) Are you ok with using signal for status update, this lets us send out history as soon as we receive them if the agent is running 2) If we want to avoid signal, then we can store the outgoing text message record until we receive the status update from ofono, combine them and send out in case of agent running. In case of agent not running we do this anyway. Failure of not existing a) or b) should be handled gracefully so that in the first error case we don't retry anymore. Regards Marcel ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono
Re: Please comment on callhistory API
Marcel, org.ofono.History will be the main adapter interface and org.ofono.CallHistoryAgent the callhistory agent and org.ofono.SmsHistoryAgent as the sms history agent. I want to seperate the two agents so that sms app will expose sms history agent and dialer will register and expose callhistory agent. Then it will be clear which agent is interested in which history, vs one org.ofono.HistoryAgent exposing ReportCall and ReportTextMessage methods. In the later case adapter needs to flush both smshistory and callsistory onto two agents even though agents are not interested only in type of history. Does it sound reasonable? Thanks, Raji Marcel Holtmann wrote: Hi Raji, CallHistory hierarchy = Service : org.ofono Interface : org.ofono.CallHistory Object path : [variable prefix]/{modem0,modem1,...}/CallHistory the object path is wrong here. This should be pretty much on the main / object path. And not on per modem and not in a sub-path. I really don't think that per modem history makes sense. Denis? Methods void RegisterAgent (objectpath) RegisterAgent method registers the agent object path. Methods on this agent will be called if history needs to push data. Possible Errors: [service].Error.InvalidArguments [service].Error.InvalidFormat [service].Error.InUse void UnregisterAgent (objectpath) UnregisterAgent method unregister the already registered agent object path. Possible Errors: [service].Error.InvalidArguments [service].Error.InvalidFormat [service].Error.InUse CallHistoryAgent hierarchy Service Name : Unique Name Interface : org.ofono.CallHistoryAgent Objectpath : Freely definable So I am actually thinking this should be just History and HistoryAgent interfaces. Since we can differentiate between different types by the different methods in the agent. Methods void SendHistory( array{dict}) This method gets called by ofono to deliver an array of records. Each record is represented as a dictionary, all the dict properties are described in the Properties section. Possible Errors: [service].Error.Unsuccessful We have to do some semantical things here first. So you proposal here is to do org.ofono.CallHistoryAgent.SendHistory. The History part is used twice here. That is never a good idea. Also it is not really sending a history per se. It is more reporting one and just one at a time. So it is not history it reports, it is a call. So my proposal here is just to have one method for ReportCall and another one for ReportTextMessage etc. void Release() Cleans up agent, assumes that agent is already unregistered, so not needed to unregister. Properties === integer Uid [Read Only] Integer representing the unique id of the history record In this case I would prefer UID as value and in uint32 please. D-Bus doesn't have an integer type. Also do we actually need this? Denis? string Calltype [Read Only] string representing the call type. Call type can be one of the following three alternatives outgoing - it is an outgoing call incoming - it is an incoming call missed - it is a missed call If is is the call history dict then just Type is good enough. No idea to duplicate the work Call all over the place. string LineIdentification [Read Only] string representing the LineIdentification , for outgoing call it is the phone number dialed. For Incoming call it is the CLIP, or COLP if received by the underlying implementation. string StartTime [Read Only] String representing start time of the call string EndTime [Read Only] String representing end time of the call These looks fine. Regards Marcel ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono
Re: Please comment on callhistory API
Hello Marcel, Marcel Holtmann wrote: Hi Raji, this is the second time I have to remind you to not top post. Next time I will ignore your email. Just a friendly reminder to follow proper mailing list etiquette. org.ofono.History will be the main adapter interface and org.ofono.CallHistoryAgent the callhistory agent and org.ofono.SmsHistoryAgent as the sms history agent. I want to seperate the two agents so that sms app will expose sms history agent and dialer will register and expose callhistory agent. Then it will be clear which agent is interested in which history, vs one org.ofono.HistoryAgent exposing ReportCall and ReportTextMessage methods. In the later case adapter needs to flush both smshistory and callsistory onto two agents even though agents are not interested only in type of history. actually not really. So why does the dialer and SMS application need to register for the history? Isn't that going to be stored central in Tracker or something similar. Should not be Tracker or some Tracker helper be registering the agent? No, Dialer and Sms applications are the ones that read and stores locally, this will probably move to tracker eventually. So I dont think we can assume that there is going to be a tracker agent. I might be wrong, but does it really make sense to separate it on this level? I am thinking by separating the applications will only register and get data they are interested in. And it needs to be MessageHistoryAgent if we decide to go for this. We banned the shortcut sms from the rest of the API. Regards Marcel ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono
Re: Please comment on callhistory API
Hello Marcel, I have incorporated your feedback into the document . Please let me know if anything needs to be changed. Thanks Raji Callhistory Adapter-Agent CallHistory is a built in plugin for ofono. It uses CallHistoryAgent api exposed by client to push voice call history information. CallHistoryAgent api is a service interface exposed by client over dbus. Plugin exposes CallHistory interface that CallHistoryAgent registers and unregisters with. if the CallHistoryAgent registers with CallHistory then plugin pushes the history information to the agent soon as it receives from ofono, otherwise it caches the data in a disk file until agent registers, once agent registers plugin will read the data from the disk file and pushes all the records to it. CallHistory: it is going to register and unregister the agent. It calls the methods on the agent for delivering history information whent the agent is up and running. The history record will be written to the disk if agent method returns error or if the agent is not running. CallHistory hierarchy = Service : org.ofono Interface : org.ofono.CallHistory Object path : [variable prefix]/{modem0,modem1,...}/CallHistory Methods void RegisterAgent (objectpath) RegisterAgent method registers the agent object path. Methods on this agent will be called if history needs to push data. Possible Errors: [service].Error.InvalidArguments [service].Error.InvalidFormat [service].Error.InUse void UnregisterAgent (objectpath) UnregisterAgent method unregister the already registered agent object path. Possible Errors: [service].Error.InvalidArguments [service].Error.InvalidFormat [service].Error.InUse CallHistoryAgent hierarchy Service Name : Unique Name Interface : org.ofono.CallHistoryAgent Objectpath : Freely definable Methods void SendHistory( array{dict}) This method gets called by ofono to deliver an array of records. Each record is represented as a dictionary, all the dict properties are described in the Properties section. Possible Errors: [service].Error.Unsuccessful void Release() Cleans up agent, assumes that agent is already unregistered, so not needed to unregister. Properties === integer Uid [Read Only] Integer representing the unique id of the history record string Calltype [Read Only] string representing the call type. Call type can be one of the following three alternatives outgoing - it is an outgoing call incoming - it is an incoming call missed - it is a missed call string LineIdentification [Read Only] string representing the LineIdentification , for outgoing call it is the phone number dialed. For Incoming call it is the CLIP, or COLP if received by the underlying implementation. string StartTime [Read Only] String representing start time of the call string EndTime [Read Only] String representing end time of the call ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono
Please comment on callhistory API
Hello, Attached Callhistory API , please send me your feedback on it, I will extend this include SmsHistory once callhistory API looks good. Thanks Raji Callhistory Adapter-Agent CallHistoryAdapter is a built in plugin for ofono. It uses CallHistoryAgent api exposed by dialer or client daemon to push voice call history information to client. CallHistoryAgent api is an service interface exposed by client over dbus. Plugin exposes CallHistoryAdapter interface that CallHistoryAgent registers and unregisters with. if the CallHistoryAgent registers with Adapter then plugin pushes the history information to dialer as soon as it receives from ofono, otherwise it caches the data in a disk file until agent registers, once agent registers plugin will read the data from the disk file and pushes all the records to it. Adapter: it is going to register and unregister the agent. Calls the methods on the agent for delivering history information whent the agent is up and running. If the record cant be delivered that means agent method returns an error then it will be written to the disk file. If the agent is down it will persist history record in disk file. CallHistoryAdapter hierarchy Service : org.ofono Interface : org.ofono.CallHistoryAdapter Object path : freely definable Methods void RegisterAgent (objectpath) RegisterAgent method registers the agent object path. Methods on this agent will be called if history needs to push data. Possible Errors: [service].Error.InvalidArguments [service].Error.InvalidFormat [service].Error.InUse void UnregisterAgent (objectpath) UnregisterAgent method unregister the already registered agent object path. Possible Errors: [service].Error.InvalidArguments [service].Error.InvalidFormat [service].Error.InUse CallHistoryAgent hierarchy == Service Name: Unique Name Interface : org.ofono.CallHistoryAgent Objectpath : Freely definable Methods void SendHistory(array {struct {uint32,uint32,uint8,uint32,uint32} }) This method gets called by ofono to deliver one record of voice call history. Possible Errors: [service].Error.Unsuccessful void SendCachedHistory(array {struct {uint32,uint32,uint8,uint32,uint32} }) This method gets called by the ofono when CallHistoryAgent starts running. It delivers all the history records as an array of structures. Possible Errors: [service].Error.Unsuccessful void Release() Cleans up agent, assumes that agent is already unregistered, so not needed to unregister. CallHistory Record CallHistoryRecord { uint32 uid; uint8 voicecalltype; charlineid[20]; uint32 starttime; uint32 endtime; } voicecalltype { outgoing = 0, incoming = 1, missed = 2 } ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono
[PATCH] plugins: Adding implementation for persisting voice call history
--- Makefile.am |3 + plugins/callhistory.c | 594 + 2 files changed, 597 insertions(+), 0 deletions(-) create mode 100644 plugins/callhistory.c diff --git a/Makefile.am b/Makefile.am index aa66907..1b7f4d4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -261,6 +261,9 @@ builtin_sources += plugins/ste.c builtin_modules += caif builtin_sources += plugins/caif.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 000..1579652 --- /dev/null +++ b/plugins/callhistory.c @@ -0,0 +1,594 @@ +/* + * + * 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_PATHvoicecallhistorydata +#define OFONO_MANAGER_PATH / +#define PHONE_NUMBER_SIZE 64 +#define RECORD_SIZE 78 +#define HEADER_SIZE 16 +#define MAX_ITEMS 50 + +#define TOTAL_SIZE (MAX_ITEMS * RECORD_SIZE + HEADER_SIZE) + +enum VOICE_CALL_TYPE { + OUTGOING = 0, + INCOMING, + MISSED +}; + +struct file_header { + int head; + int tail; + int unread; + unsigned int lastid; +}; + +struct voice_history { + int id; + char lineid[PHONE_NUMBER_SIZE]; + short int calltype; + time_t starttime; + time_t endtime; +}; + +struct shared_info { + struct file_header header; + void *dataMap; + sem_t mutex; + int temp_unread; + int temp_tail; +}; + +static struct shared_info *shared_data; + +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; +} + +/* 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); + +
Patch for merging voicecallhistory plugin implementation
Call History Plugin Introduction: Callhistory is a plugin loaded by ofono for persisting voice call history information in a disk file. Plugin exports dbus methods and signals as org.ofono.callhistory interface. Whenever there is a voice call in the system, ofono calls the plugin with the infomation (lineid,calltype,start time, end time) , plugin writes the information is written to the file , increments the 'unread' field in the header and sends out dbus signal with the number of unread records. Client (dialer) requests history records by calling method GetVoiceHistory exposed on the callhistory interface. After receiving information client calls the SetVoiceHistoryRead as an acknowledgement to indicate end of transaction. The pointers in the header are adjusted appropriately (explained clearly below). Design : Plugin uses memory mapped file for high performance input/output operations. File is used as cyclic queue for storing or reading records, it store s 50 records of 78bytes,hence fixed size file of 3916 bytes is used. File's first 16 bytes were used for storing header, and next 3900 bytes for data. Header structure has head pointer, tail pointer,unread and lastid. Head pointer points to next slot for writing record into,tail for reading record, unread for number of history records unread by client, lastid for id of the last record that is written. Below is the file structure: (3916 bytes) |Header|Data| 0 16 Header Structure: (16 bytes) |head|tail|unread|lastid| 048 12 16 head : Points to next slot for writing tail : Points to next record to be read unread : Number of Unread records so far lastid : Number of the record that is last written Below is the structure of the history record: History Record:(78 bytes) |id|lineid|calltype|start time|end time| id : Record id lineid : phone Number calltype : Outgoing/Incoming/Missed start time: start time in UTC end time: end time in UTC When the plugin is loaded by the ofono, it opens or creates a disk file of 3916 bytes size and maps it into fixed size memory space. Plugin reads the header of the file , if the 'unread' records is 0 , a signal is sent out on the dbus with the information of number of unread records. Requesting data by client: When the client calls GetVoiceHistory method,plugin uses temp_tail and temp_unread variables to accomplish reads and copying data into dbus structure. It copies tail pointer of the header into temporary tail pointer and starts to read history records one at a time from the location pointed by the temp tail pointer , copies the structure it to the dbus structure, increments the temp tail pointer by size of the history record (78 bytes) and reads data from the next record location , this is repeated until it reaches head pointer. when all the unread records are packed as dbus structure it is sent to the client. Once the data received, client needs to SetVoiceHistoryRead method to indicate that it received the data. Plugin will write the tail pointer with the temp tail pointer and unread records number is decremented by temp_unread. Using temp_tail and temp_unread variables protect from modifying the header if there is any loss in data delivery. If client doesnt call 'SetVoi ceHistoryRead' then the actual header pointers wont be updated in the file. Writing record into the file: When Ofono calls the plugin with call information (phone number, call type, call start time , call end time), plugin increaments the lastid to create record id for this record ,writes the record in the location pointed by head, and the head pointer is incremented by size of record (78 bytes), unread variable is incremented by 1. If the head reaches end of file (3916) then it is reset it back to begining of the data portion of the file (16 bytes). A dbus signal is sent out with number of current unread records. Plugin keeps writing the records in circular queue. Locking: Accessing Memory mapped file pointer , all header fields (head,tail,unread,lastid), temp_unread,temp_tail are synchronized by a mutex. writing into memory file and reading from memory file happen asynchronously, so mutex is used to protect the memory mapped file pointer , header, temp_unread, temp_tail. Limitations: History is limited to storing 50 records. The above design assumes that there is only one client (either dialer or a history daemon) that reads data and sends acknowledgemnts. ___ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono
[PATCH] plugins: Adding implementation for voice call history plugin
--- Makefile.am |3 + plugins/callhistory.c | 582 + 2 files changed, 585 insertions(+), 0 deletions(-) create mode 100644 plugins/callhistory.c diff --git a/Makefile.am b/Makefile.am index 802e94b..4471aef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -261,6 +261,9 @@ builtin_sources += plugins/ste.c builtin_modules += caif builtin_sources += plugins/caif.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 000..71feecd --- /dev/null +++ b/plugins/callhistory.c @@ -0,0 +1,582 @@ +/* + * + * 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_PATHvoicecallhistorydata +#define OFONO_MANAGER_PATH / +#define PHONE_NUMBER_SIZE 64 +#define RECORD_SIZE 78 +#define HEADER_SIZE 16 +#define MAX_ITEMS 50 + +#define TOTAL_SIZE (MAX_ITEMS * RECORD_SIZE + HEADER_SIZE) + +enum VOICE_CALL_TYPE { + OUTGOING = 0, + INCOMING, + MISSED +}; + +struct file_header { + int head; + int tail; + int unread; + unsigned int lastid; +}; + +struct voice_history { + int id; + char lineid[PHONE_NUMBER_SIZE]; + short int calltype; + time_t starttime; + time_t endtime; +}; + +struct shared_info { + struct file_header header; + void *dataMap; + sem_t mutex; + int temp_unread; + int temp_tail; +}; + +static struct shared_info *shared_data; + +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; +} + +/* 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); + +
Patch for voice call history plugin merge
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 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 000..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_PATHvoicecallhistorydata +#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