From 8a238ff2cf08fb5bc2c7813eae61d91da4fa1d4b Mon Sep 17 00:00:00 2001 From: Piotr Sawicki Date: Thu, 22 Jun 2017 13:53:56 +0200 Subject: [PATCH] Add a skeleton of client API implementation Change-Id: I067a35ae6b712c7f67076e30a29efdbf0ced6d79 --- CMakeLists.txt | 7 +- packaging/askuser-notification.spec | 32 ++ pkgconfig/CMakeLists.txt | 20 + .../askuser-notification-client/CMakeLists.txt | 26 ++ .../askuser-notification-client.pc.in | 14 + src/client/CMakeLists.txt | 68 +++ src/client/api/ApiInterface.h | 51 ++ src/client/api/askuser-notification-client.cpp | 127 +++++ src/client/impl/ApiInterfaceImpl.cpp | 68 +++ src/client/impl/ApiInterfaceImpl.h | 56 +++ src/client/impl/PopupCallbackClosure.h | 52 +++ src/client/impl/StatusCallbackClosure.h | 52 +++ src/client/include/askuser-notification-client.h | 519 +++++++++++++++++++++ 13 files changed, 1091 insertions(+), 1 deletion(-) create mode 100644 pkgconfig/CMakeLists.txt create mode 100644 pkgconfig/askuser-notification-client/CMakeLists.txt create mode 100644 pkgconfig/askuser-notification-client/askuser-notification-client.pc.in create mode 100644 src/client/CMakeLists.txt create mode 100644 src/client/api/ApiInterface.h create mode 100644 src/client/api/askuser-notification-client.cpp create mode 100644 src/client/impl/ApiInterfaceImpl.cpp create mode 100644 src/client/impl/ApiInterfaceImpl.h create mode 100644 src/client/impl/PopupCallbackClosure.h create mode 100644 src/client/impl/StatusCallbackClosure.h create mode 100644 src/client/include/askuser-notification-client.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 76ba1e0..d70618b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3) PROJECT("askuser") -SET(ASKUSER_VERSION 0.1.0) +SET(ASKUSER_VERSION_MAJOR 0) +SET(ASKUSER_VERSION ${ASKUSER_VERSION_MAJOR}.1.13) ############################# cmake packages ################################## @@ -82,11 +83,15 @@ SET(TARGET_ASKUSER_NOTIFICATION "askuser-notification") SET(TARGET_ASKUSER_COMMON "askuser-notification-common") SET(TARGET_ASKUSER_NOTIFICATION_LIB "askuser-notification-ipc") SET(TARGET_ASKUSER_NOTIFICATION_TEST "askuser-notification-test") +SET(TARGET_ASKUSER_NOTIFICATION_CLIENT_LIB "askuser-notification-client") SET(TARGET_PLUGIN_SERVICE "askuser-plugin-service") ADD_SUBDIRECTORY(src/plugin) ADD_SUBDIRECTORY(src/notification-daemon) ADD_SUBDIRECTORY(src/common) ADD_SUBDIRECTORY(src/common/protocol) +ADD_SUBDIRECTORY(src/client) + +ADD_SUBDIRECTORY(pkgconfig) IF (BUILD_WITH_SYSTEMD_DAEMON) ADD_SUBDIRECTORY(systemd) diff --git a/packaging/askuser-notification.spec b/packaging/askuser-notification.spec index e7dd07e..9365a20 100644 --- a/packaging/askuser-notification.spec +++ b/packaging/askuser-notification.spec @@ -67,6 +67,24 @@ Summary: Tool for testing askuser-notification %description test Tool for testing askuser-notification +%package client +Summary: Askuser notification client library +Requires: askuser-notification-libs +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description client +Askuser notification client library allows to check if an application +has a particular privilege. It also allows an application to determine privacy +privileges. It communicates with the askuser-notification service. It is an +asynchronous API, therefore it can be integrated with any event loop mechanism. + +%package client-devel +Summary: Askuser notification client library development files + +%description client-devel +Askuser notification client library development files + %prep %setup -q cp -a %{SOURCE1001} . @@ -123,6 +141,10 @@ systemctl restart cynara.service %postun libs -p /sbin/ldconfig +%post client -p /sbin/ldconfig + +%postun client -p /sbin/ldconfig + %files -f %{name}.lang %manifest default.manifest %license LICENSE @@ -156,3 +178,13 @@ systemctl restart cynara.service %files test %attr(755,root,root) %{_bindir}/askuser-notification-test + +%files client +%manifest default.manifest +%license LICENSE +%attr(644,-,-) %{_libdir}/libaskuser-notification-client.so.* + +%files client-devel +%{_includedir}/askuser-notification-client/*.h +%{_libdir}/pkgconfig/askuser-notification-client.pc +%{_libdir}/libaskuser-notification-client.so diff --git a/pkgconfig/CMakeLists.txt b/pkgconfig/CMakeLists.txt new file mode 100644 index 0000000..896e409 --- /dev/null +++ b/pkgconfig/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved +# +# 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 CMakeLists.txt +# @author Piotr Sawicki +# + +ADD_SUBDIRECTORY(askuser-notification-client) + diff --git a/pkgconfig/askuser-notification-client/CMakeLists.txt b/pkgconfig/askuser-notification-client/CMakeLists.txt new file mode 100644 index 0000000..491f95d --- /dev/null +++ b/pkgconfig/askuser-notification-client/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved +# +# 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 CMakeLists.txt +# @author Piotr Sawicki +# + +CONFIGURE_FILE(askuser-notification-client.pc.in askuser-notification-client.pc @ONLY) + +INSTALL(FILES + ${CMAKE_BINARY_DIR}/pkgconfig/askuser-notification-client/askuser-notification-client.pc + DESTINATION + ${LIB_INSTALL_DIR}/pkgconfig + ) + diff --git a/pkgconfig/askuser-notification-client/askuser-notification-client.pc.in b/pkgconfig/askuser-notification-client/askuser-notification-client.pc.in new file mode 100644 index 0000000..46bd583 --- /dev/null +++ b/pkgconfig/askuser-notification-client/askuser-notification-client.pc.in @@ -0,0 +1,14 @@ +# Package Information for pkg-config + +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@LIB_INSTALL_DIR@ +includedir=@INCLUDE_INSTALL_DIR@ + +Name: askuser-notification-client +Description: askuser-notification-client library +Version: @ASKUSER_VERSION@ +Requires: +Libs: -L${libdir} -laskuser-notification-client +Cflags: -I${includedir}/askuser-notification-client + diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt new file mode 100644 index 0000000..09c9049 --- /dev/null +++ b/src/client/CMakeLists.txt @@ -0,0 +1,68 @@ + +# Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved +# +# 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 CMakeLists.txt +# @author Piotr Sawicki +# + +SET(ASKUSER_NOTIFICATION_CLIENT_PATH ${ASKUSER_PATH}/client) + +PKG_CHECK_MODULES(ASKUSER_NOTIFICATION_CLIENT_DEP + REQUIRED + ) + +INCLUDE_DIRECTORIES(SYSTEM ${ASKUSER_NOTIFICATION_CLIENT_DEP_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES( + ${ASKUSER_NOTIFICATION_CLIENT_PATH}/api + ${ASKUSER_NOTIFICATION_CLIENT_PATH}/impl + ${ASKUSER_NOTIFICATION_CLIENT_PATH}/include + ) + +SET(ASKUSER_NOTIFICATION_CLIENT_SOURCES + ${ASKUSER_NOTIFICATION_CLIENT_PATH}/api/askuser-notification-client.cpp + ${ASKUSER_NOTIFICATION_CLIENT_PATH}/impl/ApiInterfaceImpl.cpp + ) + +ADD_DEFINITIONS("-fvisibility=default") + +ADD_LIBRARY( + ${TARGET_ASKUSER_NOTIFICATION_CLIENT_LIB} + SHARED + ${ASKUSER_NOTIFICATION_CLIENT_SOURCES} +) + +SET_TARGET_PROPERTIES(${TARGET_ASKUSER_NOTIFICATION_CLIENT_LIB} + PROPERTIES + SOVERSION ${ASKUSER_VERSION_MAJOR} + VERSION ${ASKUSER_VERSION} + OUTPUT_NAME "askuser-notification-client" + ) + +LINK_DIRECTORIES(${ASKUSER_NOTIFICATION_CLIENT_DEP_LIBRARY_DIRS}) + +TARGET_LINK_LIBRARIES( + ${TARGET_ASKUSER_NOTIFICATION_CLIENT_LIB} + ${TARGET_ASKUSER_NOTIFICATION_LIB} + ${TARGET_ASKUSER_COMMON} + ${ASKUSER_NOTIFICATION_CLIENT_DEP_LIBRARIES} +) + +INSTALL(TARGETS ${TARGET_ASKUSER_NOTIFICATION_CLIENT_LIB} + DESTINATION ${LIB_INSTALL_DIR}) + +FILE(GLOB HEADERS ${ASKUSER_NOTIFICATION_CLIENT_PATH}/include/*.h) +INSTALL(FILES ${HEADERS} + DESTINATION ${INCLUDE_INSTALL_DIR}/askuser-notification-client) + diff --git a/src/client/api/ApiInterface.h b/src/client/api/ApiInterface.h new file mode 100644 index 0000000..8c3ab54 --- /dev/null +++ b/src/client/api/ApiInterface.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 ApiInterface.h + * @author Piotr Sawicki + * @version 1.0 + * @brief This file contains the declaration of ApiInterface. + */ + +#pragma once + +#include + +#include +#include + +namespace AskUser { + +namespace Client { + +using RequestId = int; + +class ApiInterface +{ +public: + virtual ~ApiInterface() {} + + virtual int process(int fd, int events) = 0; + virtual askuser_check_result checkPrivilege(const std::string &privilege) = 0; + virtual RequestId popupRequest(const PopupCallbackClosure &closure, + const std::string &privilege) = 0; +}; + +} // namespace Client + +} // namespace AskUser + diff --git a/src/client/api/askuser-notification-client.cpp b/src/client/api/askuser-notification-client.cpp new file mode 100644 index 0000000..803088b --- /dev/null +++ b/src/client/api/askuser-notification-client.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 askuser-notification-client.cpp + * @author Piotr Sawicki + * @version 1.0 + * @brief This file contains the implementation of the askuser-notification client API. + */ + +#include + +#include +#include +#include +#include + +#include + +struct askuser_client { + AskUser::Client::ApiInterface *impl; + + askuser_client(AskUser::Client::ApiInterface *_impl) : impl(_impl) { + } + + ~askuser_client() { + delete impl; + } +}; + +int askuser_client_initialize(askuser_client **pp_client, + askuser_status_callback status_callback, void *p_user_data) +{ + if (!pp_client) + return ASKUSER_API_INVALID_PARAM; + + try { + AskUser::Client::StatusCallbackClosure closure(status_callback, p_user_data); + + std::unique_ptr ptr; + ptr.reset(new AskUser::Client::ApiInterfaceImpl(closure)); + + *pp_client = new askuser_client(ptr.get()); + + ptr.release(); + } catch (...) { + // TODO handle exceptions + return ASKUSER_API_UNKNOWN_ERROR; + } + + return ASKUSER_API_SUCCESS; +} + +void askuser_client_finalize(askuser_client *p_client) +{ + if (!p_client) + return; + + try { + delete p_client; + } catch (...) { + // TODO + } +} + +int askuser_client_process(askuser_client *p_client, int fd, int events) +{ + if (!p_client) + return ASKUSER_API_INVALID_PARAM; + + try { + return p_client->impl->process(fd, events); + } catch (...) { + // TODO + return ASKUSER_API_UNKNOWN_ERROR; + } +} + +int askuser_client_check_privilege(askuser_client *p_client, + const char *privilege, askuser_check_result *p_result) +{ + if (!p_client || !privilege || !p_result) + return ASKUSER_API_INVALID_PARAM; + + try { + *p_result = p_client->impl->checkPrivilege(privilege); + } catch(...) { + // TODO handle exceptions + return ASKUSER_API_UNKNOWN_ERROR; + } + + return ASKUSER_API_SUCCESS; +} + +int askuser_client_popup_request(askuser_client *p_client, const char *privilege, + askuser_popup_response_callback response_callback, + void *p_user_data, int *p_request_id) +{ + if (!p_client || !response_callback || !privilege) + return ASKUSER_API_INVALID_PARAM; + + try { + AskUser::Client::PopupCallbackClosure closure(response_callback, p_user_data); + AskUser::Client::RequestId id = p_client->impl->popupRequest(closure, privilege); + + if (p_request_id != nullptr) { + *p_request_id = id; + } + } catch (...) { + // TODO handle exceptions + return ASKUSER_API_UNKNOWN_ERROR; + } + + return ASKUSER_API_SUCCESS; +} diff --git a/src/client/impl/ApiInterfaceImpl.cpp b/src/client/impl/ApiInterfaceImpl.cpp new file mode 100644 index 0000000..ce90206 --- /dev/null +++ b/src/client/impl/ApiInterfaceImpl.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 ApiInterfaceImpl.cpp + * @author Piotr Sawicki + * @version 1.0 + * @brief The definition of ApiInterfaceImpl. + */ + +#include "ApiInterfaceImpl.h" + +namespace AskUser { + +namespace Client { + +ApiInterfaceImpl::ApiInterfaceImpl(const StatusCallbackClosure &statusClosure) +: m_statusClosure(statusClosure) +{ +} + +ApiInterfaceImpl::~ApiInterfaceImpl() +{ + // TODO +} + +int ApiInterfaceImpl::process(int fd, int events) +{ + // TODO + (void) fd; + (void) events; + return 0; +} + +askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privilege) +{ + // TODO + (void) privilege; + + return ASKUSER_CHECK_RESULT_DENY; +} + +RequestId ApiInterfaceImpl::popupRequest(const PopupCallbackClosure &closure, + const std::string &privilege) +{ + // TODO + (void) closure; + (void) privilege; + + return 0; +} + +} // namespace Client + +} // namespace AskUser diff --git a/src/client/impl/ApiInterfaceImpl.h b/src/client/impl/ApiInterfaceImpl.h new file mode 100644 index 0000000..e255ac2 --- /dev/null +++ b/src/client/impl/ApiInterfaceImpl.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 ApiInterfaceImpl.h + * @author Piotr Sawicki + * @version 1.0 + * @brief The declaration of ApiInterfaceImpl. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace AskUser { + +namespace Client { + +class ApiInterfaceImpl : public AskUser::Client::ApiInterface { +public: + ApiInterfaceImpl(const AskUser::Client::StatusCallbackClosure &closure); + ApiInterfaceImpl(const ApiInterfaceImpl& orig) = delete; + virtual ~ApiInterfaceImpl(); + + ApiInterface &operator=(const ApiInterfaceImpl& orig) = delete; + + virtual int process(int fd, int events); + virtual askuser_check_result checkPrivilege(const std::string &privilege); + virtual RequestId popupRequest(const AskUser::Client::PopupCallbackClosure &closure, + const std::string &privilege); + +private: + AskUser::Client::StatusCallbackClosure m_statusClosure; +}; + +} // namespace Client + +} // namespace AskUser + diff --git a/src/client/impl/PopupCallbackClosure.h b/src/client/impl/PopupCallbackClosure.h new file mode 100644 index 0000000..ebdf0ee --- /dev/null +++ b/src/client/impl/PopupCallbackClosure.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PopupCallbackClosure.h + * @author Piotr Sawicki + * @version 1.0 + * @brief The definition of PopupCallbackClosure. + */ + +#pragma once + +#include + +namespace AskUser { + +namespace Client { + +class PopupCallbackClosure { +public: + PopupCallbackClosure(askuser_popup_response_callback callback, void *userData) + : m_callback(callback) + , m_userData(userData) + {} + + void operator()(int requestId, askuser_call_cause cause, askuser_popup_result result) const + { + m_callback(requestId, cause, result, m_userData); + } + +private: + askuser_popup_response_callback m_callback; + void *m_userData; +}; + +} // namespace Client + +} // namespace AskUser + diff --git a/src/client/impl/StatusCallbackClosure.h b/src/client/impl/StatusCallbackClosure.h new file mode 100644 index 0000000..8a51189 --- /dev/null +++ b/src/client/impl/StatusCallbackClosure.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 StatusCallbackClosure.h + * @author Piotr Sawicki + * @version 1.0 + * @brief The definition of StatusCallbackClosure. + */ + +#pragma once + +#include + +namespace AskUser { + +namespace Client { + +class StatusCallbackClosure { +public: + StatusCallbackClosure(askuser_status_callback callback, void *userData) + : m_callback(callback) + , m_userData(userData) + {} + + void operator()(int fd, int events) const + { + m_callback(fd, events, m_userData); + } + +private: + askuser_status_callback m_callback; + void *m_userData; +}; + +} // namespace Client + +} // namespace AskUser + diff --git a/src/client/include/askuser-notification-client.h b/src/client/include/askuser-notification-client.h new file mode 100644 index 0000000..c1b6df7 --- /dev/null +++ b/src/client/include/askuser-notification-client.h @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 askuser-notification-client.h + * @author Piotr Sawicki + * @version 1.0 + * @brief The declaration of the askuser-notification client API. + */ + +#ifndef ASKUSER_NOTIFICATION_CLIENT_H +#define ASKUSER_NOTIFICATION_CLIENT_H + +/** + * \name Status return codes + * @{ + */ + +/*! \brief indicating that the call was successful */ +#define ASKUSER_API_SUCCESS 0 + +/*! \brief indicating that an unknown error occurred */ +#define ASKUSER_API_UNKNOWN_ERROR -1 + +/*! \brief indicating that a memory allocation failed */ +#define ASKUSER_API_OUT_OF_MEMORY -2 + +/*! \brief indicating that an invalid parameter was passed */ +#define ASKUSER_API_INVALID_PARAM -3 + +/*! \brief indicating that a connection error occurred */ +#define ASKUSER_API_CONNECTION_ERROR -4 + +/** @} */ + +/** + * \name Types of file descriptor events + * + * @{ + */ + +/*! \brief a file descriptor is ready to read */ +#define ASKUSER_READ_EVENT (1 << 0) + +/*! \brief a file descriptor is ready to write */ +#define ASKUSER_WRITE_EVENT (1 << 1) + +/*! \brief an error has been detected on a file descriptor by an event loop or + * the API wants to inform that a file descriptor is to be closed + */ +#define ASKUSER_EMPTY_EVENTS 0 + +/** @} */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct askuser_client askuser_client; + +/** + * \enum askuser_check_result + * Values indicating the result of an askuser_client_check_privilege() call. + * + * \var askuser_check_result::ASKUSER_CHECK_RESULT_ALLOW + * An application has a privilege. + * + * \var askuser_check_result::ASKUSER_CHECK_RESULT_DENY + * An application does not have a privilege. + * + * \var askuser_check_result::ASKUSER_CHECK_RESULT_ASK + * A user should be asked about whether grant privilege to an application or not. + */ +typedef enum { + ASKUSER_CHECK_RESULT_ALLOW, + ASKUSER_CHECK_RESULT_DENY, + ASKUSER_CHECK_RESULT_ASK, +} askuser_check_result; + +/** + * \enum askuser_popup_result + * Values returned by popup. + * + * \var askuser_popup_result::ASKUSER_POPUP_RESULT_ALLOW_FOREVER + * A user granted a privilege to an application. + * + * \var askuser_popup_result::ASKUSER_POPUP_RESULT_DENY_FOREVER + * A user did not grant a privilege to an application. + * + * \var askuser_popup_result::ASKUSER_POPUP_RESULT_DENY_ONCE + * A user did not grant a privilege to an application for this + * particular query. + */ +typedef enum { + ASKUSER_POPUP_RESULT_ALLOW_FOREVER, + ASKUSER_POPUP_RESULT_DENY_FOREVER, + ASKUSER_POPUP_RESULT_DENY_ONCE, +} askuser_popup_result; + +/** + * \enum askuser_call_cause + * Values indicating the reason passed to askuser_popup_response_callback. + * + * \var askuser_call_cause::ASKUSER_CALL_CAUSE_ANSWER + * Callback was called with a valid answer. + * + * \var askuser_call_cause::ASKUSER_CALL_CAUSE_ERROR + * Callback was called because of an error. + * + * \var askuser_call_cause::ASKUSER_CALL_CAUSE_FINALIZE + * Callback was called because askuser_client_finalize() had been called. + */ +typedef enum { + ASKUSER_CALL_CAUSE_ANSWER, + ASKUSER_CALL_CAUSE_ERROR, + ASKUSER_CALL_CAUSE_FINALIZE, +} askuser_call_cause; + + +/** + * \brief This callback function is called when the status of a file descriptor changes. + * + * A file descriptor changes when a client: + * - is ready to send a request (after calling: askuser_client_popup_request()) + * - is ready to receive a response + * + * This function is crucial to implement an asynchronous API. An application should + * register its askuser_status_callback function to monitor file descriptors. + * In the body of this callback function, the application should configure its + * I/O multiplexing mechanism (select, poll, GLib main loop etc.) to wait for specified + * events (events parameter) which may occur on a file descriptor (fd parameter). + * + * \attention This callback is called from the askuser_client_process() function context. + * + * \attention The events and fd parameters passed in this callback should be + * stored on the application side. Application should use this stored information + * in every event loop cycle to configure its I/O multiplexing mechanism. + * It is due to the fact that the callback may not be called in every loop cycle for every + * askuser_client_process() call. For example, if the API wants to send some data, + * it calls the callback with the 'events' param having the ASKUSER_WRITE_EVENT flag set. + * Then, askuser_client_process() may be called multiple times until the data is sent. + * When this task is done, the callback is called with cleared ASKUSER_WRITE_EVENT, + * which means that the application should stop waiting for the WRITE event. + * + * Have a look at the below simplified code (managing of fd is ommited for better + * readability). + * + * \code + * int app_events_to_wait_for; + * + * void callback(int fd, int events, void *p_user_data) + * { + * app_events_to_wait_for = events; + * } + * + * void event_loop() + * { + * for (;;) { + * detected_events = wait_for_events(app_events_to_wait_for); + * askuser_client_process(client, fd, detected_events); + * } + * } + * \endcode + * + * \param[in] fd A file descriptor. + * \param[in] events It is a bit-field value compounds of ASKUSER_READ_EVENT + * or ASKUSER_WRITE_EVENT or both. + * Special value ASKUSER_EMPTY_EVENTS indicates that the + * file descriptor (fd) should be removed from a file + * descriptor set of an event loop mechanism. + * \param[in] p_user_data User specific data passed to askuser_client_initialize(). + */ +typedef void (*askuser_status_callback) (int fd, int events, void *p_user_data); + +/** + * \brief This callback function is called when a client receives a response + * upon calling askuser_client_popup_request(). + * + * \attention This callback is called from the askuser_client_process() function context. + * + * \param[in] request_id A number identifying the request. It will be equal to + * the value of *p_request_id generated by a corresponding + * askuser_client_popup_request() function call. + * \param[in] cause A value representing the reason why this callback has + * been called. + * \param[in] result It is a result of response to request created by + * askuser_client_popup_request(). This should be + * interpreted as a valid value only if cause is equal to + * askuser_call_cause::ASKUSER_CALL_CAUSE_ANSWER. + * \param[in] p_user_data User specific data, this parameter was previously + * passed to askuser_client_popup_request(). + */ +typedef void (*askuser_popup_response_callback) (int request_id, + askuser_call_cause cause, + askuser_popup_result result, + void *p_user_data); + +/** + * \brief Description + * Initialize askuser-notification client. It allocates structure and + * initializes it using a given status callback and user data. + * + * \par Purpose: + * This API function must be called prior to any call of the other + * askuser-notification client functions. + * + * \par Typical use case: + * It should be called before entering an event loop and before calling any + * other askuser-notification client API function. + * + * \par Method of function operation: + * This API function initializes inner library structures and in case of success + * returns askuser_client structure. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. + * + * \par Important notes: + * Structure askuser_client created by a askuser_client_initialize() call + * should be released by calling askuser_client_finalize(). + * + * \param[out] pp_client A placeholder for a newly created askuser_client + * structure. The pp_client is valid only if this + * function returns ASKUSER_API_SUCCESS. + * \param[in] status_callback A callback function which will be called every + * time when some file descriptor belonging to the + * askuser_client structure changes its state. + * \param[in] p_user_data User specific data which will be passed to the + * status_callback function. + * Set NULL if you don't use user data. + * + * \return ASKUSER_API_SUCCESS on success + * \return a negative value in case of an error (see "Status return codes") + */ +int askuser_client_initialize(askuser_client **pp_client, + askuser_status_callback status_callback, + void *p_user_data); + +/** + * \brief Description + * Release instance of the askuser_client structure. It releases all resources + * associated with askuser_client structure. + * + * \par Purpose: + * This API function must be called to release all resources associated with + * askuser_client structure. + * + * \par Typical use case: + * This API function should be called when the askuser-notification client + * functionality is no more used by an application + * (e.g. when the application finishes). + * + * \par Method of function operation: + * This API function releases all internal resources and deallocates the + * askuser_client structure. When there are pending requests, registered + * askuser_response_callback functions will be called with an appropriate + * status code: askuser_call_cause::ASKUSER_CALL_CAUSE_FINALIZE. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. + * + * \par Important notes: + * After calling this function on a particular askuser_client structure, + * no subsequent calls of askuser_client_finalize() should be performed on + * the same structure. + * + * \param[out] p_client An instance of the askuser_client structure, + * previously created by askuser_client_initialize(). + */ +void askuser_client_finalize(askuser_client *p_client); + +/** + * \brief Description + * This function process R/W events that occurred on a file descriptor associated + * with a specific askuser_client structure. All statuses and errors which occur + * on the file descriptor will be passed to a callback function registered by + * invoking askuser_client_initialize(). + * + * \par Purpose: + * This API function is called to process read and write events which occurred + * on a file descriptor. In result of calling this function an appropriate + * callback is executed: askuser_status_callback or askuser_popup_response_callback. + * + * \par Typical use case: + * The event loop of an application waits for events which may occur on file descriptors + * previously registered by askuser_status_callback. When an event occurs then the event + * loop should call this function passing an askuser_client structure, a file + * descriptor on which the event occurred and events (a bit-field value compounds of + * ASKUSER_READ_EVENT and ASKUSER_WRITE_EVENT). + * + * \par Method of function operation: + * \parblock + * This function sends pending requests (ASKUSER_WRITE_EVENT), receives all responses + * from the askuser-notification service (ASKUSER_READ_EVENT). In result of these + * actions an appropriate callback is executed (askuser_popup_response_callback, + * or askuser_status_callback). + * \endparblock + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. + * + * \param[in] p_client An instance of the askuser_client structure, previously + * created by askuser_client_initialize(). + * \param[in] fd A file descriptor. + * \param[in] events It is a bit-field value compounds of ASKUSER_READ_EVENT + * and ASKUSER_WRITE_EVENT, which represents the detected + * events on that fd. The event loop mechanism should + * pass **ASKUSER_EMPTY_EVENTS** if it detects an error + * on the file descriptor. + * + * \return ASKUSER_API_SUCCESS on success + * \return a negative value in case of an error (see "Status return codes") + */ +int askuser_client_process(askuser_client *p_client, int fd, int events); + +/** + * \brief Description + * This function is called to check if an application has access to a particular + * privilege. + * + * \par Purpose: + * This API function should be called if an application wants to check if it has + * access to a given privilege. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. + * + * \param[in] p_client An instance of the askuser_client structure previously + * created by askuser_client_initialize(). + * \param[in] privilege Privilege that is to be checked. + * \param[out] p_result The result of a privilege check. + * + * \return ASKUSER_API_SUCCESS on success + * \return a negative value in case of an error (see "Status return codes") + */ +int askuser_client_check_privilege(askuser_client *p_client, const char *privilege, + askuser_check_result *p_result); + +/** + * \brief Description + * This function is called to determine a privacy privilege . + * + * \par Purpose: + * This API function should be called if an application wants to determine a privacy + * privilege. When this function is called, the askuser-notification service shows + * an appropriate UI dialog box (popup) with a question. After user's decision, the + * service modifies sends the response back to the application. + * The application is informed about user's decision by calling + * askuser_popup_response_callback. + * + * \par Method of function operation: + * If the result of calling askuser_client_check_privilege() is + * askuser_check_result::ASKUSER_CHECK_RESULT_ASK, the application should call + * this function to determine whether a user allows an application to use + * a particular privilege. + * + * \par Sync (or) Async: + * This is an asynchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. + * + * \param[in] p_client An instance of the askuser_client structure + * previously created by askuser_client_initialize(). + * \param[in] privilege A privilege for which a popup must be shown. + * \param[in] response_callback A callback function called when the API receives + * a response. + * \param[in] p_user_data User specific data which will be passed to + * the registered response_callback. + * Set to NULL if you don't use user data. + * \param[out] p_request_id An identifier of a request generated by the API. + * Set NULL if you don't use a request ID. + * + * \return ASKUSER_API_SUCCESS on success + * \return a negative value in case of an error (see "Status return codes") + */ +int askuser_client_popup_request(askuser_client *p_client, const char *privilege, + askuser_popup_response_callback response_callback, + void *p_user_data, int *p_request_id); + +/** + * Example + * + * NOTICE: Everything with app prefix is a part of a hypothetical + * application framework. + * + * \code + * void ask_status_callback(int fd, int events, void *p_user_data) + * { + * assert(p_user_data != NULL); + * app_context *app = (app_context *) p_user_data; + * // Note that events == 0 means that this fd should be + * // removed from a monitored file descriptor set. + * app_update_fds(app, fd, app_askuser_to_app_events(events)); + * } + * + * void ask_popup_response_callback(int request_id, askuser_call_cause cause, + * askuser_popup_result result, void *p_user_data) + * { + * assert(p_user_data != NULL); + * app_context *app = (app_context *) p_user_data; + * app_callback callback = app_get_callback(app, request_id); + * + * switch (cause) { + * case ASKUSER_CALL_CAUSE_ANSWER: + * callback(app, askuser_to_app_popup_result(result)); + * break; + * case ASKUSER_CALL_CAUSE_FINALIZE: + * callback(app, APP_IS_CLOSING); + * break; + * case ASKUSER_CALL_CAUSE_ERROR: + * // handle errors + * callback(app, APP_ASKUSER_ERROR_OCCURED); + * break; + * } + * + * app_unregister_callback(app, request_id); + * } + * + * void app_check_privilege(app_context *app, const char *privilege, app_callback callback); + * { + * int status; + * int request_id; + * askuser_check_result result; + * + * assert(app != NULL); + * askuser_client *client = app_get_askuser_client(app); + * + * status = askuser_client_check_privilege(client, &result); + * if (status != ASKUSER_API_SUCCESS) { + * // handle errors + * return; + * } + * + * switch (result) { + * case ASKUSER_CHECK_RESULT_ALLOW: + * // adjust GUI to reflect that the app has access to a + * // specific resource + * break; + * case ASKUSER_CHECK_RESULT_DENY: + * // adjust GUI to reflect that the app doesn't have access to a + * // specific resource + * break; + * case ASKUSER_CHECK_RESULT_ASK: + * status = askuser_client_popup_request(client, privilege, + * ask_popup_response_callback, app, &request_id); + * if (status != ASKUSER_API_SUCCESS) { + * //handle errors + * return; + * } + * app_register_callback(app, callback, request_id); + * break; + * } + * } + * + * + * void main_loop(app_context *app) + * { + * int status + * int fd; + * askuser_client *client = NULL; + * + * assert(app != NULL); + * + * status = askuser_client_initialize(&client, ask_status_callback, app); + * if (status != ASKUSER_API_SUCCESS) { + * // handle errors + * return; + * } + * + * app_set_askuser_client(app, client); + * + * // event loop + * for (;;) { + * app_wait_for_events(app); + * + * app_for_each_active_fd(app, fd) { + * if (app_is_askuser_fd(app, fd)) { + * app_events events = app_get_fd_events(app, fd); + * askuser_client_process(client, fd, app_to_askuser_events(events)); + * } + * // process other file descriptors not related to askuser + * } + * } + * + * askuser_client_finalize(client); + * } + * \endcode + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ASKUSER_NOTIFICATION_CLIENT_H */ -- 2.7.4