--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/agent/notification-daemon/Service.cpp
+ * @author Zofia Abramowska <z.abramowska@samsung.com>
+ * @brief Declaration of Popupper class
+ */
+
+#include "Logic.h"
+
+#include <algorithm>
+#include <signal.h>
+#include <string>
+#include <sys/signalfd.h>
+#include <vconf.h>
+#include <Elementary.h>
+
+#include <exception/Exception.h>
+#include <exception/ErrnoException.h>
+#include "ServerCallbacks.h"
+
+namespace AskUser {
+
+namespace Notification {
+
+void Logic::addChannelFd(int fd, Ecore_Fd_Handler_Flags flags) {
+ auto it = m_fdInfo.find(fd);
+ if (it != m_fdInfo.end()) {
+ m_fdInfo[fd].status = FdChange::CHANGE;
+ ecore_main_fd_handler_del(m_fdInfo[fd].handler);
+ }
+
+ auto handler = ecore_main_fd_handler_add(fd, flags, &Logic::clientChHandler, this, nullptr, nullptr);
+ if (handler == nullptr) {
+ ALOGE("Couldn't set fd handler");
+ return;
+ }
+ m_fdInfo[fd].handler = handler;
+ m_fdInfo[fd].status = FdChange::NONE;
+}
+
+void Logic::removeChannelFd(int fd) {
+ auto it = m_fdInfo.find(fd);
+ if (it == m_fdInfo.end()) {
+ return;
+ }
+ it->second.status = FdChange::DEL;
+ ecore_main_fd_handler_del(it->second.handler);
+}
+
+Eina_Bool Logic::clientChHandler(void *data, Ecore_Fd_Handler *handler) {
+ Logic *service = static_cast<Logic *>(data);
+ int fd = ecore_main_fd_handler_fd_get(handler);
+ if (fd == -1) {
+ ALOGE("Failed to fetch fd from handler");
+ return ECORE_CALLBACK_CANCEL;
+ }
+ int mask = 0;
+ if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
+ mask = AskUser::Protocol::READ;
+ } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_WRITE)) {
+ mask = AskUser::Protocol::WRITE;
+ }
+ return service->processChannel(fd, mask);
+}
+
+Eina_Bool Logic::processChannel(int fd, int mask) {
+ m_fdInfo[fd].status = FdChange::NONE;
+ updateChannel(fd, mask);
+
+ switch (m_fdInfo[fd].status) {
+ case FdChange::NONE:
+ return ECORE_CALLBACK_RENEW;
+ case FdChange::DEL: {
+ // Remove all pending events from this fd
+ auto queueIt = std::remove_if(m_pendingEvents.begin(), m_pendingEvents.end(), [fd](const FdEvent &fdEvent) {return fdEvent.fd == fd;});
+ m_pendingEvents.erase(queueIt, m_pendingEvents.end());
+
+ // Handle next event if removed active fd
+ if (fd == m_currentFd) {
+ finishCurrentEvent();
+ processEvents();
+ }
+ m_fdInfo.erase(fd);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ case FdChange::CHANGE:
+ return ECORE_CALLBACK_CANCEL;
+ default:
+ ALOGE("Unexpected fd change value : " << static_cast<int>(m_fdInfo[fd].status));
+ return ECORE_CALLBACK_CANCEL;
+ }
+}
+
+void Logic::addEvent(IUIEvent *event) {
+ FdEvent fdEvent{m_currentFd, std::unique_ptr<IUIEvent>(event)};
+ m_pendingEvents.emplace_back(std::move(fdEvent));
+ processEvents();
+}
+
+bool Logic::isEventProcessed() {
+ return m_currentEventId != -1;
+}
+
+void Logic::finishCurrentEvent() {
+ m_popupper.popupClose(m_currentEventId);
+ m_currentEventId = -1;
+ m_currentFd = -1;
+}
+
+void Logic::processEvents() {
+ // Active event processing
+ if (isEventProcessed())
+ return;
+
+ // No pending events
+ if (m_pendingEvents.empty())
+ return;
+
+ FdEvent fdEvent = std::move(m_pendingEvents.front());
+ m_currentFd = fdEvent.fd;
+ m_currentEventId = fdEvent.event->getId();
+ m_pendingEvents.pop_front();
+
+ fdEvent.event->process();
+}
+
+void Logic::registerSignalFd() {
+ // TODO use ecore event EXIT?
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTERM);
+
+ if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {
+ throw ErrnoException("Couldn't set signal mask");
+ }
+
+ int signalFd = signalfd(-1, &mask, 0);
+ if (signalFd < 0) {
+ throw ErrnoException("Couldn't create signalfd");
+ }
+ auto handler = ecore_main_fd_handler_add(signalFd, ECORE_FD_READ, &Logic::signalHandler, this, nullptr, nullptr);
+ if (handler == nullptr) {
+ throw Exception("Couldn't set fd handler");
+ }
+}
+
+void Logic::stop() {
+ if (isEventProcessed())
+ finishCurrentEvent();
+ m_popupper.stop();
+}
+
+Eina_Bool Logic::signalHandler(void *data, Ecore_Fd_Handler *) {
+ Logic *logic = static_cast<Logic*>(data);
+ logic->stop();
+ return ECORE_CALLBACK_CANCEL;
+}
+
+void Logic::prepareChannel() {
+ m_clientChannel = AskUser::Protocol::createChannel(
+ std::unique_ptr<AskUser::Protocol::IServerCallbacks>(new AskUser::Protocol::ServerCallbacks(this, &m_popupper)));
+}
+
+void Logic::updateChannel(int fd, int mask) {
+ // TODO errors?
+ m_clientChannel->process(fd, mask);
+}
+
+void Logic::init() {
+ init_agent_log();
+ m_popupper.setLocale();
+ m_popupper.initialize();
+ m_popupper.registerPopupResponseHandler([&](int popupId, NResponseType response) { popupResponse(popupId, response);});
+ m_popupper.registerToastFinishedHandler([&](int toastId) {toastFinished(toastId);});
+
+ registerSignalFd();
+
+ prepareChannel();
+}
+
+void Logic::run() {
+ // TODO ensure we won't throw inside ecore loop
+ m_popupper.start();
+ m_popupper.shutdown();
+}
+
+void Logic::popupResponse(int popupId, NResponseType response) {
+ if (popupId != m_currentEventId) {
+ ALOGD("Got different popup id than is being processed");
+ return;
+ }
+ int clientResponse;
+ // TODO translate ui response to policy result
+ switch (response) {
+ case NResponseType::Deny:
+ clientResponse = 0;
+ break;
+ case NResponseType::DenyAlways:
+ clientResponse = 1;
+ break;
+ case NResponseType::Allow:
+ clientResponse = 2;
+ break;
+ case NResponseType::AllowAlways:
+ clientResponse = 3;
+ break;
+ case NResponseType::None:
+ clientResponse = 0;
+ break;
+ case NResponseType::Error:
+ clientResponse = -255;
+ break;
+ default:
+ clientResponse = -255; // error
+ }
+ m_clientChannel->popupResponse(popupId, clientResponse);
+ finishCurrentEvent();
+ processEvents();
+}
+
+void Logic::toastFinished(int toastId) {
+ if (toastId != m_currentEventId) {
+ ALOGD("Got different toast id than is being processed");
+ return;
+ }
+ finishCurrentEvent();
+ processEvents();
+}
+
+} // namespace Notification
+
+} // namepsace AskUser
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/agent/notification-daemon/Service.h
+ * @author Zofia Abramowska <z.abramowska@samsung.com>
+ * @brief Declaration of Popupper class
+ */
+
+#pragma once
+
+#include <map>
+#include <deque>
+#include <askuser-notification/ask-user-service.h>
+#include <event/Event.h>
+
+namespace AskUser {
+
+namespace Notification {
+
+class Logic {
+public:
+ class Exception : public std::exception {
+ public:
+ Exception(std::string &&s) : m_msg(std::move(s)) {}
+ const char *what() const throw () {
+ return m_msg.c_str();
+ }
+ private:
+ std::string m_msg;
+ };
+ Logic() : m_currentFd(-1), m_currentEventId(-1), m_isFdDeleted(false) {}
+ void init();
+ void run();
+ void stop();
+
+ void addChannelFd(int fd, Ecore_Fd_Handler_Flags flags);
+ void removeChannelFd(int fd);
+
+ void addEvent(IUIEvent *event);
+
+ ~Logic() {}
+private:
+ //Initialization
+ void registerSignalFd();
+ void prepareChannel();
+ void updateChannel(int fd, int mask);
+
+ // Descriptor handlers
+ static Eina_Bool clientChHandler(void *data, Ecore_Fd_Handler *handler);
+ static Eina_Bool signalHandler(void *data, Ecore_Fd_Handler *handler);
+ //static Eina_Bool signalHandler(void *data, int type, void *event);
+
+ Eina_Bool processChannel(int fd, int mask);
+ void processEvents();
+ bool isEventProcessed();
+ void finishCurrentEvent();
+ void popupResponse(int popupId, NResponseType response);
+ void toastFinished(int toastId);
+
+ AskUser::Protocol::ChannelPtr m_clientChannel;
+ Popupper m_popupper;
+
+ struct FdEvent {
+ int fd;
+ std::unique_ptr<IUIEvent> event;
+ };
+
+ // Workaround for no information about to which fd event belongs to
+ int m_currentFd;
+ int m_currentEventId;
+ int m_isFdDeleted;
+ std::deque<FdEvent> m_pendingEvents;
+
+ enum class FdChange {
+ NONE,
+ ADD,
+ CHANGE,
+ DEL
+ };
+ struct FdInfo {
+ Ecore_Fd_Handler* handler;
+ FdChange status;
+ };
+
+ std::map<int, FdInfo> m_fdInfo;
+};
+
+} // namespace Notification
+
+} // namespace AskUser