*/
#include "view_logic_web_notification_support.h"
+#include "view_logic_web_notification_data.h"
+
+#include <stdint.h>
#include <string>
-#include <dpl/log/log.h>
-#include <dpl/string.h>
-#include <wrt-commons/security-origin-dao/security_origin_dao_types.h>
-#include <wrt-commons/security-origin-dao/security_origin_dao.h>
-#include <common/view_logic_security_origin_support.h>
+#include <map>
+#include <unistd.h>
+#include <dpl/log/secure_log.h>
+#include <dpl/assert.h>
+#include <dpl/exception.h>
+#include <dpl/wrt-dao-ro/widget_config.h>
#include <notification.h>
#include <pcrecpp.h>
#include <sstream>
#include <curl/curl.h>
-#include <widget_model.h>
-#include <EWebKit2.h>
-#include <widget_string.h>
+namespace ViewModule {
namespace {
const char* PATTERN_CHECK_EXTERNAL = "^http(s)?://\\w+.*$";
-}
-
-namespace ViewModule {
-namespace WebNotification {
-using namespace SecurityOriginDB;
-using namespace ViewModule::SecurityOriginSupportUtil;
-
-bool notificationShow(WebNotificationDataPtr notiData);
-bool notificationHide(WebNotificationDataPtr notiData);
-bool isExternalUri(const std::string &pattern, const std::string &uri);
-bool downloadImage(WebNotificationDataPtr notiData);
-size_t curlWriteData(void *ptr, size_t size, size_t nmemb, FILE *stream);
-void askUserForWebNotificationPermission(
- Evas_Object* window,
- PermissionData* data);
-static void popupCallback(void* data, Evas_Object* obj, void* eventInfo);
-
-WebNotificationData::WebNotificationData(WidgetModel* widgetModel,
- uint64_t id) :
- m_widgetModel(widgetModel),
- m_id(id)
-{
- Assert(m_widgetModel);
-}
-WebNotificationData::~WebNotificationData()
-{}
+// Function declare
+bool isExternalUri(const std::string &uri);
+size_t curlWriteData(void* ptr, size_t size, size_t nmemb, FILE* stream);
-void webNotificationPermissionRequest(
- Evas_Object* window,
- SecurityOriginDAO* securityOriginDAO,
- void* data)
+bool isExternalUri(const std::string &uri)
{
- LogDebug("permissionRequest called");
- Assert(securityOriginDAO);
- Assert(data);
- Ewk_Notification_Permission_Request* request =
- static_cast<Ewk_Notification_Permission_Request*>(data);
- const Ewk_Security_Origin* ewkOrigin =
- ewk_notification_permission_request_origin_get(request);
- Assert(ewkOrigin);
-
- SecurityOriginData securityOriginData(
- WrtDB::FEATURE_WEB_NOTIFICATION,
- Origin(
- DPL::FromUTF8String(ewk_security_origin_protocol_get(ewkOrigin)),
- DPL::FromUTF8String(ewk_security_origin_host_get(ewkOrigin)),
- ewk_security_origin_port_get(ewkOrigin)));
-
- // check cache database
- Result result = securityOriginDAO->getResult(securityOriginData);
- if (RESULT_ALLOW_ONCE == result || RESULT_ALLOW_ALWAYS == result) {
- LogDebug("allow");
- ewk_notification_permission_request_set(request, EINA_TRUE);
- return;
- } else if (RESULT_DENY_ONCE == result || RESULT_DENY_ALWAYS == result) {
- LogDebug("deny");
- ewk_notification_permission_request_set(request, EINA_FALSE);
- return;
- }
-
- // ask to user
- PermissionData* permissionData =
- new PermissionData(securityOriginDAO,
- securityOriginData,
- request);
+ pcrecpp::RE_Options pcreOpt;
+ pcreOpt.set_caseless(true);
+ pcrecpp::RE re(PATTERN_CHECK_EXTERNAL, pcreOpt);
- // suspend notification
- ewk_notification_permission_request_suspend(request);
- askUserForWebNotificationPermission(window, permissionData);
- return;
+ return re.FullMatch(uri);
}
-bool showWebNotification(WebNotificationDataPtr notiData)
+size_t curlWriteData(void* ptr, size_t size, size_t nmemb, FILE* stream)
{
- LogDebug("showWebNotification called");
-
- /* TODO : register notification to database */
- return notificationShow(notiData);
+ size_t written = fwrite(ptr, size, nmemb, stream);
+ return written;
}
+} // anonymous namespace
-bool notificationShow(WebNotificationDataPtr notiData)
+// Implementation class
+class WebNotificationSupportImplementation
{
- LogDebug("notificationShow called");
- Assert(notiData);
- notification_h noti_h = NULL;
- notification_error_e error = NOTIFICATION_ERROR_NONE;
-
- Try {
- // create notification
- noti_h = notification_new(
- NOTIFICATION_TYPE_NOTI,
- NOTIFICATION_GROUP_ID_NONE,
- notiData->m_id);
- if (!noti_h) {
- LogError("Fail to notification_new");
- return false;
+ private:
+ class Exception
+ {
+ public:
+ DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
+ DECLARE_EXCEPTION_TYPE(Base, InitError)
+ DECLARE_EXCEPTION_TYPE(Base, NotificationShowError)
+ DECLARE_EXCEPTION_TYPE(Base, DownloadImageError)
+ };
+
+ bool m_initialized;
+ std::string m_persistentPath;
+
+ typedef std::map<uint64_t, WebNotificationDataPtr> NotiMap;
+ typedef std::map<uint64_t, WebNotificationDataPtr>::iterator NotiMapIt;
+ NotiMap m_notiDataMap;
+
+ std::string createDownloadPath(const std::string& iconUrl)
+ {
+ // Make valid filename
+ // If there is already exist filename, rename to "filename_%d"
+
+ std::string downloadPath = m_persistentPath;
+ std::string fileName = iconUrl.substr(iconUrl.rfind('/') + 1);
+ _D("fileName from URL: %s", fileName.c_str());
+ std::string rename = fileName;
+ unsigned int renameSuffixNb = 0;
+ while (0 == access((m_persistentPath + rename).c_str(), F_OK)) {
+ std::ostringstream suffixOstr;
+ suffixOstr.str("");
+ suffixOstr << fileName << "_" << renameSuffixNb++;
+
+ rename = fileName;
+ rename.insert(rename.find('.'), suffixOstr.str());
}
- // set notification title
- error = notification_set_text(
- noti_h,
- NOTIFICATION_TEXT_TYPE_TITLE,
- notiData->m_title.c_str(),
- NULL,
- NOTIFICATION_VARIABLE_TYPE_NONE);
- if (error != NOTIFICATION_ERROR_NONE) {
- ThrowMsg(Exception::NotificationShowError, "Fail to set title");
- }
+ downloadPath += rename;
+ _D("Valid file path : %s", downloadPath.c_str());
+ return downloadPath;
+ }
- // set notification content
- error = notification_set_text(
- noti_h,
- NOTIFICATION_TEXT_TYPE_CONTENT,
- notiData->m_body.c_str(),
- NULL,
- NOTIFICATION_VARIABLE_TYPE_NONE);
- if (error != NOTIFICATION_ERROR_NONE) {
- ThrowMsg(Exception::NotificationShowError,
- "Fail to set content:" << error);
+ std::string downloadImage(const std::string& iconUrl)
+ {
+ if (iconUrl.empty()) {
+ _W("Icon url is empty");
+ return std::string();
}
+ std::string downloadPath = createDownloadPath(iconUrl);
- //check uri is "http", https" or not
- bool validIconURL = true;
- LogDebug("url path is " << notiData->m_iconURL);
- if (isExternalUri(PATTERN_CHECK_EXTERNAL, notiData->m_iconURL)) {
- //download image from url
- validIconURL = downloadImage(notiData);
+ // Download image by curl
+ FILE *fp = NULL;
+ CURL *curl = NULL;
+
+ Try {
+ curl = curl_easy_init();
+ if (NULL == curl) {
+ _W("fail to curl_easy_init");
+ Throw(Exception::InitError);
+ }
+ fp = fopen(downloadPath.c_str(), "wb");
+ if (fp == NULL) {
+ _W("fail to open");
+ Throw(Exception::InitError);
+ }
+
+ curl_easy_setopt(curl, CURLOPT_URL, iconUrl.c_str());
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curlWriteData);
+
+ CURLcode err = curl_easy_perform(curl);
+ if (0 != err) {
+ _W("fail to curl_easy_perform: %d", err);
+ Throw(Exception::DownloadImageError);
+ }
+ fclose(fp);
+ curl_easy_cleanup(curl);
+ } Catch(DPL::Exception) {
+ fclose(fp);
+ curl_easy_cleanup(curl);
+ return std::string();
}
+ _D("Download success");
+ return downloadPath;
+ }
- //set image
- // If fail to download external image, skip to set image.
- // In this case, set to default package image.
- if (true == validIconURL) {
- error = notification_set_image(
+ int showNotification(WebNotificationDataPtr notiData)
+ {
+ Assert(notiData);
+ notification_h noti_h = NULL;
+ notification_error_e error = NOTIFICATION_ERROR_NONE;
+
+ Try {
+ // create notification
+ noti_h = notification_new(
+ NOTIFICATION_TYPE_NOTI,
+ NOTIFICATION_GROUP_ID_DEFAULT,
+ NOTIFICATION_PRIV_ID_NONE);
+ if (!noti_h) {
+ _E("Fail to notification_new");
+ Throw(Exception::NotificationShowError);
+ }
+
+ // set notification title
+ error = notification_set_text(
noti_h,
- NOTIFICATION_IMAGE_TYPE_ICON,
- notiData->m_iconURL.c_str());
+ NOTIFICATION_TEXT_TYPE_TITLE,
+ notiData->getTitle(),
+ NULL,
+ NOTIFICATION_VARIABLE_TYPE_NONE);
if (error != NOTIFICATION_ERROR_NONE) {
- ThrowMsg(Exception::NotificationShowError,
- "Fail to free notification: " << error);
+ _E("Fail to set title");
+ Throw(Exception::NotificationShowError);
}
- }
- // insert notification
- int priv_id = NOTIFICATION_PRIV_ID_NONE;
- error = notification_insert(noti_h, &priv_id);
- if (error != NOTIFICATION_ERROR_NONE) {
- ThrowMsg(Exception::NotificationShowError,
- "Fail to insert notification: " << error);
- }
+ // set notification content
+ error = notification_set_text(
+ noti_h,
+ NOTIFICATION_TEXT_TYPE_CONTENT,
+ notiData->getBody(),
+ NULL,
+ NOTIFICATION_VARIABLE_TYPE_NONE);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Fail to set content: %d", error);
+ Throw(Exception::NotificationShowError);
+ }
- LogDebug("Notification is inserted!");
- LogDebug("noti id =[" << notiData->m_id << "] " <<
- "priv_id =[" << priv_id << "]");
+ //check uri is "http", https" or not
+ if (notiData->getIconUrl()) {
+ std::string iconPath;
+ if (isExternalUri(notiData->getIconUrl())) {
+ //download image from url
+ iconPath = downloadImage(notiData->getIconUrl());
+ }
+
+ //set image
+ // If fail to download external image, skip to set image.
+ // In this case, set to default package image.
+ if (!iconPath.empty()) {
+ error = notification_set_image(
+ noti_h,
+ NOTIFICATION_IMAGE_TYPE_ICON,
+ iconPath.c_str());
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Fail to free notification: %d", error);
+ Throw(Exception::NotificationShowError);
+ }
+ }
+ }
- if (noti_h) {
- error = notification_free(noti_h);
+ // insert notification
+ int privId = NOTIFICATION_PRIV_ID_NONE;
+ error = notification_insert(noti_h, &privId);
if (error != NOTIFICATION_ERROR_NONE) {
- ThrowMsg(Exception::NotificationShowError,
- "Fail to free notification: " << error);
+ _E("Fail to insert notification : %d", error);
+ Throw(Exception::NotificationShowError);
}
+ _D("ewkId=[%u], notiId=[%d]", notiData->getEwkNotiId(), privId);
+
+ if (noti_h) {
+ error = notification_free(noti_h);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Fail to free notification : %d", error);
+ Throw(Exception::NotificationShowError);
+ }
+ noti_h = NULL;
+ }
+ notiData->setNotiId(privId);
+ } Catch(Exception::NotificationShowError) {
+ notification_free(noti_h);
noti_h = NULL;
+ return false;
+ } Catch(DPL::Exception) {
+ _E("Fail to show notification");
+ return false;
}
return true;
- } Catch(Exception::NotificationShowError) {
- LogError(_rethrown_exception.GetMessage());
- notification_free(noti_h);
- noti_h = NULL;
- return false;
- } Catch(DPL::Exception) {
- LogError(_rethrown_exception.GetMessage());
- return false;
}
-}
-bool notificationHide(WebNotificationDataPtr notiData)
-{
- LogDebug("notificationHide called");
+ bool hideNotification(uint64_t ewkNotiId)
+ {
+ notification_error_e error = NOTIFICATION_ERROR_NONE;
+ NotiMapIt it = m_notiDataMap.find(ewkNotiId);
+ error =
+ notification_delete_by_priv_id(NULL,
+ NOTIFICATION_TYPE_NOTI,
+ it->second->getNotiId());
+ if (error == NOTIFICATION_ERROR_NONE) {
+ _D("Success to hide");
+ return true;
+ } else if (error == NOTIFICATION_ERROR_NOT_EXIST_ID) {
+ _D("Success to hide. Not exist noti");
+ return true;
+ } else {
+ _W("Error to hide : %d", error);
+ return false;
+ }
+ }
- Assert(notiData);
- return true;
-}
+ // manage noti data
+ bool isExistData(uint64_t ewkNotiId)
+ {
+ if (m_notiDataMap.find(ewkNotiId) == m_notiDataMap.end()) {
+ return false;
+ }
+ return true;
+ }
-bool isExternalUri(const std::string &pattern, const std::string &uri)
-{
- LogDebug("isExternalUri called");
+ void insertData(WebNotificationDataPtr notiData)
+ {
+ m_notiDataMap[notiData->getEwkNotiId()] = notiData;
+ }
- pcrecpp::RE_Options pcreOpt;
- pcreOpt.set_caseless(true);
- pcrecpp::RE re(pattern, pcreOpt);
+ void removeData(uint64_t ewkNotiId)
+ {
+ m_notiDataMap.erase(ewkNotiId);
+ }
- return re.FullMatch(uri);
-}
+ WebNotificationDataPtr getData(uint64_t ewkNotiId)
+ {
+ return m_notiDataMap.find(ewkNotiId)->second;
+ }
-bool downloadImage(WebNotificationDataPtr notiData)
-{
- LogDebug("downloadImage called");
-
- Assert(notiData);
- // download path is
- // /opt/apps/tizen_id/data + '/' + filename
- std::string downloadPath =
- DPL::ToUTF8String(
- notiData->m_widgetModel->PersistentStoragePath.Get()) + "/";
- LogDebug("downloadPath " << downloadPath);
-
- // Make valid filename
- // If there is already exist filename, rename to "filename_%d"
- std::string fileName =
- notiData->m_iconURL.substr(notiData->m_iconURL.rfind('/') + 1);
- LogDebug("fileName from URL: " << fileName);
- std::string rename = fileName;
- unsigned int renameSuffixNb = 0;
- while (0 == access((downloadPath + rename).c_str(), F_OK)) {
- std::ostringstream suffixOstr;
- suffixOstr.str("");
- suffixOstr << fileName << "_" << renameSuffixNb++;
-
- rename = fileName;
- rename.insert(rename.find('.'), suffixOstr.str());
+ public:
+ WebNotificationSupportImplementation() :
+ m_initialized(false)
+ {
}
- downloadPath += rename;
- LogDebug("Valid file path : " << downloadPath);
+ void initialize(WrtDB::TizenPkgId pkgId)
+ {
+ // icon download path
+ // /opt/apps/tizen_id/data + '/' + filename
+ m_persistentPath =
+ WrtDB::WidgetConfig::GetWidgetPersistentStoragePath(pkgId) + '/';
+ _D("path %s", m_persistentPath.c_str());
+ m_initialized = true;
+ }
- // Download image by curl
- FILE *fp = NULL;
- CURL *curl = NULL;
+ void deinitialize(void)
+ {
+ _D("called");
+ m_initialized = false;
+ }
- Try {
- curl = curl_easy_init();
- if (NULL == curl) {
- ThrowMsg(Exception::InitError, "fail to curl_easy_init");
+ bool show(WebNotificationDataPtr notiData)
+ {
+ Assert(m_initialized);
+ if (isExistData(notiData->getEwkNotiId())) {
+ // Web Notifications (http://www.w3.org/TR/notifications/)
+ // 4.7 Replacing a notification
+ // 3. If old is in the list of pending notifications, queue a
+ // task to replace old with new, in the same position, in the
+ // list of pending notifications, and fire an event named
+ // close on old.
+ // 4. Otherwise, queue a task to replace old with new, in the
+ // same position, in the list of active notifications, fire
+ // an event named close on old, and fire an event named show
+ // on new.
+ hideNotification(notiData->getEwkNotiId());
+ removeData(notiData->getEwkNotiId());
}
-
- fp = fopen(downloadPath.c_str(), "wb");
- if (fp == NULL) {
- ThrowMsg(Exception::InitError, "fail to open");
+ if (showNotification(notiData)) {
+ insertData(notiData);
+ return true;
}
+ return false;
+ }
- curl_easy_setopt(curl, CURLOPT_URL, notiData->m_iconURL.c_str());
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curlWriteData);
-
- CURLcode err = curl_easy_perform(curl);
- if (0 != err) {
- ThrowMsg(Exception::DownloadImageError,
- "fail to curl_easy_perform: " << err);
+ void* hide(uint64_t ewkNotiId)
+ {
+ Assert(m_initialized);
+ if (!isExistData(ewkNotiId)) {
+ _W("Noti isn't exist");
+ return NULL;
}
- fclose(fp);
- curl_easy_cleanup(curl);
- } Catch(DPL::Exception) {
- LogError(_rethrown_exception.GetMessage());
- fclose(fp);
- curl_easy_cleanup(curl);
- return false;
+ if (!hideNotification(ewkNotiId)) {
+ return NULL;
+ }
+ WebNotificationDataPtr data = getData(ewkNotiId);
+ removeData(ewkNotiId);
+ return static_cast<void*>(data->getData());
}
+};
- LogDebug("Download success.. downloadedImgPath: " << downloadPath);
- notiData->m_iconURL = downloadPath;
- return true;
+WebNotificationSupport::WebNotificationSupport() :
+ m_impl(new WebNotificationSupportImplementation())
+{
}
-size_t curlWriteData(void *ptr, size_t size, size_t nmemb, FILE *stream)
+WebNotificationSupport::~WebNotificationSupport()
{
- size_t written = fwrite(ptr, size, nmemb, stream);
- return written;
}
-void askUserForWebNotificationPermission(
- Evas_Object* window,
- PermissionData* data)
+void WebNotificationSupport::initialize(WrtDB::TizenAppId appId)
{
- LogDebug("askUserForWebNotificationPermission called");
- std::string origin = DPL::ToUTF8String(data->m_originData.origin.host);
- if (origin.empty()) {
- origin = "local";
- }
- std::string appname;
- char* name = NULL;
- if (app_get_name(&name) == APP_ERROR_NONE) {
- appname = name;
- free(name);
- } else {
- appname = "application";
- }
+ m_impl->initialize(appId);
+}
- std::string body =
- WrtText::replacePS({WRT_POP_WEB_NOTIFICATION_PERMISSION,
- appname,
- origin});
- Evas_Object* popup = createPopup(window,
- body.c_str(),
- WRT_BODY_REMEMBER_PREFERENCE,
- popupCallback,
- data);
- if (popup == NULL) {
- LogError("Fail to create popup object");
- delete data;
- return;
- } else {
- evas_object_show(popup);
- }
+void WebNotificationSupport::deinitialize(void)
+{
+ m_impl->deinitialize();
}
-void popupCallback(void* data, Evas_Object* obj, void* /*eventInfo*/)
+bool WebNotificationSupport::show(WebNotificationDataPtr notiData)
{
- LogDebug("popupCallback");
- Assert(data);
- PermissionData* permData = static_cast<PermissionData*>(data);
- Ewk_Notification_Permission_Request* request =
- static_cast<Ewk_Notification_Permission_Request*>(permData->m_data);
-
- Evas_Object* popup = getPopup(obj);
- Result result = getResult(obj);
-
- if (result != RESULT_UNKNOWN) {
- permData->m_originDao->setSecurityOriginData(permData->m_originData,
- result);
- }
- Eina_Bool ret =
- (result == RESULT_ALLOW_ALWAYS || result == RESULT_ALLOW_ONCE) ?
- EINA_TRUE : EINA_FALSE;
- ewk_notification_permission_request_set(request, ret);
- delete permData;
- evas_object_hide(popup);
- evas_object_del(popup);
+ return m_impl->show(notiData);
+}
+
+void* WebNotificationSupport::hide(uint64_t ewkNotiId)
+{
+ return m_impl->hide(ewkNotiId);
}
-} // namespace WebNotification
} //namespace ViewModule