From 4ee0e2219a3be9cbe851c422711986ac32e7925c Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Thu, 20 Sep 2018 09:01:37 +0200 Subject: [PATCH 01/16] [version] 2.26 Change-Id: Ibb8feb4665aee4761dc2592147bdd41743bed13d Signed-off-by: Piotr Kosko --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index f9c4b20..b5169ac 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.25 +Version: 2.26 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From debf5d373ae98ce8c864bebb9bd2e8dd4f0cd733 Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Tue, 2 Oct 2018 13:25:19 +0200 Subject: [PATCH 02/16] [Archive][Exif] Added missing error checking [Verification] Code compiles without errors. Change-Id: I588a1d08f4dea4a19038653b2889a1daa5b45673 Signed-off-by: Piotr Kosko --- src/archive/zip_add_request.cc | 6 +++++- src/exif/jpeg_file.cc | 6 +++++- src/humanactivitymonitor/humanactivitymonitor_manager.cc | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/archive/zip_add_request.cc b/src/archive/zip_add_request.cc index d8cb38d..d6e862f 100644 --- a/src/archive/zip_add_request.cc +++ b/src/archive/zip_add_request.cc @@ -360,7 +360,11 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node) // Get file length fseek(m_input_file, 0, SEEK_END); const size_t in_file_size = ftell(m_input_file); - fseek(m_input_file, 0, SEEK_SET); + int res = fseek(m_input_file, 0, SEEK_SET); + if (0 != res) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Reading input file failed", + ("fseek failed with error! [%d]", res)); + } LoggerD("Source file: [%s] size: %d - %s", src_file_path.c_str(), in_file_size, bytesToReadableString(in_file_size).c_str()); diff --git a/src/exif/jpeg_file.cc b/src/exif/jpeg_file.cc index aefd179..39bf00c 100644 --- a/src/exif/jpeg_file.cc +++ b/src/exif/jpeg_file.cc @@ -148,7 +148,11 @@ PlatformResult JpegFile::load(const std::string& path) { ("Couldn't open Jpeg file: [%s]", path.c_str())); } - fseek(m_in_file, 0, SEEK_END); + int res = fseek(m_in_file, 0, SEEK_END); + if (0 != res) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Reading JPEG file failed", + ("fseek failed with error! [%d]", res)); + } long ftell_val = ftell(m_in_file); if (0 > ftell_val) { diff --git a/src/humanactivitymonitor/humanactivitymonitor_manager.cc b/src/humanactivitymonitor/humanactivitymonitor_manager.cc index 1dc5779..13f3a0c 100644 --- a/src/humanactivitymonitor/humanactivitymonitor_manager.cc +++ b/src/humanactivitymonitor/humanactivitymonitor_manager.cc @@ -1523,8 +1523,8 @@ HumanActivityMonitorManager::HumanActivityMonitorManager() return ConvertRecordedTime(data, obj); }; - monitors_.insert(std::make_pair(kActivityTypePedometer, - std::make_shared())); + monitors_.insert( + std::make_pair(kActivityTypePedometer, std::make_shared())); monitors_.insert(std::make_pair(kActivityTypeWristUp, std::make_shared(kActivityTypeWristUp))); monitors_.insert(std::make_pair( -- 2.7.4 From e93a64e5dfdb5a1ce0dc6854c1b6739c5fd6ae2f Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Tue, 2 Oct 2018 14:08:07 +0200 Subject: [PATCH 03/16] [version] 2.27 Change-Id: I7aa0f9e1384347db1d0b045ef46542fcd5e8c7a2 Signed-off-by: Piotr Kosko --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index b5169ac..20abcdc 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.26 +Version: 2.27 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From 1f1cdcadda70444917e9e77c1e0b9ee12ba8d511 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Fri, 24 Aug 2018 18:12:09 +0200 Subject: [PATCH 04/16] [Messaging] Fix sorting and filtering issues in findConversations The commit fixes the following problems of email service's findConversations: - conversations sorted with regard to timestamp, subject, to, from attributes were ordered incorrectly - an attempt to sort results with regard to unreadMessages, isRead, cc, bcc, lastMessageId attributes resulted in throwing a JS exception - unreadMessages attribute value depended on the offset argument value - filtering by unreadMessages, did not work The commit changes also the method of creation of MessageConversation from database records. It may be quicker than the previous one, that unnecessarily retrieved numerous messages from the database several times. [Verification] TCT Pass rate: 100% Several filters and sort modes were tested manually, with Chrome DevTools. Change-Id: I6196e316ff2b1477c909d528859ef980237454b6 Signed-off-by: Pawel Wasowski --- src/messaging/MsgCommon/AbstractFilter.cpp | 12 +- src/messaging/email_manager.cc | 18 +-- src/messaging/message_conversation.cc | 195 ++++++++++++++++++++++++++-- src/messaging/message_conversation.h | 11 +- src/messaging/messaging_database_manager.cc | 180 ++++++++++++++----------- src/messaging/messaging_database_manager.h | 9 +- 6 files changed, 315 insertions(+), 110 deletions(-) diff --git a/src/messaging/MsgCommon/AbstractFilter.cpp b/src/messaging/MsgCommon/AbstractFilter.cpp index 3f30d4d..1037576 100644 --- a/src/messaging/MsgCommon/AbstractFilter.cpp +++ b/src/messaging/MsgCommon/AbstractFilter.cpp @@ -150,26 +150,20 @@ bool FilterUtils::isTimeStampInRange(const time_t& time_stamp, tizen::AnyPtr& in tizen::AnyPtr& end_value) { ScopeLogger(); time_t from_time = 0; - time_t to_time = 0; - bool initial_is_valid_time_value = false; if (initial_value && !initial_value->isNullOrUndefined()) { struct tm ftime = *initial_value->toDateTm(); from_time = mktime(&ftime); - initial_is_valid_time_value = true; - } - if (!initial_is_valid_time_value) { + } else { LoggerE("initialValue is not Time!"); return false; } - bool end_is_valid_time_value = false; + time_t to_time = 0; if (end_value && !end_value->isNullOrUndefined()) { struct tm ttime = *end_value->toDateTm(); to_time = mktime(&ttime); - end_is_valid_time_value = true; - } - if (end_is_valid_time_value) { + } else { LoggerE("endValue is not Time!"); return false; } diff --git a/src/messaging/email_manager.cc b/src/messaging/email_manager.cc index 256fbb3..85608c1 100644 --- a/src/messaging/email_manager.cc +++ b/src/messaging/email_manager.cc @@ -1072,26 +1072,16 @@ void EmailManager::findMessages(FindMsgCallbackUserData* callback) { PlatformResult EmailManager::FindConversationsPlatform(ConversationCallbackData* callback) { ScopeLogger(); - int convListCount = 0; std::lock_guard lock(m_mutex); - std::vector conversationsInfo; + std::vector> conversationsInfo; PlatformResult ret = - MessagingDatabaseManager::getInstance().findEmailConversations(callback, &conversationsInfo); + MessagingDatabaseManager::getInstance().findEmailConversations(*callback, &conversationsInfo); if (ret.IsError()) return ret; - convListCount = conversationsInfo.size(); - LoggerD("Found %d conversations", convListCount); + LoggerD("Found %zu conversations", conversationsInfo.size()); - for (int i = 0; i < convListCount; ++i) { - std::shared_ptr conversation; - PlatformResult ret = MessageConversation::convertEmailConversationToObject( - conversationsInfo.at(i).id, &conversation); - if (ret.IsError()) { - LoggerE("%d (%s)", ret.error_code(), (ret.message()).c_str()); - return ret; - } - conversation->setUnreadMessages(conversationsInfo.at(i).unreadMessages); + for (const auto& conversation : conversationsInfo) { callback->addConversation(conversation); } diff --git a/src/messaging/message_conversation.cc b/src/messaging/message_conversation.cc index 5d1ea2c..d320a3a 100644 --- a/src/messaging/message_conversation.cc +++ b/src/messaging/message_conversation.cc @@ -43,6 +43,85 @@ MessageConversation::MessageConversation() ScopeLogger("Message Conversation constructor."); } +namespace { + +std::string SanitizeUtf8String(const std::string& input) { + ScopeLogger(); + + std::string result = input; + const gchar* end = nullptr; + + while (FALSE == g_utf8_validate(result.c_str(), -1, &end)) { + result = result.substr(0, end - result.c_str()); + } + + return result; +} + +std::vector SanitizeUtf8StringVector(const std::vector& string_vector) { + ScopeLogger(); + + std::vector sanitized_strings; + for (const auto& string : string_vector) { + sanitized_strings.push_back(SanitizeUtf8String(string)); + } + + return sanitized_strings; +} + +std::vector GetSanitizedEmailRecipientsFromCString(const char* recipients_c_string) { + ScopeLogger(); + + if (!recipients_c_string) { + return {}; + } + + return SanitizeUtf8StringVector(Message::getEmailRecipientsFromStruct(recipients_c_string)); +} + +std::string GetSanitizedStringFromCString(const char* c_string) { + ScopeLogger(); + + if (!c_string) { + return ""; + } + + return SanitizeUtf8String(c_string); +} + +std::string GetSingleSanitizedEmailAddressFromCString(const char* address_c_string) { + ScopeLogger(); + + if (!address_c_string) { + return ""; + } + + return SanitizeUtf8String(MessagingUtil::extractSingleEmailAddress(address_c_string)); +} + +} // namespace + +MessageConversation::MessageConversation(const email_mail_data_t& mail_data) + : m_conversation_id(mail_data.thread_id), + m_conversation_type(MessageType::EMAIL), + m_timestamp(mail_data.date_time), + m_count(mail_data.thread_item_count), + m_unread_messages(0), + m_preview(GetSanitizedStringFromCString(mail_data.preview_text)), + m_conversation_subject(GetSanitizedStringFromCString(mail_data.subject)), + m_is_read(mail_data.flags_seen_field), + m_from(GetSingleSanitizedEmailAddressFromCString(mail_data.full_address_from)), + m_to(GetSanitizedEmailRecipientsFromCString(mail_data.full_address_to)), + m_cc(GetSanitizedEmailRecipientsFromCString(mail_data.full_address_cc)), + m_bcc(GetSanitizedEmailRecipientsFromCString(mail_data.full_address_bcc)), + m_last_message_id(mail_data.mail_id) { + ScopeLogger(); + auto result = initializeUnreadMessagesCount(); + if (result.IsError()) { + LoggerE("Could not initialize unreadMessages. conversation id: %d", m_conversation_id); + } +} + MessageConversation::~MessageConversation() { ScopeLogger("Message Conversation destructor."); } @@ -327,19 +406,19 @@ PlatformResult MessageConversation::convertEmailConversationToObject( if (resultMail->full_address_from[0] != '\0') { conversation->m_from = - MessagingUtil::extractSingleEmailAddress(resultMail->full_address_from); + GetSingleSanitizedEmailAddressFromCString(resultMail->full_address_from); } if (mailData->full_address_to != NULL) { - conversation->m_to = Message::getEmailRecipientsFromStruct(mailData->full_address_to); + conversation->m_to = GetSanitizedEmailRecipientsFromCString(mailData->full_address_to); } if (mailData->full_address_cc != NULL) { - conversation->m_cc = Message::getEmailRecipientsFromStruct(mailData->full_address_cc); + conversation->m_cc = GetSanitizedEmailRecipientsFromCString(mailData->full_address_cc); } if (mailData->full_address_bcc != NULL) { - conversation->m_bcc = Message::getEmailRecipientsFromStruct(mailData->full_address_bcc); + conversation->m_bcc = GetSanitizedEmailRecipientsFromCString(mailData->full_address_bcc); } conversation->m_last_message_id = resultMail->mail_id; @@ -485,17 +564,113 @@ bool MessageConversation::isMatchingAttributeRange(const std::string& attribute_ return false; } -std::string MessageConversation::SanitizeUtf8String(const std::string& input) { +common::PlatformResult MessageConversation::initializeUnreadMessagesCount() { ScopeLogger(); - std::string result = input; - const gchar* end = nullptr; + email_list_filter_t filter_list = {}; + memset(&filter_list, 0, sizeof(email_list_filter_t)); - while (FALSE == g_utf8_validate(result.c_str(), -1, &end)) { - result = result.substr(0, end - result.c_str()); + filter_list.list_filter_item_type = EMAIL_LIST_FILTER_ITEM_RULE; + filter_list.list_filter_item.rule.rule_type = EMAIL_LIST_FILTER_RULE_EQUAL; + filter_list.list_filter_item.rule.target_attribute = EMAIL_MAIL_ATTRIBUTE_THREAD_ID; + filter_list.list_filter_item.rule.key_value.integer_type_value = m_conversation_id; + + int total_messages = 0; + int unread_messages = 0; + auto result = email_count_mail(&filter_list, 1, &total_messages, &unread_messages); + if (EMAIL_ERROR_NONE != result) { + return LogAndCreateResult( + ErrorCode::UNKNOWN_ERR, "Error while getting data from database.", + ("email_count_mail error: %d (%s)", result, get_error_message(result))); } - return result; + m_unread_messages = unread_messages; + + return PlatformResult{ErrorCode::NO_ERROR}; +} + +const MessageConversation::MessageConversationComparatorMap + MessageConversation::m_message_conversation_comparators = { + { + "id", [] (const ConversationPtr& a, const ConversationPtr& b) { + return std::to_string(a->m_conversation_id) < std::to_string(b->m_conversation_id); + } + }, + { + "timestamp", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_timestamp < b->m_timestamp; + } + }, + { + "messageCount", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_count < b->m_count; + } + }, + { + "unreadMessages", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_unread_messages < b->m_unread_messages; + } + }, + { + "preview", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_preview < b->m_preview; + } + }, + { + "subject", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_conversation_subject < b->m_conversation_subject; + } + }, + { + "isRead", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_is_read < b->m_is_read; + } + }, + { + "from", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_from < b->m_from; + } + }, + { + "to", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_to < b->m_to; + } + }, + { + "cc", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_cc < b->m_cc; + } + }, + { + "bcc", [] (const ConversationPtr& a, const ConversationPtr& b) { + return a->m_bcc < b->m_bcc; + } + }, + { + "lastMessageId", [] (const ConversationPtr& a, const ConversationPtr& b) { + return std::to_string(a->m_last_message_id) < std::to_string(b->m_last_message_id); + } + }, + { + /* Every record has EMAIL type - no element is "greater than" any other. */ + "type", [] (const ConversationPtr& a, const ConversationPtr& b) { + return false; + } + } +}; + +MessageConversation::MessageConversationComparator MessageConversation::getComparator( + const std::string& attribute) { + auto comparator_it = m_message_conversation_comparators.find(attribute); + if (std::end(m_message_conversation_comparators) != comparator_it) { + return comparator_it->second; + } + + auto default_comparator = [](const ConversationPtr& a, const ConversationPtr& b) { + return false; + }; + + return default_comparator; } } // messaging diff --git a/src/messaging/message_conversation.h b/src/messaging/message_conversation.h index 1d01ff5..273f526 100644 --- a/src/messaging/message_conversation.h +++ b/src/messaging/message_conversation.h @@ -25,6 +25,7 @@ #include #include #include "MsgCommon/AbstractFilter.h" +#include "common/platform_result.h" #include "messaging_util.h" namespace extension { @@ -43,6 +44,7 @@ typedef std::vector ConversationPtrVector; class MessageConversation : public tizen::FilterableObject { public: MessageConversation(); + MessageConversation(const email_mail_data_t& mail_data); ~MessageConversation(); // attributes getters @@ -94,8 +96,12 @@ class MessageConversation : public tizen::FilterableObject { virtual bool isMatchingAttributeRange(const std::string& attribute_name, tizen::AnyPtr initial_value, tizen::AnyPtr end_value) const; + using MessageConversationComparator = + std::function; + static MessageConversationComparator getComparator(const std::string& attribute); + private: - std::string SanitizeUtf8String(const std::string& input); + common::PlatformResult initializeUnreadMessagesCount(); int m_conversation_id; MessageType m_conversation_type; @@ -110,6 +116,9 @@ class MessageConversation : public tizen::FilterableObject { std::vector m_cc; std::vector m_bcc; int m_last_message_id; + + using MessageConversationComparatorMap = std::map; + static const MessageConversationComparatorMap m_message_conversation_comparators; }; } // messaging diff --git a/src/messaging/messaging_database_manager.cc b/src/messaging/messaging_database_manager.cc index 4e4edff..03d190d 100644 --- a/src/messaging/messaging_database_manager.cc +++ b/src/messaging/messaging_database_manager.cc @@ -28,8 +28,10 @@ #include "common/logger.h" #include "common/platform_exception.h" +#include "common/scope_exit.h" #include "conversation_callback_data.h" +#include "message_conversation.h" #include "messaging_database_manager.h" #include "messaging_manager.h" @@ -143,31 +145,6 @@ MessagingDatabaseManager::MessagingDatabaseManager() { std::make_pair("msgId", AttributeInfo("B.MSG_ID", INTEGER, PrimitiveType_String))); m_msg_conv_attr_map.insert( std::make_pair("direction", AttributeInfo("B.MSG_DIRECTION", INTEGER, PrimitiveType_String))); - - // Attributes map for email conversations ===================================== - m_email_conv_attr_map.insert( - std::make_pair("id", AttributeInfo("thread_id", INTEGER, PrimitiveType_String))); - m_email_conv_attr_map.insert( - std::make_pair("serviceId", AttributeInfo("account_id", INTEGER, PrimitiveType_String))); - m_email_conv_attr_map.insert( - std::make_pair("type", AttributeInfo("account_id", INTEGER, PrimitiveType_String))); - m_email_conv_attr_map.insert( - std::make_pair("timestamp", AttributeInfo("date_time", DATETIME, PrimitiveType_Time))); - m_email_conv_attr_map.insert(std::make_pair( - "messageCount", AttributeInfo("thread_item_count", INTEGER, PrimitiveType_ULong))); - m_email_conv_attr_map.insert(std::make_pair( - "unreadMessages", AttributeInfo(std::string("thread_id IN (SELECT thread_id ") + - std::string("FROM mail_tbl WHERE flags_seen_field = 0 ") + - std::string("GROUP BY thread_id HAVING COUNT(thread_id)"), - INTEGER, PrimitiveType_ULong))); - m_email_conv_attr_map.insert( - std::make_pair("preview", AttributeInfo("preview_text", TEXT, PrimitiveType_String))); - m_email_conv_attr_map.insert( - std::make_pair("subject", AttributeInfo("subject", TEXT, PrimitiveType_String))); - m_email_conv_attr_map.insert( - std::make_pair("from", AttributeInfo("full_address_from", TEXT, PrimitiveType_String))); - m_email_conv_attr_map.insert( - std::make_pair("to", AttributeInfo("full_address_to", TEXT, PrimitiveType_String))); } MessagingDatabaseManager::~MessagingDatabaseManager() { @@ -891,69 +868,126 @@ PlatformResult MessagingDatabaseManager::findShortMessageConversations( return PlatformResult(ErrorCode::NO_ERROR); } -PlatformResult MessagingDatabaseManager::findEmailConversations( - ConversationCallbackData* callback, std::vector* result) { +namespace { + +void convertToMessageConversations(const email_mail_data_t* mailData, int mailDataCount, + ConversationPtrVector* conversations) { ScopeLogger(); - std::ostringstream sqlWhereClause; - int resultsCount; - email_mail_data_t* results; - std::map conversationsBag; - std::vector conversationsInfo; - // Adding filters query - AbstractFilterPtr filter = callback->getFilter(); - SortModePtr sortMode = callback->getSortMode(); - long limit = callback->getLimit(); - long offset = callback->getOffset(); - MessageType msgType = callback->getMessageServiceType(); - int accountId = callback->getAccountId(); + conversations->reserve(static_cast(mailDataCount)); + for (int i = 0; i < mailDataCount; ++i) { + conversations->push_back(std::make_shared(mailData[i])); + } +} - std::string filters_query; - PlatformResult ret = - addFilters(filter, sortMode, limit, offset, m_email_conv_attr_map, msgType, &filters_query); - if (ret.IsError()) { - LoggerE("Add filters failed (%s)", ret.message().c_str()); - return ret; +void filterMessageConversations(const AbstractFilter& filter, + ConversationPtrVector* conversations) { + ScopeLogger(); + + auto toBeFilteredOut = [&filter](const ConversationPtr& conversation) { + return !filter.isMatching(conversation.get()); + }; + + conversations->erase( + std::remove_if(std::begin(*conversations), std::end(*conversations), toBeFilteredOut), + std::end(*conversations)); +} + +void sortConversations(const SortMode& sortMode, ConversationPtrVector* conversations) { + ScopeLogger(); + + const std::string attribute = sortMode.getAttributeName(); + auto comparator = MessageConversation::getComparator(attribute); + + if (SortModeOrder::ASC == sortMode.getOrder()) { + std::sort(conversations->begin(), conversations->end(), comparator); + } else { + std::sort(conversations->rbegin(), conversations->rend(), comparator); } - sqlWhereClause << "WHERE " << m_email_conv_attr_map["serviceId"].sql_name << " = " << accountId - << " AND " << filters_query; - LoggerD("%s", sqlWhereClause.str().c_str()); +} - // Getting results from database - msg_error_t err = - email_query_mails(const_cast(sqlWhereClause.str().c_str()), &results, &resultsCount); - if (EMAIL_ERROR_NONE != err) { - LoggerE("Getting mail list fail [%d]", err); +} // namespace - if (EMAIL_ERROR_MAIL_NOT_FOUND == err) { - resultsCount = 0; +PlatformResult MessagingDatabaseManager::retrieveEmailThreadsFromDatabase( + const ConversationCallbackData& findEmailConversationsData, + ConversationPtrVector* conversations) { + ScopeLogger(); + + std::string limitAndOffset; + PlatformResult result = PlatformResult{ErrorCode::UNKNOWN_ERR}; + AttributeInfoMap emptyAttributeMap; + /* + * Sorting and filtering is done programmatically, after data retrieval from the database, + * because some parameters cannot be used in ORDER BY/WHERE or both clauses, + * passed to the email_query_mails() - e.g. there is no "unreadMessages" column in the. + * + * For that reason both filter and sort mode arguments of addFilters are null pointers. + */ + result = addFilters(AbstractFilterPtr{nullptr}, SortModePtr{nullptr}, + findEmailConversationsData.getLimit(), findEmailConversationsData.getOffset(), + emptyAttributeMap, findEmailConversationsData.getMessageServiceType(), + &limitAndOffset); + + if (result.IsError()) { + LoggerE("addFilters failed (%s)", result.message().c_str()); + return result; + } + + const std::string isLastMessageInThread = + "(MAIL_ID IN " + "(SELECT MAIL_ID " + "FROM " + "(SELECT MAIL_ID, MAX(DATE_TIME) " + "FROM MAIL_TBL " + "GROUP BY THREAD_ID)))"; + + const std::string isServiceAccountId = + "account_id = " + std::to_string(findEmailConversationsData.getAccountId()); + std::string sqlWhereClause = + "WHERE " + isLastMessageInThread + " AND " + isServiceAccountId + " " + limitAndOffset; + + LoggerD("%s", sqlWhereClause.c_str()); + + int threadsCount = 0; + email_mail_data_t* threadsList = nullptr; + + SCOPE_EXIT { + if (threadsList) { + email_free_mail_data(&threadsList, threadsCount); + } + }; + + msg_error_t errorCode = email_query_mails(&sqlWhereClause[0], &threadsList, &threadsCount); + if (EMAIL_ERROR_NONE != errorCode) { + if (EMAIL_ERROR_MAIL_NOT_FOUND == errorCode) { + threadsCount = 0; } else { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error while getting data from database.", - ("email_query_mails error: %d (%s)", err, get_error_message(err))); + return LogAndCreateResult( + ErrorCode::UNKNOWN_ERR, "Error while getting data from database.", + ("email_query_mails error: %d (%s)", errorCode, get_error_message(errorCode))); } } - // Assigning found emails to conversation - for (int i = 0; i < resultsCount; ++i) { - if (conversationsBag.find(results[i].thread_id) == conversationsBag.end()) { - EmailConversationInfo info; - info.id = results[i].thread_id; - conversationsInfo.push_back(info); - conversationsBag.insert(std::make_pair(results[i].thread_id, 0)); - } + convertToMessageConversations(threadsList, threadsCount, conversations); + return PlatformResult{ErrorCode::NO_ERROR}; +} - if (!(static_cast(results[i].flags_seen_field))) { - ++conversationsBag[results[i].thread_id]; - } +PlatformResult MessagingDatabaseManager::findEmailConversations( + const ConversationCallbackData& findEmailConversationsData, + ConversationPtrVector* conversations) { + ScopeLogger(); + + auto result = retrieveEmailThreadsFromDatabase(findEmailConversationsData, conversations); + if (result.IsError()) { + return result; } - for (std::vector::iterator it = conversationsInfo.begin(); - it != conversationsInfo.end(); ++it) { - (*it).unreadMessages = conversationsBag[(*it).id]; + filterMessageConversations(*findEmailConversationsData.getFilter(), conversations); + + if (findEmailConversationsData.getSortMode()) { + sortConversations(*findEmailConversationsData.getSortMode(), conversations); } - email_free_mail_data(&results, resultsCount); - *result = conversationsInfo; return PlatformResult(ErrorCode::NO_ERROR); } diff --git a/src/messaging/messaging_database_manager.h b/src/messaging/messaging_database_manager.h index a241492..c10c2ff 100644 --- a/src/messaging/messaging_database_manager.h +++ b/src/messaging/messaging_database_manager.h @@ -26,6 +26,7 @@ #include "common/platform_result.h" #include "find_msg_callback_user_data.h" +#include "message_conversation.h" //#include "ConversationCallbackData.h" namespace extension { @@ -82,8 +83,8 @@ class MessagingDatabaseManager { std::pair* result); common::PlatformResult findShortMessageConversations(ConversationCallbackData* callback, std::vector* result); - common::PlatformResult findEmailConversations(ConversationCallbackData* callback, - std::vector* result); + common::PlatformResult findEmailConversations(const ConversationCallbackData& callback, + ConversationPtrVector* conversations); private: MessagingDatabaseManager(); @@ -109,12 +110,14 @@ class MessagingDatabaseManager { common::PlatformResult addFilters(tizen::AbstractFilterPtr filter, tizen::SortModePtr sortMode, long limit, long offset, AttributeInfoMap& attributeMap, MessageType msgType, std::string* result); + common::PlatformResult retrieveEmailThreadsFromDatabase( + const ConversationCallbackData& findEmailConversationsData, + ConversationPtrVector* conversations); AttributeInfoMap m_msg_attr_map; AttributeInfoMap m_email_attr_map; AttributeInfoMap m_msg_conv_attr_map; - AttributeInfoMap m_email_conv_attr_map; }; } // Messaging -- 2.7.4 From 41d79756a053fc601f1f34ec41e1308030b8ddb1 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Fri, 19 Oct 2018 12:03:02 +0200 Subject: [PATCH 05/16] [Messaging] Refactor MessageConversation related code Refactoring was requested to get rid of duplicated and unnecessary code. [Verification] TCT pass rate: 100% Change-Id: Iee2eacf50ca89ea60e89b283d3aac24111cfd5e5 Signed-off-by: Pawel Wasowski --- src/messaging/message.cc | 5 ++ src/messaging/message_conversation.cc | 112 +++++++--------------------- src/messaging/messaging_database_manager.cc | 2 + src/messaging/messaging_util.cc | 37 ++++++++- src/messaging/messaging_util.h | 3 + 5 files changed, 70 insertions(+), 89 deletions(-) diff --git a/src/messaging/message.cc b/src/messaging/message.cc index 5fdbbc6..15935d0 100644 --- a/src/messaging/message.cc +++ b/src/messaging/message.cc @@ -1517,6 +1517,11 @@ std::vector Message::split(const std::string& input, char delimiter std::vector Message::getEmailRecipientsFromStruct(const char* recipients) { ScopeLogger(); + + if (!recipients) { + return {}; + } + std::vector tmp = Message::split(recipients, ';'); for (std::vector::iterator it = tmp.begin(); it != tmp.end(); ++it) { *it = MessagingUtil::ltrim(*it); diff --git a/src/messaging/message_conversation.cc b/src/messaging/message_conversation.cc index d320a3a..4644b29 100644 --- a/src/messaging/message_conversation.cc +++ b/src/messaging/message_conversation.cc @@ -43,77 +43,19 @@ MessageConversation::MessageConversation() ScopeLogger("Message Conversation constructor."); } -namespace { - -std::string SanitizeUtf8String(const std::string& input) { - ScopeLogger(); - - std::string result = input; - const gchar* end = nullptr; - - while (FALSE == g_utf8_validate(result.c_str(), -1, &end)) { - result = result.substr(0, end - result.c_str()); - } - - return result; -} - -std::vector SanitizeUtf8StringVector(const std::vector& string_vector) { - ScopeLogger(); - - std::vector sanitized_strings; - for (const auto& string : string_vector) { - sanitized_strings.push_back(SanitizeUtf8String(string)); - } - - return sanitized_strings; -} - -std::vector GetSanitizedEmailRecipientsFromCString(const char* recipients_c_string) { - ScopeLogger(); - - if (!recipients_c_string) { - return {}; - } - - return SanitizeUtf8StringVector(Message::getEmailRecipientsFromStruct(recipients_c_string)); -} - -std::string GetSanitizedStringFromCString(const char* c_string) { - ScopeLogger(); - - if (!c_string) { - return ""; - } - - return SanitizeUtf8String(c_string); -} - -std::string GetSingleSanitizedEmailAddressFromCString(const char* address_c_string) { - ScopeLogger(); - - if (!address_c_string) { - return ""; - } - - return SanitizeUtf8String(MessagingUtil::extractSingleEmailAddress(address_c_string)); -} - -} // namespace - MessageConversation::MessageConversation(const email_mail_data_t& mail_data) : m_conversation_id(mail_data.thread_id), m_conversation_type(MessageType::EMAIL), m_timestamp(mail_data.date_time), m_count(mail_data.thread_item_count), m_unread_messages(0), - m_preview(GetSanitizedStringFromCString(mail_data.preview_text)), - m_conversation_subject(GetSanitizedStringFromCString(mail_data.subject)), + m_preview(MessagingUtil::SanitizeUtf8String(mail_data.preview_text)), + m_conversation_subject(MessagingUtil::SanitizeUtf8String(mail_data.subject)), m_is_read(mail_data.flags_seen_field), - m_from(GetSingleSanitizedEmailAddressFromCString(mail_data.full_address_from)), - m_to(GetSanitizedEmailRecipientsFromCString(mail_data.full_address_to)), - m_cc(GetSanitizedEmailRecipientsFromCString(mail_data.full_address_cc)), - m_bcc(GetSanitizedEmailRecipientsFromCString(mail_data.full_address_bcc)), + m_from(MessagingUtil::extractSingleEmailAddress(mail_data.full_address_from)), + m_to(Message::getEmailRecipientsFromStruct(mail_data.full_address_to)), + m_cc(Message::getEmailRecipientsFromStruct(mail_data.full_address_cc)), + m_bcc(Message::getEmailRecipientsFromStruct(mail_data.full_address_bcc)), m_last_message_id(mail_data.mail_id) { ScopeLogger(); auto result = initializeUnreadMessagesCount(); @@ -406,20 +348,12 @@ PlatformResult MessageConversation::convertEmailConversationToObject( if (resultMail->full_address_from[0] != '\0') { conversation->m_from = - GetSingleSanitizedEmailAddressFromCString(resultMail->full_address_from); + MessagingUtil::extractSingleEmailAddress(resultMail->full_address_from); } - if (mailData->full_address_to != NULL) { - conversation->m_to = GetSanitizedEmailRecipientsFromCString(mailData->full_address_to); - } - - if (mailData->full_address_cc != NULL) { - conversation->m_cc = GetSanitizedEmailRecipientsFromCString(mailData->full_address_cc); - } - - if (mailData->full_address_bcc != NULL) { - conversation->m_bcc = GetSanitizedEmailRecipientsFromCString(mailData->full_address_bcc); - } + conversation->m_to = Message::getEmailRecipientsFromStruct(mailData->full_address_to); + conversation->m_cc = Message::getEmailRecipientsFromStruct(mailData->full_address_cc); + conversation->m_bcc = Message::getEmailRecipientsFromStruct(mailData->full_address_bcc); conversation->m_last_message_id = resultMail->mail_id; @@ -457,11 +391,11 @@ void MessageConversation::setUnreadMessages(int unread_messages) { } void MessageConversation::setPreview(std::string preview) { - m_preview = SanitizeUtf8String(preview); + m_preview = MessagingUtil::SanitizeUtf8String(preview); } void MessageConversation::setSubject(std::string conversation_subject) { - m_conversation_subject = SanitizeUtf8String(conversation_subject); + m_conversation_subject = MessagingUtil::SanitizeUtf8String(conversation_subject); } void MessageConversation::setIsRead(bool is_read) { @@ -589,6 +523,15 @@ common::PlatformResult MessageConversation::initializeUnreadMessagesCount() { return PlatformResult{ErrorCode::NO_ERROR}; } +namespace { + +bool defaultConversationComparator(const ConversationPtr&, const ConversationPtr&) { + return false; +} + +} // namespace + +// clang-format off const MessageConversation::MessageConversationComparatorMap MessageConversation::m_message_conversation_comparators = { { @@ -653,24 +596,19 @@ const MessageConversation::MessageConversationComparatorMap }, { /* Every record has EMAIL type - no element is "greater than" any other. */ - "type", [] (const ConversationPtr& a, const ConversationPtr& b) { - return false; - } + "type", defaultConversationComparator } }; +// clang-format on MessageConversation::MessageConversationComparator MessageConversation::getComparator( - const std::string& attribute) { + const std::string& attribute) { auto comparator_it = m_message_conversation_comparators.find(attribute); if (std::end(m_message_conversation_comparators) != comparator_it) { return comparator_it->second; } - auto default_comparator = [](const ConversationPtr& a, const ConversationPtr& b) { - return false; - }; - - return default_comparator; + return defaultConversationComparator; } } // messaging diff --git a/src/messaging/messaging_database_manager.cc b/src/messaging/messaging_database_manager.cc index 03d190d..6d87bd2 100644 --- a/src/messaging/messaging_database_manager.cc +++ b/src/messaging/messaging_database_manager.cc @@ -933,6 +933,7 @@ PlatformResult MessagingDatabaseManager::retrieveEmailThreadsFromDatabase( return result; } + // clang-format off const std::string isLastMessageInThread = "(MAIL_ID IN " "(SELECT MAIL_ID " @@ -940,6 +941,7 @@ PlatformResult MessagingDatabaseManager::retrieveEmailThreadsFromDatabase( "(SELECT MAIL_ID, MAX(DATE_TIME) " "FROM MAIL_TBL " "GROUP BY THREAD_ID)))"; + // clang-format on const std::string isServiceAccountId = "account_id = " + std::to_string(findEmailConversationsData.getAccountId()); diff --git a/src/messaging/messaging_util.cc b/src/messaging/messaging_util.cc index d919911..875844b 100644 --- a/src/messaging/messaging_util.cc +++ b/src/messaging/messaging_util.cc @@ -239,13 +239,23 @@ std::string MessagingUtil::extractSingleEmailAddress(const std::string& address) // then extract email address from the inside if (found_begin != std::string::npos && found_end != std::string::npos && found_begin < found_end) { - return address.substr(found_begin + 1, found_end - found_begin - 1); + return SanitizeUtf8String(address.substr(found_begin + 1, found_end - found_begin - 1)); } else { // return unmodified source string - return address; + return SanitizeUtf8String(address); } } +std::string MessagingUtil::extractSingleEmailAddress(const char* address) { + ScopeLogger(); + + if (!address) { + return {}; + } + + return extractSingleEmailAddress(std::string{address}); +} + std::vector MessagingUtil::extractEmailAddresses( const std::vector& addresses) { ScopeLogger(); @@ -1138,6 +1148,29 @@ PlatformResult MessagingUtil::jsonToMessageConversation( return PlatformResult(ErrorCode::NO_ERROR); } +std::string MessagingUtil::SanitizeUtf8String(const std::string& input) { + ScopeLogger(); + + std::string result = input; + const gchar* end = nullptr; + + while (FALSE == g_utf8_validate(result.c_str(), -1, &end)) { + result = result.substr(0, end - result.c_str()); + } + + return result; +} + +std::string MessagingUtil::SanitizeUtf8String(const char* input) { + ScopeLogger(); + + if (!input) { + return {}; + } + + return SanitizeUtf8String(std::string{input}); +} + PostQueue::PostQueue(MessagingInstance& instance) : instance_(instance) { ScopeLogger("this: [%p]", this); } diff --git a/src/messaging/messaging_util.h b/src/messaging/messaging_util.h index 7ccd031..6af1d6c 100644 --- a/src/messaging/messaging_util.h +++ b/src/messaging/messaging_util.h @@ -120,6 +120,7 @@ class MessagingUtil { static std::string messageTypeToString(MessageType type); static std::string ltrim(const std::string& input); static std::string extractSingleEmailAddress(const std::string& address); + static std::string extractSingleEmailAddress(const char* address); static std::vector extractEmailAddresses(const std::vector& addresses); static picojson::value messageBodyToJson(std::shared_ptr body); @@ -164,6 +165,8 @@ class MessagingUtil { static common::PlatformResult loadFileContentToString(const std::string& file_path, std::string* result); static std::string messageStatusToString(MessageStatus status); + static std::string SanitizeUtf8String(const std::string& input); + static std::string SanitizeUtf8String(const char* input); private: static common::PlatformResult jsonFilterToAbstractFilter(const picojson::object& json, -- 2.7.4 From 167de1ac0fc699f65fc1a6eb62bee31c76a45997 Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Mon, 22 Oct 2018 14:16:20 +0200 Subject: [PATCH 06/16] [version] 2.28 Change-Id: Icfae075f33085630150a69087c7dc8ccd78c9697 --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 20abcdc..41308a9 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.27 +Version: 2.28 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From fa478b91fc7685b8bc143788f5239e05409f7246 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Piotr=20Kosko/Native/Web=20API=20=28SWP=29=20/SRPOL/Profess?= =?utf8?q?ional/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 19 Nov 2018 14:46:34 +0100 Subject: [PATCH 07/16] [Common] Added missing return statement MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit [Bug] When parsing invalid message, exception is catched, but the control is not finished. Going to following lines, other exception would be raised. We need to finish execution for invalid message. [Verification] Code compiles without errors. Change-Id: I65784e775b9a765332c4a1f0a19b8184e896872c Signed-off-by: Piotr Kosko/Native/Web API (SWP) /SRPOL/Professional/삼성전자 --- src/utils/utils_api.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/utils_api.js b/src/utils/utils_api.js index 2eef03e..f99b4e4 100644 --- a/src/utils/utils_api.js +++ b/src/utils/utils_api.js @@ -1020,7 +1020,8 @@ var NativeManager = function(extension) { try { var msg = JSON_.parse(json); } catch (error) { - xwalk.utils.error('Invalid JSON received: ' + json); + xwalk.utils.error('Ignoring message - Invalid JSON received: ' + json); + return; } var id; -- 2.7.4 From 44aac3774a78e994142793f3e582fad53284cbae Mon Sep 17 00:00:00 2001 From: =?utf8?q?Piotr=20Kosko/Native/Web=20API=20=28SWP=29=20/SRPOL/Profess?= =?utf8?q?ional/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 19 Nov 2018 14:56:05 +0100 Subject: [PATCH 08/16] [version] 2.29 Change-Id: I27c09aef9adc3ba125477521e95a85633b0e702d --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 41308a9..8d63276 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.28 +Version: 2.29 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From bb52aa78d47349922042482ac55a89746ecf4b51 Mon Sep 17 00:00:00 2001 From: Lukasz Bardeli Date: Wed, 5 Dec 2018 10:18:08 +0100 Subject: [PATCH 09/16] [MessagePort] Fixed issue with removeMessagePortListener without any added earlier If any listener was added before remove then error was thrown 'Cannot read property length of undefined' [Verification] Code compiles without error. TCT passrate 100% Change-Id: I96000345ae483a9fa2c0b50a6be0ece427ce8e1b Signed-off-by: Lukasz Bardeli --- src/messageport/messageport_api.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/messageport/messageport_api.js b/src/messageport/messageport_api.js index ab612f1..4883d79 100755 --- a/src/messageport/messageport_api.js +++ b/src/messageport/messageport_api.js @@ -251,22 +251,22 @@ LocalMessagePort.prototype.removeMessagePortListener = function(watchId) { {'name' : 'watchId', 'type': types_.LONG, 'nullable': false, 'optional': false } ]); - var to_delete; + var toDelete; var listeners = callbacks[ports[this.messagePortName]]; - for (var i = 0, j = listeners.length; i < j; i++) { - var listener_id = listeners[i][1]; - if (watchId == listener_id) { - to_delete = i; + for (var key in listeners) { + var listenerId = listeners[key][1]; + if (watchId == listenerId) { + toDelete = key; break; } } - if (typeof to_delete === 'undefined') + if (typeof toDelete === 'undefined') throw new WebAPIException(WebAPIException.NOT_FOUND_ERR, 'The port of the target application is not found.'); - listeners.splice(to_delete, 1); + listeners.splice(toDelete, 1); }; -- 2.7.4 From 25ae263f8cabeed0f6dd4b061e601ef356c447e6 Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Wed, 19 Dec 2018 19:05:20 +0100 Subject: [PATCH 10/16] [Messaging] Prevent crash on getMessageServices call Calling tizen.messaging.getMessageServices() multiple times at short intervals used to cause a crash, due to race condition, occurring between different threads, modifying the same MessagingManager instance's fields. The fix moves execution of the underlying implementation to the main thread - it is not called concurrently. The function execution time is typically below 2 ms, so moving it to the main thread should not worsen user experience. [Verification] tct-tizen-messaging-email-tests pass rate: 100% tct-tizen-messaging-sms-tests pass rate: 100% tct-tizen-messaging-mms-tests pass rate: 100% A code snippet, that used to cause a crash, does not cause crash now: for (var i = 0; i < 1000; ++i) { tizen.messaging.getMessageServices('messaging.email', s=>{console.log(s);}, e=>{console.error(e);}); } Change-Id: I2f140281e64aeffea1ad9ca15f99ee38378693d3 Signed-off-by: Pawel Wasowski --- src/messaging/messaging_manager.cc | 286 ++++++++++++++++++------------------- src/messaging/messaging_manager.h | 4 + 2 files changed, 146 insertions(+), 144 deletions(-) diff --git a/src/messaging/messaging_manager.cc b/src/messaging/messaging_manager.cc index 566f198..d0e20f9 100644 --- a/src/messaging/messaging_manager.cc +++ b/src/messaging/messaging_manager.cc @@ -27,6 +27,7 @@ #include "common/logger.h" #include "common/picojson.h" #include "common/platform_exception.h" +#include "common/scope_exit.h" #include "common/task-queue.h" #include "common/tools.h" @@ -87,170 +88,167 @@ MessagingManager::~MessagingManager() { delete m_mms_service.second; } } +namespace { -static gboolean callbackCompleted(const std::shared_ptr& user_data) { +std::string getAccountName(const email_account_t& email_account) { ScopeLogger(); - std::shared_ptr response = user_data->json; - common::Instance::PostMessage(&user_data->instance_, response->serialize().c_str()); - return false; + + std::string name = "["; + if (email_account.account_name) { + name += email_account.account_name; + } + name += "] "; + name += email_account.incoming_server_user_name; + + return name; } -static void* getMsgServicesThread(const std::shared_ptr& user_data) { +} // namespace + +PlatformResult MessagingManager::initEmailServices() { ScopeLogger(); - std::shared_ptr response = user_data->json; - picojson::object& obj = response->get(); - MessageType type = MessageType::UNDEFINED; - - auto platform_result = MessagingUtil::stringToMessageType(user_data->type, &type); - // after extraction of input data, remove it - - if (platform_result) { - switch (type) { - case MessageType::SMS: - LoggerD("MessageService for SMS"); - { - if (user_data->sms_service->second) { - delete user_data->sms_service->second; - } - - MessageService* service = - MessageServiceShortMsg::GetSmsMessageService(user_data->instance_); - - if (!service) { - platform_result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, - "MessageService for SMS creation failed"); - } else { - *(user_data->sms_service) = std::make_pair(service->getMsgServiceId(), service); - - picojson::array array; - array.push_back(picojson::value(service->toPicoJS())); - ReportSuccess(picojson::value(array), obj); - - // service is stored, so it cannot be deleted - service = nullptr; - } - } - break; + email_account_t* email_accounts = nullptr; + int count = 0; + SCOPE_EXIT { + email_free_account(&email_accounts, count); + }; + + int ret = email_get_account_list(&email_accounts, &count); + if (ret != EMAIL_ERROR_NONE) { + return LogAndCreateResult( + ErrorCode::UNKNOWN_ERR, "Could not get account list", + ("email_get_account_list error: %d (%s)", ret, get_error_message(ret))); + } - case MessageType::MMS: - LoggerD("MessageService for MMS"); - { - if (user_data->mms_service->second) { - delete user_data->mms_service->second; - } - - MessageService* service = - MessageServiceShortMsg::GetMmsMessageService(user_data->instance_); - - if (!service) { - platform_result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, - "MessageService for SMS creation failed"); - } else { - *(user_data->mms_service) = std::make_pair(service->getMsgServiceId(), service); - - picojson::array array; - array.push_back(picojson::value(service->toPicoJS())); - ReportSuccess(picojson::value(array), obj); - - // service is stored, so it cannot be deleted - service = nullptr; - } - } - break; + std::vector> msg_services{}; + msg_services.reserve(count); - case MessageType::EMAIL: - LoggerD("MessageService for EMAIL"); - { - email_account_t* email_accounts = nullptr; - int count = 0; - - int ntv_ret = email_get_account_list(&email_accounts, &count); - if (ntv_ret != EMAIL_ERROR_NONE) { - platform_result = LogAndCreateResult( - ErrorCode::UNKNOWN_ERR, "Error during getting account list", - ("email_get_account_list error: %d (%s)", ntv_ret, get_error_message(ntv_ret))); - } else { - std::vector msgServices; - - for (int i = 0; i < count && platform_result; ++i) { - std::string name = "["; - if (email_accounts[i].account_name) { - name += email_accounts[i].account_name; - } - name += "] "; - name += email_accounts[i].incoming_server_user_name; - LoggerD("Account[%d/%d] id: %d, name: %s", i, count, email_accounts[i].account_id, - name.c_str()); - - MessageService* service = new (std::nothrow) MessageServiceEmail( - email_accounts[i].account_id, name.c_str(), user_data->instance_); - if (!service) { - LoggerD("message service[%d] is NULL", i); - std::for_each(msgServices.begin(), msgServices.end(), - [](MessageService* service) { delete service; }); - msgServices.clear(); - platform_result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, - "MessageService for email creation failed"); - } else { - msgServices.push_back(service); - } - - // service is stored, so it cannot be deleted - service = nullptr; - } - - email_free_account(&email_accounts, count); - - if (platform_result) { - std::map& email_services = *(user_data->services_map); - std::for_each(email_services.begin(), email_services.end(), - [](std::pair el) { delete el.second; }); - email_services.clear(); - - std::vector response; - std::for_each(msgServices.begin(), msgServices.end(), - [&response, &email_services](MessageService* service) { - response.push_back(picojson::value(service->toPicoJS())); - email_services.insert(std::pair( - service->getMsgServiceId(), service)); - }); - ReportSuccess(picojson::value(response), obj); - } - } - } - break; - default: - platform_result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Service type is undefined"); + for (int i = 0; i < count; ++i) { + /* const reference extends the lifetime of the temporary object, + so it's still valid after returning from a function */ + const auto& name = getAccountName(email_accounts[i]); + LoggerD("Account[%d/%d] id: %d, name: %s", i, count, email_accounts[i].account_id, + name.c_str()); + + std::unique_ptr service{ + new (std::nothrow) MessageServiceEmail{email_accounts[i].account_id, name, instance_}}; + + if (!service) { + LoggerD("message service[%d] is NULL", i); + return PlatformResult{ErrorCode::UNKNOWN_ERR, "An unknown error occurred"}; + } else { + msg_services.push_back(std::move(service)); } - } else { - platform_result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unsupported service type"); } - if (!platform_result) { - LoggerE("Unknown error"); - ReportError(platform_result, &obj); + // clearing the map to avoid problems with refreshing the map after removing account + m_email_services.clear(); + for (auto& service : msg_services) { + m_email_services.insert(std::make_pair(service->getMsgServiceId(), service.get())); + service.release(); + } + + return PlatformResult{ErrorCode::NO_ERROR}; +} + +PlatformResult MessagingManager::initSmsService() { + ScopeLogger(); + + if (m_sms_service.second) { + // SMS service is already initialized + return PlatformResult{ErrorCode::NO_ERROR}; + } + + MessageService* service = MessageServiceShortMsg::GetSmsMessageService(instance_); + + if (!service) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "SMS MessageService creation failed"); + } + + m_sms_service = std::make_pair(service->getMsgServiceId(), service); + return PlatformResult{ErrorCode::NO_ERROR}; +} + +PlatformResult MessagingManager::initMmsService() { + ScopeLogger(); + + if (m_mms_service.second) { + // MMS service is already initialized + return PlatformResult{ErrorCode::NO_ERROR}; + } + + MessageService* service = MessageServiceShortMsg::GetMmsMessageService(instance_); + + if (!service) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "MMS MessageService creation failed"); } - return nullptr; + m_mms_service = std::make_pair(service->getMsgServiceId(), service); + return PlatformResult{ErrorCode::NO_ERROR}; } void MessagingManager::getMessageServices(const std::string& type, double callbackId) { ScopeLogger(); - auto json = std::shared_ptr(new picojson::value(picojson::object())); - picojson::object& obj = json->get(); - obj[JSON_CALLBACK_ID] = picojson::value(callbackId); + picojson::value response{picojson::object{}}; + picojson::object& response_object = response.get(); + response_object[JSON_CALLBACK_ID] = picojson::value(callbackId); + MessageType message_service_type = UNDEFINED; + + auto result = MessagingUtil::stringToMessageType(type, &message_service_type); + if (!result) { + ReportError(PlatformResult{ErrorCode::INVALID_VALUES_ERR, "Unknown service type: " + type}, + &response_object); + common::Instance::PostMessage(&instance_, response.serialize().c_str()); + return; + } + + response_object[JSON_RESULT] = picojson::value{picojson::array{}}; + picojson::array& service_array = response_object[JSON_RESULT].get(); + PlatformResult service_init_result = PlatformResult{ErrorCode::UNKNOWN_ERR}; + + switch (message_service_type) { + case SMS: + service_init_result = initSmsService(); + if (!service_init_result) { + break; + } + service_array.push_back(picojson::value{(m_sms_service.second)->toPicoJS()}); + break; + + case MMS: + service_init_result = initMmsService(); + if (!service_init_result) { + break; + } + service_array.push_back(picojson::value{(m_mms_service.second)->toPicoJS()}); + break; - auto user_data = std::shared_ptr(new MsgManagerCallbackData(instance_)); - user_data->type = type; - user_data->json = json; - user_data->services_map = &m_email_services; - user_data->sms_service = &m_sms_service; - user_data->mms_service = &m_mms_service; + case EMAIL: + service_init_result = initEmailServices(); + if (!service_init_result) { + break; + } + for (const auto& email_service : m_email_services) { + service_array.push_back(picojson::value{(email_service.second)->toPicoJS()}); + } + break; + + case UNDEFINED: + default: + service_init_result = + PlatformResult{ErrorCode::UNKNOWN_ERR, "Could not retrieve " + type + "service"}; + break; + } + + if (service_init_result) { + ReportSuccess(response_object); + } else { + ReportError(service_init_result, &response_object); + } - common::TaskQueue::GetInstance().Queue(getMsgServicesThread, - callbackCompleted, user_data); + common::Instance::PostMessage(&instance_, response.serialize().c_str()); } MessageService* MessagingManager::getMessageService(const int id) { diff --git a/src/messaging/messaging_manager.h b/src/messaging/messaging_manager.h index 220c23f..79ffb19 100644 --- a/src/messaging/messaging_manager.h +++ b/src/messaging/messaging_manager.h @@ -52,6 +52,10 @@ class MessagingManager { private: void operator=(const MessagingManager&); + common::PlatformResult initEmailServices(); + common::PlatformResult initSmsService(); + common::PlatformResult initMmsService(); + msg_handle_t m_msg_handle; std::map m_email_services; std::pair m_sms_service; -- 2.7.4 From f7798b8ed156de512904b09d7a0d312eb17b05f9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Piotr=20Kosko/Native/Web=20API=20=28SWP=29=20/SRPOL/Profess?= =?utf8?q?ional/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 9 Jan 2019 11:28:49 +0100 Subject: [PATCH 11/16] [version] 2.30 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Change-Id: I701491ee275a9540c9ddb821f420898629a3f5ca Signed-off-by: Piotr Kosko/Native/Web API (SWP) /SRPOL/Professional/삼성전자 --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 8d63276..bb867bd 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.29 +Version: 2.30 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From 4e6fb1776bdcf89acd7394403fa9c32465867b7d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Piotr=20Kosko/Native/Web=20API=20=28SWP=29=20/SRPOL/Profess?= =?utf8?q?ional/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 16 Jan 2019 09:45:10 +0100 Subject: [PATCH 12/16] [Archive][Exif] Added checking return value of fseek MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit SVACE issues: 246302, 246317 Change-Id: If4f803b9db18c352912290b25df706a21cd07853 Signed-off-by: Piotr Kosko/Native/Web API (SWP) /SRPOL/Professional/삼성전자 --- src/archive/zip_add_request.cc | 9 +++++++-- src/exif/jpeg_file.cc | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/archive/zip_add_request.cc b/src/archive/zip_add_request.cc index d6e862f..583bfea 100644 --- a/src/archive/zip_add_request.cc +++ b/src/archive/zip_add_request.cc @@ -358,9 +358,14 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node) } // Get file length - fseek(m_input_file, 0, SEEK_END); + int res = fseek(m_input_file, 0, SEEK_END); + if (0 != res) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Reading input file failed", + ("fseek failed with error! [%d]", res)); + } + const size_t in_file_size = ftell(m_input_file); - int res = fseek(m_input_file, 0, SEEK_SET); + res = fseek(m_input_file, 0, SEEK_SET); if (0 != res) { return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Reading input file failed", ("fseek failed with error! [%d]", res)); diff --git a/src/exif/jpeg_file.cc b/src/exif/jpeg_file.cc index 39bf00c..a391e73 100644 --- a/src/exif/jpeg_file.cc +++ b/src/exif/jpeg_file.cc @@ -161,7 +161,12 @@ PlatformResult JpegFile::load(const std::string& path) { } const std::size_t in_file_size = static_cast(ftell_val); - fseek(m_in_file, 0, SEEK_SET); + res = fseek(m_in_file, 0, SEEK_SET); + if (0 != res) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Reading JPEG file failed", + ("fseek failed with error! [%d]", res)); + } + LoggerD("JPEG file: [%s] size:%d", path.c_str(), in_file_size); if (0 == in_file_size) { return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "JPEG file is invalid", -- 2.7.4 From 8c3bbf1da4d974d53727d6bdfe4dda2602a976ef Mon Sep 17 00:00:00 2001 From: =?utf8?q?Piotr=20Kosko/Native/Web=20API=20=28SWP=29=20/SRPOL/Profess?= =?utf8?q?ional/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 16 Jan 2019 09:46:08 +0100 Subject: [PATCH 13/16] [version] 2.31 Change-Id: Ic8c3ade13866c7e55ee660346c3a79103f29d006 --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index bb867bd..b8c6c03 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.30 +Version: 2.31 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From 74706c9c5602781b96f1b03be2e98173ca7cfd4c Mon Sep 17 00:00:00 2001 From: Dawid Juszczak Date: Wed, 20 Mar 2019 12:19:48 +0100 Subject: [PATCH 14/16] [messaging] fixed bug with foldersupdate callback foldersupdated callback in method addFoldersChangeListener was not invoked when renamed folder [Verification] Tested on device, works fine. Also tested with new testcase added in commit: https://review.tizen.org/gerrit/#/c/test/tct/web/api/+/201880/ Change-Id: I26f3ae8991218e97d1a55cf6a0abffba622ed25f Signed-off-by: Dawid Juszczak --- src/messaging/DBus/MessageProxy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/messaging/DBus/MessageProxy.cpp b/src/messaging/DBus/MessageProxy.cpp index 19c6253..5ec6c58 100644 --- a/src/messaging/DBus/MessageProxy.cpp +++ b/src/messaging/DBus/MessageProxy.cpp @@ -283,6 +283,7 @@ PlatformResult MessageProxy::handleMailboxEvent(int account_id, int mailbox_id, break; case NOTI_MAILBOX_UPDATE: case NOTI_MAILBOX_FIELD_UPDATE: + case NOTI_MAILBOX_RENAME: ChangeListenerContainer::getInstance().callFolderUpdated(eventFolder); break; case NOTI_MAILBOX_DELETE: -- 2.7.4 From b1db67d895aecb2dcee0bda287e5c012b3345bfd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Piotr=20Kosko/Native/Web=20API=20=28PLT=29=20/SRPOL/Profess?= =?utf8?q?ional/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 8 Apr 2019 10:18:05 +0200 Subject: [PATCH 15/16] [Filesystem] listFiles method of File ignores files without access [Bug] Files with invalid SMACK labels (not allowed to be accessed by app) caused exception about missing member ("location is required argument"). Fix ignores the files that cannot be accessed. [Verification] Manually checked with Chrome console and trying to list files with invalid SMACK label. Files are being ignored. 100% passrate for filesystem module. Change-Id: I48ed83ebbba5d0c6cfa0e597f083a7a1abce17fa --- src/filesystem/filesystem_instance.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc index fbd555f..6c2367f 100644 --- a/src/filesystem/filesystem_instance.cc +++ b/src/filesystem/filesystem_instance.cc @@ -657,7 +657,13 @@ void FilesystemInstance::ReadDir(const picojson::value& args, picojson::object& obj["callbackId"] = picojson::value(callback_id); for (auto path : paths) { FilesystemStat stat = FilesystemStat::getStat(path); - statPaths.push_back(stat.toJSON()); + + if (FilesystemError::None == stat.error) { + statPaths.push_back(stat.toJSON()); + } else { + LoggerW("File stat for path: %s failed with error: %d. Ignoring this entry.", path.c_str(), + static_cast::type>(stat.error)); + } } ReportSuccess(result, obj); Instance::PostMessage(this, response.serialize().c_str()); -- 2.7.4 From ab3c6bd5581e3237df25f1ab9ce9bf07c403f353 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Piotr=20Kosko/Native/Web=20API=20=28PLT=29=20/SRPOL/Profess?= =?utf8?q?ional/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 9 Apr 2019 12:08:45 +0200 Subject: [PATCH 16/16] [version] 2.32 Change-Id: Idb24a1afa087aa101cebcfde7d46d283d459c956 --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index b8c6c03..fed967b 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.31 +Version: 2.32 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4