Implement a notification response wait/send API 93/30093/2 accepted/tizen/common/20141114.144141 accepted/tizen/ivi/20141119.063311 submit/tizen_common/20141114.091625 submit/tizen_ivi/20141119.000000 submit/tizen_ivi/20141119.111111 submit/tizen_mobile/20141120.000000
authorManuel Bachmann <manuel.bachmann@open.eurogiciel.org>
Mon, 10 Nov 2014 13:33:19 +0000 (14:33 +0100)
committerManuel Bachmann <manuel.bachmann@open.eurogiciel.org>
Mon, 10 Nov 2014 14:27:10 +0000 (15:27 +0100)
Currently, interactive responses for notifications (done in
notification-display-service) are sent using a framework-
dependent mechanism. This is prone to become unmaintainable
as the scope of GUI notifications broadens.

There is a need for a generic way to wait for notifications
responses on one side, and to send such a response on
another side. We introduce 2 new functions here :

- notification_wait_response() : retrieves an integer and
a char* from the response, with an optional timeout value.

- notification_send_response() : send a response under the
form of an integer and an optional char*.

Communication is done with sockets using a TID (thread ID)
as an identifier.

Bug-Tizen: TC-996

Change-Id: I86d9d4bc3399dddff03b7f6c7eacbe2f842c5019
Signed-off-by: Manuel Bachmann <manuel.bachmann@open.eurogiciel.org>
CMakeLists.txt
include/notification.h
src/notification.c

index 4c230df..7fa2c0a 100755 (executable)
@@ -57,7 +57,7 @@ FOREACH(flag ${pkgs_CFLAGS})
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
 ENDFOREACH(flag)
 
-SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -g -Wall")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -g -Wall -Wno-unused-result")
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
 
 SET(CMAKE_SKIP_BUILD_RPATH TRUE)
index ddc7e9c..0243f75 100755 (executable)
@@ -1885,6 +1885,46 @@ notification_error_e notification_op_get_data(notification_op *noti_op,
                                                       void *data);
 
 /**
+ * @brief Wait for a response coming for this notification
+ * @details The notification should have the EXECUTE_TYPE_RESPONDING flag
+ * @remarks
+ * @param[in] noti notification handle
+ * @param[in] timeout in seconds - 0 for infinite
+ * @param[out] integer response
+ * @param[out] text response
+ * @return NOTIFICATION_ERROR_NONE if success, other value if failure
+ * @retval NOTIFICATION_ERROR_NONE - success
+ * @retval NOTIFICATION_ERROR_INVALID_DATA - invalid parameter
+ * @retval NOTIFICATION_ERROR_NO_MEMORY - not enough memory
+ * @pre notification handle should be created by notification_new().
+ * @post
+ * @see
+ */
+notification_error_e notification_wait_response(notification_h noti,
+                                               int timeout,
+                                               int *respi,
+                                               char **respc);
+
+/**
+ * @brief Send a response for a waiting notification
+ * @details
+ * @remarks
+ * @param[in] noti notification handle
+ * @param[in] integer response
+ * @param[in] text response
+ * @return NOTIFICATION_ERROR_NONE if success, other value if failure
+ * @retval NOTIFICATION_ERROR_NONE - success
+ * @retval NOTIFICATION_ERROR_INVALID_DATA - invalid parameter
+ * @retval NOTIFICATION_ERROR_NO_MEMORY - not enough memory
+ * @pre notification handle should be created by notification_new().
+ * @post
+ * @see
+ */
+notification_error_e notification_send_response(notification_h noti,
+                                               int respi,
+                                               char *respc);
+
+/**
  * @}
  */
 
index f11ac22..17b9985 100755 (executable)
  *
  */
 
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/un.h>
 #include <libintl.h>
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib-lowlevel.h>
@@ -2805,3 +2810,147 @@ EXPORT_API notification_error_e notification_delete_group_by_priv_id(const char
        }
        return NOTIFICATION_ERROR_NONE;
 }
+
+EXPORT_API notification_error_e notification_wait_response(notification_h noti,
+                                                          int timeout,
+                                                          int *respi,
+                                                          char **respc)
+{
+       bundle *b, *bc = NULL;
+       pid_t tid;
+       const char *tid_c;
+       int sock_fd, msg_fd;
+       char *sock_path;
+       struct sockaddr_un sock_addr;
+       char msg_buffer[1024];
+       ssize_t msg_size;
+       struct timeval timeout_tv;
+       char *resp;
+
+        /* a response packet *must* have an execute option TYPE_RESPONDING
+           with an associated bundle.
+           If its bundle does not already contain a "tid" hint (which
+           complex applications such as xwalk may overwrite), we will
+           try to find the TID and set it in the bundle ourselves. */
+       notification_get_execute_option (noti, NOTIFICATION_EXECUTE_TYPE_RESPONDING,
+       NULL, &b);
+
+       if (b == NULL)
+               return NOTIFICATION_ERROR_INVALID_DATA;
+
+       tid_c = bundle_get_val(b, "tid");
+       if (tid_c == NULL) {
+               tid = syscall(SYS_gettid);
+               asprintf((char **)&tid_c, "%d", tid);
+               bc = bundle_dup(b);
+               bundle_add(bc, "tid", tid_c);
+               notification_set_execute_option (noti, NOTIFICATION_EXECUTE_TYPE_RESPONDING,
+                                                NULL, NULL, bc);
+               notification_update(noti);
+       }
+
+       sock_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (sock_fd == -1)
+               return NOTIFICATION_ERROR_NO_MEMORY;
+
+       sock_addr.sun_family = AF_UNIX;
+       asprintf(&sock_path, "/tmp/.notification-%s", tid_c);
+       strncpy(sock_addr.sun_path, sock_path, sizeof(sock_addr.sun_path) - 1);
+       if (bind(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) == -1) {
+               close(sock_fd);
+               free(sock_path);
+               free((char *)tid_c);
+               return NOTIFICATION_ERROR_NO_MEMORY;
+       }
+
+       if (timeout > 0) {
+               timeout_tv.tv_sec = timeout;
+               timeout_tv.tv_usec = 0;
+               setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout_tv, sizeof(timeout_tv));
+               setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout_tv, sizeof(timeout_tv));
+       }
+
+       listen(sock_fd, 1);
+       msg_fd = accept(sock_fd, NULL, 0);
+       do {
+               msg_size = read(msg_fd, msg_buffer, 1024);
+       } while (msg_size > 0);
+
+       resp = strtok(msg_buffer, "\n");
+       if (resp) {
+               *respi = atoi(resp);
+               if (respc != NULL) {
+                       resp = strtok(NULL, "\n");
+                       if (resp)
+                               *respc = resp;
+                       else
+                               *respc = NULL;
+               }
+       } else {
+               *respi = 0;
+               if (respc != NULL)
+                       *respc = NULL;
+       }
+
+       close(sock_fd);
+       unlink(sock_path);
+       free(sock_path);
+       free((char *)tid_c);
+
+       return NOTIFICATION_ERROR_NONE;
+}
+
+EXPORT_API notification_error_e notification_send_response(notification_h noti,
+                                                          int respi,
+                                                          char *respc)
+{
+       bundle *b = NULL;
+       notification_h notic;
+       int notic_id;
+       char *notic_pkgname;
+       int tid;
+       const char *tid_c;
+       int sock_fd;
+       char *sock_path;
+       struct sockaddr_un sock_addr;
+       char *msg_buffer;
+
+       notification_get_id(noti, NULL, &notic_id);
+       notification_get_pkgname(noti, &notic_pkgname);
+       notic = notification_load(notic_pkgname, notic_id);
+       notification_get_execute_option (notic, NOTIFICATION_EXECUTE_TYPE_RESPONDING,
+       NULL, &b);
+
+       if (b == NULL)
+               return NOTIFICATION_ERROR_INVALID_DATA;
+
+       tid_c = bundle_get_val(b, "tid");
+       if (tid_c == NULL)
+               return NOTIFICATION_ERROR_INVALID_DATA;
+       tid = atoi(tid_c);
+
+       sock_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (sock_fd == -1)
+               return NOTIFICATION_ERROR_NO_MEMORY;
+
+       sock_addr.sun_family = AF_UNIX;
+       asprintf(&sock_path, "/tmp/.notification-%d", tid);
+       strncpy(sock_addr.sun_path, sock_path, sizeof(sock_addr.sun_path) - 1);
+       if (connect(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) == -1) {
+               close(sock_fd);
+               free(sock_path);
+               return NOTIFICATION_ERROR_NO_MEMORY;
+       }
+
+       if (respc)
+               asprintf(&msg_buffer, "%d\n%s\n", respi, respc);
+       else
+               asprintf(&msg_buffer, "%d\n", respi);
+       write(sock_fd, msg_buffer, strlen(msg_buffer) + 1);
+
+       close(sock_fd);
+       free(sock_path);
+       free(msg_buffer);
+
+       return NOTIFICATION_ERROR_NONE;
+}