resolve TSAM-7570: add new API - msg_reg_thread_change_callback() 47/89147/9
authorKyeonghun Lee <kh9090.lee@samsung.com>
Thu, 22 Sep 2016 11:31:44 +0000 (20:31 +0900)
committerKyeonghun Lee <kh9090.lee@samsung.com>
Fri, 30 Sep 2016 09:29:05 +0000 (18:29 +0900)
Change-Id: Id21dde9a3a48f86bf807af6af18b912fc15e8c8f
Signed-off-by: Kyeonghun Lee <kh9090.lee@samsung.com>
22 files changed:
framework/plugin-manager/MsgPluginManager.cpp
framework/storage-handler/MsgStorageMessage.cpp
framework/transaction-manager/MsgCmdHandlerTransport.cpp
framework/transaction-manager/MsgTransManager.cpp
include/common/MsgCmdTypes.h
include/common/MsgPluginInterface.h
include/framework/MsgCmdHandler.h
include/framework/MsgTransManager.h
include/mapi/msg_storage.h
include/mapi/msg_storage_types.h
include/proxy/MsgHandle.h
include/proxy/MsgProxyListener.h
include/utils/MsgUtilFunction.h
mapi/msg_storage.cpp
plugin/sms_plugin/SmsPluginEventHandler.cpp
plugin/sms_plugin/SmsPluginStorage.cpp
plugin/sms_plugin/include/SmsPluginEventHandler.h
proxy/MsgHandleControl.cpp
proxy/MsgHandleStorage.cpp
proxy/MsgProxyListener.cpp
utils/MsgDebug.cpp
utils/MsgUtilFunction.cpp

index 9fd26ef..cea023e 100755 (executable)
@@ -131,6 +131,55 @@ void MsgStorageChangeListener(msg_storage_change_type_t storageChangeType, msg_i
 }
 
 
+void MsgThreadChangeListener(msg_storage_change_type_t storageChangeType, msg_thread_id_t threadId)
+{
+       MSG_BEGIN();
+
+       MSG_DEBUG("StorageChangeType : [%d], thread ID : [%d]", storageChangeType, threadId);
+
+       /* establish connection to msgfw daemon */
+       MsgIpcClientSocket client;
+       try {
+               client.connect(MSG_SOCKET_PATH);
+       } catch (MsgException& e) {
+               MSG_FATAL("%s", e.what());
+               return;
+       }
+
+       /* composing command */
+       int cmdSize = sizeof(MSG_CMD_S) + sizeof(msg_thread_id_t);
+
+       char cmdBuf[cmdSize];
+       bzero(cmdBuf, cmdSize);
+
+       MSG_CMD_S* pCmd = (MSG_CMD_S*)cmdBuf;
+
+       /* Set Command Parameters */
+       pCmd->cmdType = MSG_CMD_PLG_THREAD_CHANGE_IND;
+
+       memset(pCmd->cmdCookie, 0x00, MAX_COOKIE_LEN);
+
+       memcpy((void*)((char*)pCmd+sizeof(MSG_CMD_TYPE_T)+MAX_COOKIE_LEN), &threadId, sizeof(msg_thread_id_t));
+       memcpy((void*)((char*)pCmd+sizeof(MSG_CMD_TYPE_T)+MAX_COOKIE_LEN+sizeof(msg_thread_id_t)), &storageChangeType, sizeof(msg_storage_change_type_t));
+
+       /* Send Command to Transaction Manager */
+       client.write(cmdBuf, cmdSize);
+
+       /* Receive result from Transaction Manager */
+       MSG_DEBUG("Waiting result for STORAGE CHANGE");
+
+       char *temp = NULL;
+       unique_ptr<char*, void(*)(char**)> wrap(&temp, unique_ptr_deleter);
+       unsigned int len;
+       client.read(&temp, &len);
+
+       /* close connection to msgfw daemon */
+       client.close();
+
+       MSG_END();
+}
+
+
 msg_error_t MsgIncomingMessageListener(MSG_MESSAGE_INFO_S *pMsg)
 {
        MSG_BEGIN();
@@ -862,6 +911,7 @@ MsgPlugin::MsgPlugin(MSG_MAIN_TYPE_T mainType, const char *libPath): mSupportedM
        MSG_PLUGIN_LISTENER_S fwListener = {0};
        fwListener.pfSentStatusCb                       = &MsgSentStatusListener;
        fwListener.pfStorageChangeCb            = &MsgStorageChangeListener;
+       fwListener.pfThreadChangeCb                     = &MsgThreadChangeListener;
        fwListener.pfMsgIncomingCb                      = &MsgIncomingMessageListener;
        fwListener.pfInitSimBySatCb                     = &MsgInitSimBySatListener;
        fwListener.pfSyncMLMsgIncomingCb        = &MsgIncomingSyncMLMessageListener;
index de136bf..e5b6dbe 100755 (executable)
@@ -1013,6 +1013,10 @@ msg_error_t MsgStoDeleteMessage(msg_message_id_t msgId, bool bCheckIndication)
        }
        dbHandle->endTrans(true);
 
+       /* Update Thread Callback */
+       if (bCheckIndication == true && MsgExistConversation(dbHandle, convId) == true)
+               MsgTransactionManager::instance()->broadcastThreadChangeCB(MSG_SUCCESS, MSG_STORAGE_CHANGE_UPDATE, convId);
+
        if (msgType.mainType == MSG_SMS_TYPE && folderId == MSG_INBOX_ID) {
                msgType.classType = MSG_CLASS_NONE;
 
@@ -1039,7 +1043,7 @@ msg_error_t MsgStoDeleteAllMessageInFolder(msg_folder_id_t folderId, bool bOnlyD
 
        char sqlQuery[MAX_QUERY_LEN+1];
 
-       queue<msg_thread_id_t> threadList;
+       queue<msg_thread_id_t> threadList, threadList2;
 
 #ifdef FEATURE_SMS_CDMA
        const char *tableList[] = {MSGFW_PUSH_MSG_TABLE_NAME, MSGFW_CB_MSG_TABLE_NAME,
@@ -1081,6 +1085,7 @@ msg_error_t MsgStoDeleteAllMessageInFolder(msg_folder_id_t folderId, bool bOnlyD
        for (int i = 1; i <= rowCnt; i++) {
                MSG_DEBUG("thread ID : %d", dbHandle->getColumnToInt(i));
                threadList.push((msg_thread_id_t)dbHandle->getColumnToInt(i));
+               threadList2.push((msg_thread_id_t)dbHandle->getColumnToInt(i));
        }
 
        dbHandle->freeTable();
@@ -1306,6 +1311,15 @@ msg_error_t MsgStoDeleteAllMessageInFolder(msg_folder_id_t folderId, bool bOnlyD
 
        dbHandle->endTrans(true);
 
+       /* Update Thread Callback */
+       while (!threadList2.empty()) {
+               msg_thread_id_t cur_thread_id = threadList2.front();
+               if (MsgExistConversation(dbHandle, cur_thread_id) == true)
+                       MsgTransactionManager::instance()->broadcastThreadChangeCB(MSG_SUCCESS, MSG_STORAGE_CHANGE_UPDATE, cur_thread_id);
+
+               threadList2.pop();
+       }
+
        /* Set pMsgIdList */
        if (pMsgIdList != NULL && pToDeleteMsgIdList->nCount > 0) {
                pMsgIdList->nCount = pToDeleteMsgIdList->nCount;
@@ -1368,7 +1382,7 @@ msg_error_t MsgStoDeleteMessageByList(msg_id_list_s *pMsgIdList)
 
        char sqlQuery[MAX_QUERY_LEN+1];
 
-       queue<msg_thread_id_t> threadList1, threadList2;
+       queue<msg_thread_id_t> threadList1, threadList2, threadList3;
 
 #ifdef FEATURE_SMS_CDMA
        const char *tableList[] = {MMS_PLUGIN_MESSAGE_TABLE_NAME, MSGFW_MMS_PREVIEW_TABLE_NAME,
@@ -1451,6 +1465,7 @@ msg_error_t MsgStoDeleteMessageByList(msg_id_list_s *pMsgIdList)
                MSG_DEBUG("thread ID : %d", dbHandle->getColumnToInt(i));
                threadList1.push((msg_thread_id_t)dbHandle->getColumnToInt(i));
                threadList2.push((msg_thread_id_t)dbHandle->getColumnToInt(i));
+               threadList3.push((msg_thread_id_t)dbHandle->getColumnToInt(i));
        }
        dbHandle->freeTable();
 
@@ -1653,6 +1668,15 @@ msg_error_t MsgStoDeleteMessageByList(msg_id_list_s *pMsgIdList)
                return err;
        }
 
+       /* Update Thread Callback */
+       while (!threadList3.empty()) {
+               msg_thread_id_t cur_thread_id = threadList3.front();
+               if (MsgExistConversation(dbHandle, cur_thread_id) == true)
+                       MsgTransactionManager::instance()->broadcastThreadChangeCB(MSG_SUCCESS, MSG_STORAGE_CHANGE_UPDATE, cur_thread_id);
+
+               threadList3.pop();
+       }
+
        if (g_idle_add(resetNotification, NULL) == 0) {
                MSG_DEBUG("resetNotification() Error");
        }
index c4382cb..5448e2a 100755 (executable)
@@ -369,6 +369,29 @@ int MsgRegStorageChangeCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent)
 }
 
 
+int MsgRegThreadChangeCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent)
+{
+       /* input check */
+       if (!pCmd || !ppEvent) {
+               MSG_DEBUG("pCmd or ppEvent is null");
+               return 0;
+       }
+
+       /* Get Message Request */
+       int listenerFd = 0;
+       memcpy(&listenerFd, (void*)((char*)pCmd+sizeof(MSG_CMD_TYPE_T)+MAX_COOKIE_LEN), sizeof(int));
+       MSG_DEBUG("Registering storage change CB for %d", listenerFd);
+
+       /* storing dst fd in list */
+       MsgTransactionManager::instance()->setThreadChangeCB(listenerFd);
+
+       /* Make Event Data */
+       int eventSize = MsgMakeEvent(NULL, 0, MSG_EVENT_REG_THREAD_CHANGE_CB, MsgException::SUCCESS, (void**)ppEvent);
+
+       return eventSize;
+}
+
+
 int MsgRegIncomingReportMsgCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent)
 {
        /* input check */
@@ -1001,6 +1024,36 @@ int MsgStorageChangeHandler(const MSG_CMD_S *pCmd, char **ppEvent)
        return eventSize;
 }
 
+int MsgThreadChangeHandler(const MSG_CMD_S *pCmd, char **ppEvent)
+{
+       /* input check */
+       if (!pCmd || !ppEvent) {
+               MSG_DEBUG("pCmd or ppEvent is null");
+               return 0;
+       }
+
+       msg_storage_change_type_t storageChangeType;
+       msg_thread_id_t threadId;
+
+       memcpy(&threadId, (void*)((char*)pCmd+sizeof(MSG_CMD_TYPE_T)+MAX_COOKIE_LEN), sizeof(msg_thread_id_t));
+       memcpy(&storageChangeType, (void*)((char*)pCmd+sizeof(MSG_CMD_TYPE_T)+MAX_COOKIE_LEN+sizeof(msg_thread_id_t)), sizeof(msg_storage_change_type_t));
+
+       char* encodedData = NULL;
+       unique_ptr<char*, void(*)(char**)> buf(&encodedData, unique_ptr_deleter);
+
+       int eventSize = 0;
+
+       MSG_DEBUG("storageChangeType : [%d], thread Id : [%d]", storageChangeType, threadId);
+
+       /* broadcast to listener threads, here */
+       MsgTransactionManager::instance()->broadcastThreadChangeCB(MSG_SUCCESS, storageChangeType, threadId);
+
+       /* Make Event Data to Client */
+       eventSize = MsgMakeEvent(NULL, 0, MSG_EVENT_PLG_THREAD_CHANGE_IND, MSG_SUCCESS, (void**)ppEvent);
+
+       return eventSize;
+}
+
 int MsgResendMessageHandler(const MSG_CMD_S *pCmd, char **ppEvent)
 {
        msg_error_t err = MSG_SUCCESS;
index d59bcd6..56d0a7f 100755 (executable)
@@ -19,6 +19,7 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <pthread.h>
+#include <algorithm>
 
 #include <bundle.h>
 #include <eventsystem.h>
@@ -30,6 +31,8 @@
 #include "MsgContact.h"
 #include "MsgIpcSocket.h"
 #include "MsgGconfWrapper.h"
+#include "MsgSqliteWrapper.h"
+#include "MsgUtilStorage.h"
 #include "MsgUtilFunction.h"
 #include "MsgUtilFile.h"
 #include "MsgLbs.h"
@@ -41,6 +44,8 @@
 
 #define MSG_CHECK_PRIVILEGE
 
+std::list<msg_thread_id_t> cur_conv_list;
+
 void MsgMakeErrorEvent(MSG_CMD_TYPE_T cmdType, msg_error_t errType, int *pEventSize, char **ppEvent)
 {
        if (*ppEvent) delete [] *ppEvent;
@@ -54,6 +59,29 @@ void MsgMakeErrorEvent(MSG_CMD_TYPE_T cmdType, msg_error_t errType, int *pEventS
        pMsgEvent->result = errType;
 }
 
+void initConversationList()
+{
+       MsgDbHandler *dbHandle = getDbHandle();
+
+       msg_error_t err = MSG_SUCCESS;
+       int rowCnt = 0;
+
+       char sqlQuery[MAX_QUERY_LEN+1] = {0};
+       snprintf(sqlQuery, MAX_QUERY_LEN, "SELECT CONV_ID FROM %s;", MSGFW_CONVERSATION_TABLE_NAME);
+
+       err = dbHandle->getTable(sqlQuery, &rowCnt, NULL);
+       if (err != MSG_SUCCESS) {
+               MSG_DEBUG("getTable failed [%d]", err);
+               dbHandle->freeTable();
+               return;
+       }
+
+       for (int i = 0; i < rowCnt; i++)
+               cur_conv_list.push_back((msg_thread_id_t)dbHandle->getColumnToInt(i+1));
+
+       dbHandle->freeTable();
+}
+
 /*==================================================================================================
                                      IMPLEMENTATION OF MsgTransactionManager - Member Functions
 ==================================================================================================*/
@@ -75,6 +103,8 @@ MsgTransactionManager::MsgTransactionManager() : running(false), mx(), mxQ(), cv
 
        handlerMap.clear();
 
+       initConversationList();
+
 /*     Fill in mMsgHandlers, as given in the below. */
        handlerMap[MSG_CMD_ADD_MSG]                             = &MsgAddMessageHandler;
        handlerMap[MSG_CMD_ADD_SYNCML_MSG]              = &MsgAddSyncMLMessageHandler;
@@ -105,6 +135,7 @@ MsgTransactionManager::MsgTransactionManager() : running(false), mx(), mxQ(), cv
 
        handlerMap[MSG_CMD_REG_SENT_STATUS_CB]  = &MsgRegSentStatusCallbackHandler;
        handlerMap[MSG_CMD_REG_STORAGE_CHANGE_CB] = &MsgRegStorageChangeCallbackHandler;
+       handlerMap[MSG_CMD_REG_THREAD_CHANGE_CB] = &MsgRegThreadChangeCallbackHandler;
        handlerMap[MSG_CMD_REG_INCOMING_MSG_CB] = &MsgRegIncomingMsgCallbackHandler;
        handlerMap[MSG_CMD_REG_INCOMING_MMS_CONF_MSG_CB]        = &MsgRegIncomingMMSConfMsgCallbackHandler;
        handlerMap[MSG_CMD_REG_INCOMING_SYNCML_MSG_CB]  = &MsgRegIncomingSyncMLMsgCallbackHandler;
@@ -642,6 +673,7 @@ bool MsgTransactionManager::checkPrivilege(int fd, MSG_CMD_TYPE_T CmdType)
        case MSG_CMD_GET_MEMSIZE:
        case MSG_CMD_BACKUP_MESSAGE:
        case MSG_CMD_REG_STORAGE_CHANGE_CB:
+       case MSG_CMD_REG_THREAD_CHANGE_CB:
        case MSG_CMD_GET_REPORT_STATUS:
        case MSG_CMD_GET_THREAD_ID_BY_ADDRESS:
        case MSG_CMD_GET_THREAD_INFO:
@@ -934,6 +966,17 @@ void MsgTransactionManager::setStorageChangeCB(int listenerFd)
 }
 
 
+void MsgTransactionManager::setThreadChangeCB(int listenerFd)
+{
+       if (listenerFd <= 0)
+               THROW(MsgException::INVALID_PARAM, "InParam Error: listenerFd %d", listenerFd);
+
+       MsgMutexLocker lock(mx);
+
+       threadChangeFdMap[listenerFd] = true;
+}
+
+
 void MsgTransactionManager::setReportMsgCB(int listenerFd)
 {
        if (listenerFd <= 0)
@@ -1176,6 +1219,15 @@ void MsgTransactionManager::broadcastSyncMLMsgOperationCB(const msg_error_t err,
 }
 
 
+bool compare_func(msg_thread_id_t const &a, msg_thread_id_t const &b)
+{
+       if (a == b)
+               return true;
+
+       return false;
+}
+
+
 void MsgTransactionManager::broadcastStorageChangeCB(const msg_error_t err, const msg_storage_change_type_t storageChangeType, const msg_id_list_s *pMsgIdList)
 {
        MSG_BEGIN();
@@ -1209,6 +1261,79 @@ void MsgTransactionManager::broadcastStorageChangeCB(const msg_error_t err, cons
                write(it->first, pEventData, eventSize);
        }
 
+       MsgDbHandler *dbHandle = getDbHandle();
+       MsgSimpleQ<msg_thread_id_t> updatedConvQ;
+
+       if (storageChangeType == MSG_STORAGE_CHANGE_INSERT) {
+               for (int i = 0; i < pMsgIdList->nCount; i++) {
+                       msg_thread_id_t conv_id = MsgGetThreadId(dbHandle, pMsgIdList->msgIdList[i]);
+                       bool found = (std::find(cur_conv_list.begin(), cur_conv_list.end(), conv_id) != cur_conv_list.end());
+
+                       if (found == false) {
+                               cur_conv_list.push_back(conv_id);
+                               updatedConvQ.push_back(conv_id);
+                               broadcastThreadChangeCB(MSG_SUCCESS, MSG_STORAGE_CHANGE_INSERT, conv_id);
+                       } else {
+                               if (updatedConvQ.checkExist(conv_id, compare_func) == false) {
+                                       broadcastThreadChangeCB(MSG_SUCCESS, MSG_STORAGE_CHANGE_UPDATE, conv_id);
+                                       updatedConvQ.push_back(conv_id);
+                               }
+                       }
+               }
+       } else if (storageChangeType == MSG_STORAGE_CHANGE_UPDATE) {
+               for (int i = 0; i < pMsgIdList->nCount; i++) {
+                       msg_thread_id_t conv_id = MsgGetThreadId(dbHandle, pMsgIdList->msgIdList[i]);
+                       if (updatedConvQ.checkExist(conv_id, compare_func) == false) {
+                               broadcastThreadChangeCB(MSG_SUCCESS, MSG_STORAGE_CHANGE_UPDATE, conv_id);
+                               updatedConvQ.push_back(conv_id);
+                       }
+               }
+       } else if (storageChangeType == MSG_STORAGE_CHANGE_DELETE) {
+               std::list<msg_thread_id_t>::iterator it = cur_conv_list.begin();
+               for (; it != cur_conv_list.end(); ) {
+                       if (MsgExistConversation(dbHandle, *it) == false) {
+                               broadcastThreadChangeCB(MSG_SUCCESS, MSG_STORAGE_CHANGE_DELETE, *it);
+                               it = cur_conv_list.erase(it);
+                       } else{
+                               it++;
+                       }
+               }
+       }
+
+       updatedConvQ.clear();
+
+       MSG_END();
+}
+
+
+void MsgTransactionManager::broadcastThreadChangeCB(const msg_error_t err, const msg_storage_change_type_t storageChangeType, const msg_thread_id_t threadId)
+{
+       MSG_BEGIN();
+
+       MSG_DEBUG("storageChangeType [%d], threadId [%d]", storageChangeType, threadId);
+
+       int dataSize = 0;
+
+       char* pEventData = NULL;
+       unique_ptr<char*, void(*)(char**)> eventBuf(&pEventData, unique_ptr_deleter);
+
+       char* encodedData = NULL;
+       unique_ptr<char*, void(*)(char**)> buf(&encodedData, unique_ptr_deleter);
+
+       /* Encoding Thread Change Data */
+       dataSize = MsgEncodeThreadChangeData(storageChangeType, threadId, &encodedData);
+
+       int eventSize = MsgMakeEvent(encodedData, dataSize, MSG_EVENT_PLG_THREAD_CHANGE_IND, err, (void**)(&pEventData));
+
+       MsgMutexLocker lock(mx);
+
+       fd_map::iterator it = threadChangeFdMap.begin();
+
+       for (; it != threadChangeFdMap.end(); it++) {
+               MSG_DEBUG("Send Thread Change Callback to listener %d", it->first);
+               write(it->first, pEventData, eventSize);
+       }
+
        MSG_END();
 }
 
index fed00ec..fd21d0c 100755 (executable)
@@ -166,6 +166,9 @@ enum _MSG_CMD_TYPE_E {
 #endif
 
        MSG_CMD_CHECK_PERMISSION,
+       MSG_CMD_REG_THREAD_CHANGE_CB,
+       MSG_CMD_PLG_THREAD_CHANGE_IND,
+
 /* end of MSG_CMD; new CMD should be defined before MSG_CMD_NUM */
        MSG_CMD_NUM
 };
@@ -277,6 +280,8 @@ enum _MSG_EVENT_TYPE_E {
        MSG_EVENT_PLG_CHECK_UNIQUENESS,
 #endif
        MSG_EVENT_CHECK_PERMISSION,
+       MSG_EVENT_REG_THREAD_CHANGE_CB,
+       MSG_EVENT_PLG_THREAD_CHANGE_IND,
 
 /* Enums that does not match _MSG_CMD_TYPE_E */
        MSG_EVENT_PLG_REPORT_MSG_INCOMING_IND,
index 62ab9fb..b144ca0 100755 (executable)
@@ -1052,6 +1052,7 @@ typedef msg_error_t (*MsgPlgGetDefaultNetworkSimId) (int *simId);
 /* framework defined callbacks. */
 typedef void (*MsgPlgOnSentStatus)(MSG_SENT_STATUS_S *pSentStatus);
 typedef void (*MsgPlgOnStorageChange)(msg_storage_change_type_t storageChangeType, msg_id_list_s *pMsgIdList);
+typedef void (*MsgPlgOnThreadChange)(msg_storage_change_type_t storageChangeType, msg_thread_id_t threadId);
 typedef msg_error_t (*MsgPlgOnMsgIncoming)(MSG_MESSAGE_INFO_S *pMsgInfo);
 typedef msg_error_t (*MsgPlgOnInitSimBySat)(void);
 typedef msg_error_t (*MsgPlgOnSyncMLMsgIncoming)(MSG_SYNCML_MESSAGE_DATA_S *pSyncMLData);
@@ -1072,6 +1073,7 @@ typedef msg_error_t (*MsgPlgOnInitImsi)(int sim_idx);
 struct _MSG_PLUGIN_LISTENER_S {
        MsgPlgOnSentStatus                                      pfSentStatusCb;                                 /** The function pointer of sent status callback. */
        MsgPlgOnStorageChange                   pfStorageChangeCb;                      /** The function pointer of storage change callback. */
+       MsgPlgOnThreadChange                    pfThreadChangeCb;                       /** The function pointer of thread change callback. */
        MsgPlgOnMsgIncoming                             pfMsgIncomingCb;                                /** The function pointer of receive message callback. */
        MsgPlgOnInitSimBySat                            pfInitSimBySatCb;                               /** The function pointer of init SIM callback. */
        MsgPlgOnSyncMLMsgIncoming       pfSyncMLMsgIncomingCb;  /** The function pointer of receive syncML message callback. */
index f5b9536..f74a208 100755 (executable)
@@ -78,7 +78,9 @@ int MsgRegIncomingSyncMLMsgCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent
 int MsgRegIncomingLBSMsgCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent);
 int MsgRegSyncMLMsgOperationCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent);
 int MsgRegStorageChangeCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent);
+int MsgRegThreadChangeCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent);
 int MsgStorageChangeHandler(const MSG_CMD_S *pCmd, char **ppEvent);
+int MsgThreadChangeHandler(const MSG_CMD_S *pCmd, char **ppEvent);
 int MsgRegIncomingReportMsgCallbackHandler(const MSG_CMD_S *pCmd, char **ppEvent);
 
 int MsgSentStatusHandler(const MSG_CMD_S *pCmd, char **ppEvent);
index 7f8413f..32761f9 100755 (executable)
@@ -80,6 +80,7 @@ public:
        void setJavaMMSList(MSG_CMD_REG_INCOMING_JAVAMMS_TRID_S *pTrId);
        void setSyncMLMsgOperationCB(MSG_CMD_REG_SYNCML_MSG_OPERATION_CB_S *pCbinfo);
        void setStorageChangeCB(int listenerFd);
+       void setThreadChangeCB(int listenerFd);
        void setReportMsgCB(int listenerFd);
 
        javamms_list &getJavaMMSList();
@@ -92,6 +93,7 @@ public:
        void broadcastLBSMsgCB(const msg_error_t err, const MSG_LBS_MESSAGE_DATA_S *lbsData);
        void broadcastSyncMLMsgOperationCB(const msg_error_t err, const int msgId, const int extId);
        void broadcastStorageChangeCB(const msg_error_t err, const msg_storage_change_type_t storageChangeType, const msg_id_list_s *pMsgIdList);
+       void broadcastThreadChangeCB(const msg_error_t err, const msg_storage_change_type_t storageChangeType, const msg_thread_id_t threadId);
        void broadcastReportMsgCB(const msg_error_t err, const msg_report_type_t reportMsgType, const MSG_MESSAGE_INFO_S *pMsgInfo);
 
        bool initCynara();
@@ -125,6 +127,7 @@ private:
        syncmlop_list operationSyncMLMsgCBList;
 
        fd_map storageChangeFdMap;
+       fd_map threadChangeFdMap;
        fd_map reportMsgCBFdMap;
 
        MsgMutex mx; /* mutex for shared resources like callback listeners */
index feeb2d2..4fb9263 100755 (executable)
@@ -845,6 +845,34 @@ int msg_reg_storage_change_callback(msg_handle_t handle, msg_storage_change_cb c
 
 
 /**
+ * @brief Registers a callback function about the change of thread status to Message handle.
+ * @details This API is used to register a callback function about the change of thread status "msg_thread_change_cb" to Message handle.
+ *
+ * @since_tizen 3.0
+ * @privlevel public
+ * @privilege %http://tizen.org/privilege/message.read
+ *
+ * @remarks This function MUST be called after Message handle is opened.
+ *
+ * @param[in] handle      The Message handle
+ * @param[in] cb          The function to be called
+ * @param[in] user_param  A pointer to user data
+ *
+ * @return  @c 0 on success,
+ *        otherwise a negative error value
+ *
+ * @retval MSG_SUCCESS               Success in operation
+ * @retval MSG_ERR_INVALID_PARAMETER Parameter is invalid
+ * @retval MSG_ERR_MSGHANDLE_NOT_CONNECTED Message handle is not connected
+ * @retval MSG_ERR_MEMORY_ERROR         Memory is error
+ * @retval MSG_ERR_PERMISSION_DENIED The application does not have the privilege to call this method
+ * @retval MSG_ERR_NOT_SUPPORTED     Not supported
+ */
+
+int msg_reg_thread_change_callback(msg_handle_t handle, msg_thread_change_cb cb, void *user_param);
+
+
+/**
  * @brief Gets the report status information of message.
  *
  * @since_tizen 2.3
index 8a740df..f3e59bd 100755 (executable)
@@ -95,6 +95,16 @@ typedef unsigned char msg_storage_change_type_t;
 typedef void (*msg_storage_change_cb)(msg_handle_t handle, msg_storage_change_type_t storageChangeType, msg_id_list_s *pMsgIdList, void *user_param);
 
 
+/** @brief     Called when the threads of message framework is changed.
+ *          Applications SHOULD implement this callback function and register it into Message handle.
+ *             For how to register this callback function, please refer to msg_reg_thread_change_callback().
+ *             The callback function runs in the application process, not in the framework process.
+ * @param[in]  handle      The Message handle.
+ * @param[in]  user_param  A pointer to user data
+ */
+typedef void (*msg_thread_change_cb)(msg_handle_t handle, msg_storage_change_type_t storageChangeType, msg_thread_id_t threadId, void *user_param);
+
+
 /*==================================================================================================
                                                                                        ENUMS
 ==================================================================================================*/
index 816013e..f3acaae 100755 (executable)
@@ -135,6 +135,7 @@ public:
 
        msg_error_t getRejectMsgList(const char *pNumber, msg_struct_list_s *pRejectMsgList);
        msg_error_t regStorageChangeCallback(msg_storage_change_cb onStorageChange, void *pUserParam);
+       msg_error_t regThreadChangeCallback(msg_thread_change_cb onThreadChange, void *pUserParam);
        msg_error_t getReportStatus(msg_message_id_t msg_id, msg_struct_list_s *report_list);
        msg_error_t getThreadIdByAddress(msg_struct_list_s *pAddrList, msg_thread_id_t *pThreadId);
        msg_error_t getThreadIdByAddress(msg_list_handle_t msg_address_list, msg_thread_id_t *pThreadId);
index 99f2141..6cf9dc8 100755 (executable)
@@ -113,6 +113,14 @@ typedef struct {
 typedef struct {
        MsgHandle* hAddr;
        int fd;
+       msg_thread_change_cb pfThreadChangeCB;
+       void* userParam;
+} MSG_THREAD_CHANGE_CB_ITEM_S;
+
+
+typedef struct {
+       MsgHandle* hAddr;
+       int fd;
        msg_report_msg_incoming_cb pfReportMsgIncomingCB;
        void* userParam;
 } MSG_REPORT_INCOMING_CB_ITEM_S;
@@ -127,6 +135,7 @@ typedef std::list<MSG_SYNCML_INCOMING_CB_ITEM_S> MsgNewSyncMLMessageCBList;
 typedef std::list<MSG_LBS_INCOMING_CB_ITEM_S> MsgNewLBSMessageCBList;
 typedef std::list<MSG_SYNCML_OPERATION_CB_ITEM_S> MsgOperationSyncMLMessageCBList;
 typedef std::list<MSG_STORAGE_CHANGE_CB_ITEM_S> MsgStorageChangeCBList;
+typedef std::list<MSG_THREAD_CHANGE_CB_ITEM_S> MsgThreadChangeCBList;
 typedef std::list<MSG_REPORT_INCOMING_CB_ITEM_S> MsgReportMessageCBList;
 typedef std::set<MsgHandle*> handle_set;
 
@@ -150,6 +159,7 @@ public:
        bool regLBSMessageIncomingEventCB(MsgHandle* pMsgHandle, int fd, msg_lbs_msg_incoming_cb pfNewLBSMsgIncoming, void *pUserParam);
        bool regSyncMLMessageOperationEventCB(MsgHandle* pMsgHandle, int fd, msg_syncml_msg_operation_cb pfSyncMLMessageOperation, void *pUserParam);
        bool regStorageChangeEventCB(MsgHandle* pMsgHandle, int fd, msg_storage_change_cb pfStorageChangeOperation, void *pUserParam);
+       bool regThreadChangeEventCB(MsgHandle* pMsgHandle, int fd, msg_thread_change_cb pfThreadChangeOperation, void *pUserParam);
        bool regReportMsgIncomingCB(MsgHandle* pMsgHandle, int fd, msg_report_msg_incoming_cb pfReportMessage, void *pUserParam);
 
        void clearListOfClosedHandle(MsgHandle* pMsgHandle);
@@ -192,6 +202,7 @@ private:
        MsgNewLBSMessageCBList newLBSMessageCBList;
        MsgOperationSyncMLMessageCBList operationSyncMLMessageCBList;
        MsgStorageChangeCBList storageChangeCBList;
+       MsgThreadChangeCBList threadChangeCBList;
        MsgReportMessageCBList reportMessageCBList;
 
        GIOChannel *channel;
index f5656f1..82ded6e 100755 (executable)
@@ -84,6 +84,8 @@ int MsgEncodeSyncMLOperationData(int msgId, int extId, char **ppDest);
 
 int MsgEncodeStorageChangeData(const msg_storage_change_type_t storageChangeType, const msg_id_list_s *pMsgIdList, char **ppDest);
 
+int MsgEncodeThreadChangeData(const msg_storage_change_type_t storageChangeType, const msg_thread_id_t threadId, char **ppDest);
+
 int MsgEncodeReportMsgData(const msg_report_type_t msgReportType, const MSG_MESSAGE_INFO_S *pMsgInfo, char **ppDest);
 
 int MsgEncodeReportStatus(MSG_REPORT_STATUS_INFO_S* pReportStatus, int count, char **ppDest);
index 5c509e4..8710602 100755 (executable)
@@ -951,6 +951,30 @@ EXPORT_API int msg_reg_storage_change_callback(msg_handle_t handle, msg_storage_
        return err;
 }
 
+EXPORT_API int msg_reg_thread_change_callback(msg_handle_t handle, msg_thread_change_cb cb, void *user_param)
+{
+       CHECK_MSG_SUPPORTED(MSG_TELEPHONY_SMS_FEATURE);
+       msg_error_t err = MSG_SUCCESS;
+
+       if (handle == NULL || cb == NULL)
+               return MSG_ERR_INVALID_PARAMETER;
+
+       MsgHandle* pHandle = (MsgHandle*)handle;
+
+       try {
+               err = pHandle->regThreadChangeCallback(cb, user_param);
+       } catch (MsgException& e) {
+               MSG_FATAL("%s", e.what());
+               if (e.errorCode() == MsgException::SERVER_READY_ERROR)
+                       return MSG_ERR_PERMISSION_DENIED;
+               else
+                       return MSG_ERR_CALLBACK_ERROR;
+       }
+
+       return err;
+
+}
+
 EXPORT_API int msg_get_report_status(msg_handle_t handle, msg_message_id_t msg_id, msg_struct_list_s *report_list)
 {
        CHECK_MSG_SUPPORTED(MSG_TELEPHONY_SMS_FEATURE);
index 7685911..68fdf01 100755 (executable)
@@ -509,6 +509,15 @@ msg_error_t SmsPluginEventHandler::callbackStorageChange(msg_storage_change_type
 }
 
 
+msg_error_t SmsPluginEventHandler::callbackThreadChange(msg_storage_change_type_t storageChangeType, msg_thread_id_t threadId)
+{
+       /* Callback to MSG FW */
+       listener.pfThreadChangeCb(storageChangeType, threadId);
+
+       return MSG_SUCCESS;
+}
+
+
 void SmsPluginEventHandler::convertTpduToMsginfo(SMS_TPDU_S *pTpdu, MSG_MESSAGE_INFO_S *msgInfo)
 {
        switch (pTpdu->tpduType) {
index 3b3f215..35af834 100755 (executable)
@@ -27,6 +27,7 @@
 #include "MsgNotificationWrapper.h"
 #include "SmsPluginMain.h"
 #include "SmsPluginSimMsg.h"
+#include "SmsPluginEventHandler.h"
 #include "SmsPluginStorage.h"
 
 
@@ -636,6 +637,16 @@ msg_error_t SmsPluginStorage::deleteSmsMessage(msg_message_id_t msgId)
 
        dbHandle->endTrans(true);
 
+       memset(sqlQuery, 0x00, sizeof(sqlQuery));
+       snprintf(sqlQuery, sizeof(sqlQuery), "SELECT CONV_ID FROM %s WHERE CONV_ID = %d;", MSGFW_CONVERSATION_TABLE_NAME, convId);
+       if (dbHandle->prepareQuery(sqlQuery) != MSG_SUCCESS)
+               return MSG_ERR_DB_PREPARE;
+
+       if (dbHandle->stepQuery() == MSG_ERR_DB_ROW)
+               SmsPluginEventHandler::instance()->callbackThreadChange(MSG_STORAGE_CHANGE_UPDATE, convId);
+
+       dbHandle->finalizeQuery();
+
        signed char folder_id = (signed char)folderId;
        if (folder_id == MSG_INBOX_ID) {
                msgType.classType = MSG_CLASS_NONE;
index 035f33a..c7c1f0c 100755 (executable)
@@ -47,6 +47,7 @@ public:
        msg_error_t callbackCBMsgIncoming(MSG_CB_MSG_S *pCbMsg, MSG_MESSAGE_INFO_S *pMsgInfo);
        msg_error_t callbackInitSimBySat();
        msg_error_t callbackStorageChange(msg_storage_change_type_t storageChangeType, MSG_MESSAGE_INFO_S *pMsgInfo);
+       msg_error_t callbackThreadChange(msg_storage_change_type_t storageChangeType, msg_thread_id_t threadId);
        msg_error_t handleSimMsg(MSG_MESSAGE_INFO_S *pMsgInfo, int *simIdList, msg_message_id_t *retMsgId, int listSize);
        msg_error_t updateIMSI(int sim_idx);
        void handleSimMemoryFull(int simIndex);
index e4a9f5c..8220910 100755 (executable)
@@ -616,6 +616,7 @@ bool MsgHandle::checkEventData(char *pEventData)
        case MSG_EVENT_PLG_INCOMING_SYNCML_MSG_IND:
        case MSG_EVENT_PLG_INCOMING_LBS_MSG_IND:
        case MSG_EVENT_PLG_STORAGE_CHANGE_IND:
+       case MSG_EVENT_PLG_THREAD_CHANGE_IND:
        case MSG_EVENT_PLG_INCOMING_CB_MSG_IND:
        case MSG_EVENT_PLG_INCOMING_PUSH_MSG_IND:
        case MSG_EVENT_PLG_REPORT_MSG_INCOMING_IND:
index bc30ecb..7e1d989 100755 (executable)
@@ -1409,6 +1409,65 @@ msg_error_t MsgHandle::regStorageChangeCallback(msg_storage_change_cb onStorageC
 }
 
 
+msg_error_t MsgHandle::regThreadChangeCallback(msg_thread_change_cb onThreadChange, void *pUserParam)
+{
+       if (!onThreadChange)
+               THROW(MsgException::INVALID_PARAM, "onThreadChange is null");
+
+       MsgProxyListener* eventListener = MsgProxyListener::instance();
+
+       eventListener->start(this);
+
+       int remoteFd = eventListener->getRemoteFd(); /* fd that is reserved to the "listener thread" by msgfw daemon */
+
+       if (remoteFd == -1 ) {
+               eventListener->stop();
+               return MSG_ERR_INVALID_MSGHANDLE;
+       }
+
+       if (eventListener->regThreadChangeEventCB(this, remoteFd, onThreadChange, pUserParam) == false) {
+               eventListener->stop();
+               return MSG_ERR_INVALID_PARAMETER;
+       }
+
+       /* Allocate Memory to Command Data */
+       int cmdSize = sizeof(MSG_CMD_S) + sizeof(int); /* cmd type, listenerFd */
+       char cmdBuf[cmdSize];
+       bzero(cmdBuf, cmdSize);
+       MSG_CMD_S* pCmd = (MSG_CMD_S*) cmdBuf;
+
+       /* Set Command Parameters */
+       pCmd->cmdType = MSG_CMD_REG_THREAD_CHANGE_CB;
+
+       /* Copy Cookie */
+       memcpy(pCmd->cmdCookie, mCookie, MAX_COOKIE_LEN);
+
+       MSG_DEBUG("remote fd %d", remoteFd);
+
+       memcpy((void*)((char*)pCmd+sizeof(MSG_CMD_TYPE_T)+MAX_COOKIE_LEN), &remoteFd, sizeof(remoteFd));
+
+       MSG_DEBUG("reg status [%d : %s], %d", pCmd->cmdType, MsgDbgCmdStr(pCmd->cmdType), remoteFd);
+
+       /* Send Command to Messaging FW */
+       char* pEventData = NULL;
+       unique_ptr<char*, void(*)(char**)> eventBuf(&pEventData, unique_ptr_deleter);
+
+       write((char*)pCmd, cmdSize, &pEventData);
+
+       /* Get Return Data */
+       MSG_EVENT_S* pEvent = (MSG_EVENT_S*)pEventData;
+
+       if (pEvent == NULL)
+               THROW(MsgException::INVALID_RESULT, "Event is NULL");
+
+       if (pEvent->eventType != MSG_EVENT_REG_THREAD_CHANGE_CB) {
+               THROW(MsgException::INVALID_PARAM, "Event Data Error");
+       }
+
+       return pEvent->result;
+}
+
+
 msg_error_t MsgHandle::getReportStatus(msg_message_id_t msg_id, msg_struct_list_s *report_list)
 {
        /* Allocate Memory to Command Data */
index dc0493e..8d834c9 100755 (executable)
@@ -501,6 +501,33 @@ bool MsgProxyListener::regStorageChangeEventCB(MsgHandle* pMsgHandle, int fd, ms
 }
 
 
+bool MsgProxyListener::regThreadChangeEventCB(MsgHandle* pMsgHandle, int fd, msg_thread_change_cb pfThreadChangeOperation, void *pUserParam)
+{
+       MsgMutexLocker lock(mx);
+
+       std::list<MSG_THREAD_CHANGE_CB_ITEM_S>::iterator it = threadChangeCBList.begin();
+
+       for (; it != threadChangeCBList.end(); it++) {
+               if (it->hAddr == pMsgHandle && it->pfThreadChangeCB == pfThreadChangeOperation) {
+                       if (it->fd == fd) {
+                               MSG_DEBUG("msg_thread_change_cb() callback : [%p] is already registered!!!", pfThreadChangeOperation);
+                               return false;
+                       } else {
+                               MSG_DEBUG("callback is registered by restarting server");
+                               it->fd = fd;
+                               return true;
+                       }
+               }
+       }
+
+       MSG_THREAD_CHANGE_CB_ITEM_S changeCB = {pMsgHandle, fd, pfThreadChangeOperation, pUserParam};
+
+       threadChangeCBList.push_back(changeCB);
+
+       return true;
+}
+
+
 void MsgProxyListener::clearListOfClosedHandle(MsgHandle* pMsgHandle)
 {
        MSG_BEGIN();
@@ -1111,6 +1138,31 @@ void MsgProxyListener::handleEvent(const MSG_EVENT_S* pMsgEvent)
                }
 
                mx.unlock();
+       } else if (pMsgEvent->eventType == MSG_EVENT_PLG_THREAD_CHANGE_IND) {
+               msg_storage_change_type_t storageChangeType;
+               msg_thread_id_t threadId;
+
+               /* Decode event data */
+               memcpy(&storageChangeType, (void*)((char*)pMsgEvent+sizeof(MSG_EVENT_TYPE_T)+sizeof(msg_error_t)), sizeof(msg_storage_change_type_t));
+               memcpy(&threadId, (void*)((char*)pMsgEvent+sizeof(MSG_EVENT_TYPE_T)+sizeof(msg_error_t)+sizeof(msg_storage_change_type_t)), sizeof(msg_thread_id_t));
+
+               MSG_DEBUG("storageChangeType [%d], threadId [%d]", storageChangeType, threadId);
+
+               mx.lock();
+
+               MsgThreadChangeCBList::iterator it = threadChangeCBList.begin();
+
+               for ( ; it != threadChangeCBList.end(); it++) {
+                       MsgHandle* pHandle = it->hAddr;
+
+                       msg_thread_change_cb pfunc = it->pfThreadChangeCB;
+
+                       void* param = it->userParam;
+
+                       pfunc((msg_handle_t)pHandle, storageChangeType, threadId, param);
+               }
+
+               mx.unlock();
        } else if (pMsgEvent->eventType == MSG_EVENT_PLG_INCOMING_CB_MSG_IND) {
                MSG_CB_MSG_S *pCbMsg = (MSG_CB_MSG_S *)pMsgEvent->data;
 
index dacc4e4..4ad72be 100755 (executable)
@@ -218,6 +218,10 @@ const char * MsgDbgCmdStr(MSG_CMD_TYPE_T cmdType)
 #endif
        case MSG_CMD_CHECK_PERMISSION:
                return "MSG_CMD_CHECK_PERMISSION";
+       case MSG_CMD_REG_THREAD_CHANGE_CB:
+               return "MSG_CMD_REG_THREAD_CHANGE_CB";
+       case MSG_CMD_PLG_THREAD_CHANGE_IND:
+               return "MSG_CMD_PLG_THREAD_CHANGE_IND";
 
        default:
                return "Unknown Command Type!!!";
@@ -426,6 +430,10 @@ const char * MsgDbgEvtStr(MSG_EVENT_TYPE_T evtType)
 
        case MSG_EVENT_PLG_REPORT_MSG_INCOMING_IND:
                return "MSG_EVENT_PLG_REPORT_MSG_INCOMING_IND";
+       case MSG_EVENT_REG_THREAD_CHANGE_CB:
+               return "MSG_EVENT_REG_THREAD_CHANGE_CB";
+       case MSG_EVENT_PLG_THREAD_CHANGE_IND:
+               return "MSG_EVENT_PLG_THREAD_CHANGE_IND";
 
        default:
                return "Unknown Event Type!!!";
index fc6fd6f..3bf80da 100755 (executable)
@@ -439,6 +439,25 @@ int MsgEncodeStorageChangeData(const msg_storage_change_type_t storageChangeType
 }
 
 
+int MsgEncodeThreadChangeData(const msg_storage_change_type_t storageChangeType, const msg_thread_id_t threadId, char **ppDest)
+{
+       int dataSize = 0;
+
+       dataSize = sizeof(msg_storage_change_type_t) + sizeof(msg_thread_id_t);
+
+       *ppDest = (char*)new char[dataSize];
+
+       void* p = (void*)*ppDest;
+
+       memcpy(p, &storageChangeType, sizeof(msg_storage_change_type_t));
+       p = (void*)((char*)p + sizeof(msg_storage_change_type_t));
+
+       memcpy(p, &threadId, sizeof(msg_thread_id_t));
+
+       return dataSize;
+}
+
+
 int MsgEncodeReportMsgData(const msg_report_type_t msgReportType, const MSG_MESSAGE_INFO_S *pMsgInfo, char **ppDest)
 {
        int dataSize = 0;