From 486c47c93c826fea4fb79f3aefbc942aafd738d7 Mon Sep 17 00:00:00 2001 From: Rusty Lynch Date: Fri, 6 Sep 2013 12:10:18 -0700 Subject: [PATCH 01/14] Initial import Change-Id: I7e3c9fb0bbe124c596fe8b17c3de96c9ced752e8 Signed-off-by: Rusty Lynch --- Makefile.am | 22 ++ README | 8 + autogen.sh | 4 + configure.ac | 19 ++ main.c | 23 ++ notification_service.c | 372 ++++++++++++++++++++++ notification_service.h | 20 ++ notifications.service.in | 2 + notifications.socket.in | 5 + service_common.c | 809 +++++++++++++++++++++++++++++++++++++++++++++++ service_common.h | 84 +++++ 11 files changed, 1368 insertions(+) create mode 100644 Makefile.am create mode 100644 README create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 main.c create mode 100644 notification_service.c create mode 100644 notification_service.h create mode 100644 notifications.service.in create mode 100644 notifications.socket.in create mode 100644 service_common.c create mode 100644 service_common.h diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..c0b4bbc --- /dev/null +++ b/Makefile.am @@ -0,0 +1,22 @@ +bin_PROGRAMS = notification-service + +AM_CFLAGS = $(GCC_CFLAGS) +AM_CPPFLAGS = $(GCC_CFLAGS) + +notification_service_SOURCES = \ + main.c \ + notification_service.c \ + service_common.c +notification_service_CFLAGS = -I. $(TIZEN_CFLAGS) +notification_service_LDADD = $(TIZEN_LIBS) + +SCRIPT_IN_FILES = \ + notifications.service.in \ + notifications.socket.in + +install-data-hook: + $(mkinstalldirs) $(DESTDIR)/usr/lib/systemd/system/sockets.target.wants + install -m 0644 notifications.service $(DESTDIR)/usr/lib/systemd/system/notifications.service + install -m 0644 notifications.socket $(DESTDIR)/usr/lib/systemd/system/notifications.socket + ln -fs ../notifications.socket $(DESTDIR)/usr/lib/systemd/system/sockets.target.wants/notifications.socket + diff --git a/README b/README new file mode 100644 index 0000000..0c9f207 --- /dev/null +++ b/README @@ -0,0 +1,8 @@ +This package consist of the notification-service implementation picked out of the Tizen data-provider-master project at: +https://review.tizen.org/git/?p=platform/framework/web/data-provider-master.git;a=summary + +This implementation had no real dependencies on the rest of the services provided by data-provider-master which were very mobile profile specific, so it was forked into this new project and adopted as an IVI component. + +Eventually this project might be proposed as a generic Tizen 3.0 component, with the old implementation in data-provider-master removed, but first the implementation will be proven and optimized in the IVI profile (even though there is nothing IVI specific about this code.) + + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..3ca9aba --- /dev/null +++ b/autogen.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +autoreconf --force -v --install +test -n "$NOCONFIGURE" || "./configure" "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..394cdfe --- /dev/null +++ b/configure.ac @@ -0,0 +1,19 @@ +AC_PREREQ([2.68]) +AC_INIT([notification-service], [0.0.1], []) +AM_INIT_AUTOMAKE([foreign 1.11]) +AC_CONFIG_SRCDIR([configure.ac]) +AC_CONFIG_HEADERS([config.h]) + +AC_PROG_CC + +LT_PREREQ([2.2]) +LT_INIT([disable-static]) + +PKG_PROG_PKG_CONFIG() +PKG_CHECK_MODULES([TIZEN], [eina ecore com-core notification]) +AC_SUBST(TIZEN_CFLAGS) +AC_SUBST(TIZEN_LIBS) + +AC_CONFIG_FILES([Makefile notifications.service notifications.socket]) +AC_PROG_RANLIB([ranlib]) +AC_OUTPUT diff --git a/main.c b/main.c new file mode 100644 index 0000000..2af826c --- /dev/null +++ b/main.c @@ -0,0 +1,23 @@ +#include +#include + +int +main(int argc, char **argv) +{ + if (!ecore_init()) { + fprintf(stderr, "ERROR: Cannot init Ecore!\n"); + return -1; + } + + if (notification_service_init() != 0) { + fprintf(stderr, "Unable to initialize notification service!\n"); + goto shutdown; + } + + ecore_main_loop_begin(); + + shutdown: + ecore_shutdown(); + return 0; +} + diff --git a/notification_service.c b/notification_service.c new file mode 100644 index 0000000..93e8d52 --- /dev/null +++ b/notification_service.c @@ -0,0 +1,372 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ +#include +#include +#include +#include +#include +#include + +#include "service_common.h" + +#ifndef NOTIFICATION_ADDR +#define NOTIFICATION_ADDR "/tmp/.notification.service" +#endif + +#ifndef NOTIFICATION_DEL_PACKET_UNIT +#define NOTIFICATION_DEL_PACKET_UNIT 10 +#endif + +static struct info { + Eina_List *context_list; + struct service_context *svc_ctx; +} s_info = { + .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */ + .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */ +}; + +struct context { + struct tcb *tcb; + double seq; +}; + +struct noti_service { + const char *cmd; + void (*handler)(struct tcb *tcb, struct packet *packet, void *data); +}; + +/*! + * FUNCTIONS to handle notifcation + */ +static inline int get_priv_id(int num_deleted, int *list_deleted, int index) { + if (index < num_deleted) { + return *(list_deleted + index); + } else { + return -1; + } +} + +static inline char *get_string(char *string) +{ + if (string == NULL) { + return NULL; + } + if (string[0] == '\0') { + return NULL; + } + + return string; +} + +static inline struct packet *create_packet_from_deleted_list(int op_num, int *list, int start_index) { + return packet_create( + "del_noti_multiple", + "iiiiiiiiiii", + ((op_num - start_index) > NOTIFICATION_DEL_PACKET_UNIT) ? NOTIFICATION_DEL_PACKET_UNIT : op_num - start_index, + get_priv_id(op_num, list, start_index), + get_priv_id(op_num, list, start_index + 1), + get_priv_id(op_num, list, start_index + 2), + get_priv_id(op_num, list, start_index + 3), + get_priv_id(op_num, list, start_index + 4), + get_priv_id(op_num, list, start_index + 5), + get_priv_id(op_num, list, start_index + 6), + get_priv_id(op_num, list, start_index + 7), + get_priv_id(op_num, list, start_index + 8), + get_priv_id(op_num, list, start_index + 9) + ); +} + +/*! + * SERVICE HANDLER + */ +static void _handler_insert(struct tcb *tcb, struct packet *packet, void *data) +{ + int ret = 0; + int priv_id = 0; + struct packet *packet_reply = NULL; + struct packet *packet_service = NULL; + notification_h noti = NULL; + + noti = notification_create(NOTIFICATION_TYPE_NOTI); + if (noti != NULL) { + if (notification_ipc_make_noti_from_packet(noti, packet) == NOTIFICATION_ERROR_NONE) { + ret = notification_noti_insert(noti); + if (ret != NOTIFICATION_ERROR_NONE) { + notification_free(noti); + return ; + } + + notification_get_id(noti, NULL, &priv_id); + packet_reply = packet_create_reply(packet, "ii", ret, priv_id); + if (packet_reply) { + service_common_unicast_packet(tcb, packet_reply); + packet_destroy(packet_reply); + } + + packet_service = notification_ipc_make_packet_from_noti(noti, "add_noti", 2); + if (packet_service != NULL) { + service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE); + packet_destroy(packet_service); + } + } + notification_free(noti); + } +} + +static void _handler_update(struct tcb *tcb, struct packet *packet, void *data) +{ + int ret = 0; + int priv_id = 0; + struct packet *packet_reply = NULL; + struct packet *packet_service = NULL; + notification_h noti = NULL; + + noti = notification_create(NOTIFICATION_TYPE_NOTI); + if (noti != NULL) { + if (notification_ipc_make_noti_from_packet(noti, packet) == NOTIFICATION_ERROR_NONE) { + ret = notification_noti_update(noti); + if (ret != NOTIFICATION_ERROR_NONE) { + notification_free(noti); + return ; + } + + notification_get_id(noti, NULL, &priv_id); + packet_reply = packet_create_reply(packet, "ii", ret, priv_id); + if (packet_reply) { + service_common_unicast_packet(tcb, packet_reply); + packet_destroy(packet_reply); + } + + packet_service = notification_ipc_make_packet_from_noti(noti, "update_noti", 2); + if (packet_service != NULL) { + service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE); + packet_destroy(packet_service); + } + } + notification_free(noti); + } +} + +static void _handler_refresh(struct tcb *tcb, struct packet *packet, void *data) +{ + int ret = NOTIFICATION_ERROR_NONE; + struct packet *packet_reply = NULL; + + packet_reply = packet_create_reply(packet, "i", ret); + if (packet_reply) { + service_common_unicast_packet(tcb, packet_reply); + packet_destroy(packet_reply); + } + + service_common_multicast_packet(tcb, packet, TCB_CLIENT_TYPE_SERVICE); +} + +static void _handler_delete_single(struct tcb *tcb, struct packet *packet, void *data) +{ + int ret = 0; + int priv_id = 0; + struct packet *packet_reply = NULL; + struct packet *packet_service = NULL; + char *pkgname = NULL; + + if (packet_get(packet, "si", &pkgname, &priv_id) == 2) { + pkgname = get_string(pkgname); + + ret = notification_noti_delete_by_priv_id(pkgname, priv_id); + + packet_reply = packet_create_reply(packet, "ii", ret, priv_id); + if (packet_reply) { + service_common_unicast_packet(tcb, packet_reply); + packet_destroy(packet_reply); + } + + packet_service = packet_create("del_noti_single", "ii", 1, priv_id); + if (packet_service != NULL) { + service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE); + packet_destroy(packet_service); + } + } +} + +static void _handler_delete_multiple(struct tcb *tcb, struct packet *packet, void *data) +{ + int ret = 0; + struct packet *packet_reply = NULL; + struct packet *packet_service = NULL; + char *pkgname = NULL; + notification_type_e type = 0; + int num_deleted = 0; + int *list_deleted = NULL; + + if (packet_get(packet, "si", &pkgname, &type) == 2) { + pkgname = get_string(pkgname); + + ret = notification_noti_delete_all(type, pkgname, &num_deleted, &list_deleted); + + packet_reply = packet_create_reply(packet, "ii", ret, num_deleted); + if (packet_reply) { + service_common_unicast_packet(tcb, packet_reply); + packet_destroy(packet_reply); + } + + if (num_deleted > 0) { + if (num_deleted <= NOTIFICATION_DEL_PACKET_UNIT) { + packet_service = create_packet_from_deleted_list(num_deleted, list_deleted, 0); + + if (packet_service) { + service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE); + packet_destroy(packet_service); + } + } else { + int set = 0; + int set_total = num_deleted / NOTIFICATION_DEL_PACKET_UNIT; + + for (set = 0; set <= set_total; set++) { + packet_service = create_packet_from_deleted_list(num_deleted, + list_deleted, set * NOTIFICATION_DEL_PACKET_UNIT); + + if (packet_service) { + service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE); + packet_destroy(packet_service); + } + } + } + } + + if (list_deleted != NULL) { + free(list_deleted); + list_deleted = NULL; + } + } +} + +static void _handler_service_register(struct tcb *tcb, struct packet *packet, void *data) +{ + struct packet *packet_reply; + int ret; + + ret = tcb_client_type_set(tcb, TCB_CLIENT_TYPE_SERVICE); + + packet_reply = packet_create_reply(packet, "i", ret); + if (packet_reply) { + service_common_unicast_packet(tcb, packet_reply); + packet_destroy(packet_reply); + } +} + +/*! + * SERVICE THREAD + */ +static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data) +{ + int i = 0; + const char *command; + static struct noti_service service_req_table[] = { + { + .cmd = "add_noti", + .handler = _handler_insert, + }, + { + .cmd = "update_noti", + .handler = _handler_update, + }, + { + .cmd = "refresh_noti", + .handler = _handler_refresh, + }, + { + .cmd = "del_noti_single", + .handler = _handler_delete_single, + }, + { + .cmd = "del_noti_multiple", + .handler = _handler_delete_multiple, + }, + { + .cmd = "service_register", + .handler = _handler_service_register, + }, + { + .cmd = NULL, + .handler = NULL, + }, + }; + + if (!packet) { + return 0; + } + + command = packet_command(packet); + if (!command) { + return -EINVAL; + } + + switch (packet_type(packet)) { + case PACKET_REQ: + /* Need to send reply packet */ + for (i = 0; service_req_table[i].cmd; i++) { + if (strcmp(service_req_table[i].cmd, command)) + continue; + + service_req_table[i].handler(tcb, packet, data); + break; + } + + break; + case PACKET_REQ_NOACK: + break; + case PACKET_ACK: + break; + default: + return -EINVAL; + } + + /*! + * return value has no meanning, + * it will be printed by dlogutil. + */ + return 0; +} + + +/*! + * MAIN THREAD + * Do not try to do anyother operation in these functions + */ +int notification_service_init(void) +{ + if (s_info.svc_ctx) { + return -1; + } + + s_info.svc_ctx = service_common_create(NOTIFICATION_ADDR, service_thread_main, NULL); + if (!s_info.svc_ctx) { + return -1; + } + + return 0; +} + +int notification_service_fini(void) +{ + if (!s_info.svc_ctx) + return -1; + + service_common_destroy(s_info.svc_ctx); + return 0; +} + +/* End of a file */ diff --git a/notification_service.h b/notification_service.h new file mode 100644 index 0000000..e02dfa3 --- /dev/null +++ b/notification_service.h @@ -0,0 +1,20 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +extern int notification_service_init(void); +extern int notification_service_fini(void); + +/* End of a file */ diff --git a/notifications.service.in b/notifications.service.in new file mode 100644 index 0000000..47db370 --- /dev/null +++ b/notifications.service.in @@ -0,0 +1,2 @@ +[Service] +ExecStart=/usr/bin/notification-service diff --git a/notifications.socket.in b/notifications.socket.in new file mode 100644 index 0000000..cdd863f --- /dev/null +++ b/notifications.socket.in @@ -0,0 +1,5 @@ +[Socket] +ListenStream=/tmp/.notification.service + +[Install] +WantedBy=sockets.target diff --git a/service_common.c b/service_common.c new file mode 100644 index 0000000..db79011 --- /dev/null +++ b/service_common.c @@ -0,0 +1,809 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "service_common.h" + +#define EVT_CH 'e' +#define EVT_END_CH 'x' + +int errno; + +struct service_event_item { + enum { + SERVICE_EVENT_TIMER, + } type; + + union { + struct { + int fd; + } timer; + } info; + + int (*event_cb)(struct service_context *svc_cx, void *data); + void *cbdata; +}; + +/*! + * \note + * Server information and global (only in this file-scope) variables are defined + */ +struct service_context { + pthread_t server_thid; /*!< Server thread Id */ + int fd; /*!< Server socket handle */ + + Eina_List *tcb_list; /*!< TCB list, list of every thread for client connections */ + + Eina_List *packet_list; + pthread_mutex_t packet_list_lock; + int evt_pipe[PIPE_MAX]; + int tcb_pipe[PIPE_MAX]; + + int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data); + void *service_thread_data; + + Eina_List *event_list; +}; + +struct packet_info { + struct tcb *tcb; + struct packet *packet; +}; + +/*! + * \note + * Thread Control Block + * - The main server will create a thread for every client connections. + * When a new client is comming to us, this TCB block will be allocated and initialized. + */ +struct tcb { /* Thread controll block */ + struct service_context *svc_ctx; + pthread_t thid; /*!< Thread Id */ + int fd; /*!< Connection handle */ + enum tcb_type type; +}; + +/*! + * Do services for clients + * Routing packets to destination processes. + * CLIENT THREAD + */ +static void *client_packet_pump_main(void *data) +{ + struct tcb *tcb = data; + struct service_context *svc_ctx = tcb->svc_ctx; + struct packet *packet; + fd_set set; + char *ptr; + int size; + int packet_offset; + int recv_offset; + int pid; + long ret; + char evt_ch = EVT_CH; + enum { + RECV_INIT, + RECV_HEADER, + RECV_PAYLOAD, + RECV_DONE, + } recv_state; + struct packet_info *packet_info; + Eina_List *l; + + ret = 0; + recv_state = RECV_INIT; + /*! + * \note + * To escape from the switch statement, we use this ret value + */ + while (ret == 0) { + FD_ZERO(&set); + FD_SET(tcb->fd, &set); + ret = select(tcb->fd + 1, &set, NULL, NULL, NULL); + if (ret < 0) { + ret = -errno; + if (errno == EINTR) { + ret = 0; + continue; + } + free(ptr); + ptr = NULL; + break; + } else if (ret == 0) { + ret = -ETIMEDOUT; + free(ptr); + ptr = NULL; + break; + } + + if (!FD_ISSET(tcb->fd, &set)) { + ret = -EINVAL; + free(ptr); + ptr = NULL; + break; + } + + /*! + * \TODO + * Service!!! Receive packet & route packet + */ + switch (recv_state) { + case RECV_INIT: + size = packet_header_size(); + packet_offset = 0; + recv_offset = 0; + packet = NULL; + ptr = malloc(size); + if (!ptr) { + ret = -ENOMEM; + break; + } + recv_state = RECV_HEADER; + /* Go through, don't break from here */ + case RECV_HEADER: + ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid); + if (ret <= 0) { + if (ret == 0) + ret = -ECANCELED; + free(ptr); + ptr = NULL; + break; + } + + recv_offset += ret; + ret = 0; + + if (recv_offset == size) { + packet = packet_build(packet, packet_offset, ptr, size); + free(ptr); + ptr = NULL; + if (!packet) { + ret = -EFAULT; + break; + } + + packet_offset += recv_offset; + + size = packet_payload_size(packet); + if (size <= 0) { + recv_state = RECV_DONE; + recv_offset = 0; + break; + } + + recv_state = RECV_PAYLOAD; + recv_offset = 0; + + ptr = malloc(size); + if (!ptr) { + ret = -ENOMEM; + } + } + break; + case RECV_PAYLOAD: + ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid); + if (ret <= 0) { + if (ret == 0) + ret = -ECANCELED; + free(ptr); + ptr = NULL; + break; + } + + recv_offset += ret; + ret = 0; + + if (recv_offset == size) { + packet = packet_build(packet, packet_offset, ptr, size); + free(ptr); + ptr = NULL; + if (!packet) { + ret = -EFAULT; + break; + } + + packet_offset += recv_offset; + + recv_state = RECV_DONE; + recv_offset = 0; + } + break; + case RECV_DONE: + default: + /* Dead code */ + break; + } + + if (recv_state == RECV_DONE) { + /*! + * Push this packet to the packet list with TCB + * Then the service main function will get this. + */ + packet_info = malloc(sizeof(*packet_info)); + if (!packet_info) { + ret = -errno; + packet_destroy(packet); + break; + } + + packet_info->packet = packet; + packet_info->tcb = tcb; + + CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock); + svc_ctx->packet_list = eina_list_append(svc_ctx->packet_list, packet_info); + CRITICAL_SECTION_END(&svc_ctx->packet_list_lock); + + if (write(svc_ctx->evt_pipe[PIPE_WRITE], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) { + ret = -errno; + CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock); + svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info); + CRITICAL_SECTION_END(&svc_ctx->packet_list_lock); + + packet_destroy(packet); + free(packet_info); + break; + } else { + recv_state = RECV_INIT; + } + } + } + + CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock); + EINA_LIST_FOREACH(svc_ctx->packet_list, l, packet_info) { + if (packet_info->tcb == tcb) { + packet_info->tcb = NULL; + } + } + CRITICAL_SECTION_END(&svc_ctx->packet_list_lock); + + /*! + * \note + * Emit a signal to collect this TCB from the SERVER THREAD. + */ + write(svc_ctx->tcb_pipe[PIPE_WRITE], &tcb, sizeof(tcb)) != sizeof(tcb); + + return (void *)ret; +} + +/*! + * \note + * SERVER THREAD + */ +static inline struct tcb *tcb_create(struct service_context *svc_ctx, int fd) +{ + struct tcb *tcb; + int status; + + tcb = malloc(sizeof(*tcb)); + if (!tcb) { + return NULL; + } + + tcb->fd = fd; + tcb->svc_ctx = svc_ctx; + tcb->type = TCB_CLIENT_TYPE_APP; + + status = pthread_create(&tcb->thid, NULL, client_packet_pump_main, tcb); + if (status != 0) { + free(tcb); + return NULL; + } + + svc_ctx->tcb_list = eina_list_append(svc_ctx->tcb_list, tcb); + return tcb; +} + +/*! + * \note + * SERVER THREAD + */ +static inline void tcb_teminate_all(struct service_context *svc_ctx) +{ + struct tcb *tcb; + void *ret; + int status; + + /*! + * We don't need to make critical section on here. + * If we call this after terminate the server thread first. + * Then there is no other thread to access tcb_list. + */ + EINA_LIST_FREE(svc_ctx->tcb_list, tcb) { + /*! + * ASSERT(tcb->fd >= 0); + */ + secure_socket_destroy_handle(tcb->fd); + + status = pthread_join(tcb->thid, &ret); + + free(tcb); + } +} + +/*! + * \note + * SERVER THREAD + */ +static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb) +{ + void *ret; + int status; + + svc_ctx->tcb_list = eina_list_remove(svc_ctx->tcb_list, tcb); + /*! + * ASSERT(tcb->fd >= 0); + * Close the connection, and then collecting the return value of thread + */ + secure_socket_destroy_handle(tcb->fd); + + status = pthread_join(tcb->thid, &ret); + + free(tcb); +} + +/*! + * \note + * SERVER THREAD + */ +static inline int find_max_fd(struct service_context *svc_ctx) +{ + int fd; + Eina_List *l; + struct service_event_item *item; + + fd = svc_ctx->fd > svc_ctx->tcb_pipe[PIPE_READ] ? svc_ctx->fd : svc_ctx->tcb_pipe[PIPE_READ]; + fd = fd > svc_ctx->evt_pipe[PIPE_READ] ? fd : svc_ctx->evt_pipe[PIPE_READ]; + + EINA_LIST_FOREACH(svc_ctx->event_list, l, item) { + if (item->type == SERVICE_EVENT_TIMER && fd < item->info.timer.fd) + fd = item->info.timer.fd; + } + + fd += 1; + return fd; +} + +/*! + * \note + * SERVER THREAD + */ +static inline void update_fdset(struct service_context *svc_ctx, fd_set *set) +{ + Eina_List *l; + struct service_event_item *item; + + FD_ZERO(set); + FD_SET(svc_ctx->fd, set); + FD_SET(svc_ctx->tcb_pipe[PIPE_READ], set); + FD_SET(svc_ctx->evt_pipe[PIPE_READ], set); + + EINA_LIST_FOREACH(svc_ctx->event_list, l, item) { + if (item->type == SERVICE_EVENT_TIMER) + FD_SET(item->info.timer.fd, set); + } +} + +/*! + * \note + * SERVER THREAD + */ +static inline void processing_timer_event(struct service_context *svc_ctx, fd_set *set) +{ + uint64_t expired_count; + Eina_List *l; + Eina_List *n; + struct service_event_item *item; + + EINA_LIST_FOREACH_SAFE(svc_ctx->event_list, l, n, item) { + switch (item->type) { + case SERVICE_EVENT_TIMER: + if (!FD_ISSET(item->info.timer.fd, set)) + break; + + if (read(item->info.timer.fd, &expired_count, sizeof(expired_count)) == sizeof(expired_count)) { + if (item->event_cb(svc_ctx, item->cbdata) >= 0) + break; + } + + if (!eina_list_data_find(svc_ctx->event_list, item)) + break; + + svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item); + close(item->info.timer.fd); + + free(item); + break; + default: + break; + } + } +} + +/*! + * Accept new client connections + * And create a new thread for service. + * + * Create Client threads & Destroying them + * SERVER THREAD + */ +static void *server_main(void *data) +{ + struct service_context *svc_ctx = data; + fd_set set; + long ret; + int client_fd; + struct tcb *tcb; + int fd; + char evt_ch; + struct packet_info *packet_info; + + while (1) { + fd = find_max_fd(svc_ctx); + update_fdset(svc_ctx, &set); + + ret = select(fd, &set, NULL, NULL, NULL); + if (ret < 0) { + ret = -errno; + if (errno == EINTR) { + continue; + } + break; + } else if (ret == 0) { + ret = -ETIMEDOUT; + break; + } + + if (FD_ISSET(svc_ctx->fd, &set)) { + client_fd = secure_socket_get_connection_handle(svc_ctx->fd); + if (client_fd < 0) { + ret = -EFAULT; + break; + } + + tcb = tcb_create(svc_ctx, client_fd); + if (!tcb) + secure_socket_destroy_handle(client_fd); + } + + if (FD_ISSET(svc_ctx->tcb_pipe[PIPE_READ], &set)) { + if (read(svc_ctx->tcb_pipe[PIPE_READ], &tcb, sizeof(tcb)) != sizeof(tcb)) { + ret = -EFAULT; + break; + } + + /*! + * \note + * Invoke the service thread main, to notify the termination of a TCB + */ + ret = svc_ctx->service_thread_main(tcb, NULL, svc_ctx->service_thread_data); + + /*! + * at this time, the client thread can access this tcb. + * how can I protect this TCB from deletion without disturbing the server thread? + */ + tcb_destroy(svc_ctx, tcb); + } + + if (FD_ISSET(svc_ctx->evt_pipe[PIPE_READ], &set)) { + if (read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) { + ret = -EFAULT; + break; + } + + CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock); + packet_info = eina_list_nth(svc_ctx->packet_list, 0); + svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info); + CRITICAL_SECTION_END(&svc_ctx->packet_list_lock); + + /*! + * \CRITICAL + * What happens if the client thread is terminated, so the packet_info->tcb is deleted + * while processing svc_ctx->service_thread_main? + */ + ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data); + + packet_destroy(packet_info->packet); + free(packet_info); + } + + processing_timer_event(svc_ctx, &set); + /* If there is no such triggered FD? */ + } + + /*! + * Consuming all pended packets before terminates server thread. + * + * If the server thread is terminated, we should flush all pended packets. + * And we should services them. + * While processing this routine, the mutex is locked. + * So every other client thread will be slowed down, sequently, every clients can meet problems. + * But in case of termination of server thread, there could be systemetic problem. + * This only should be happenes while terminating the master daemon process. + */ + CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock); + EINA_LIST_FREE(svc_ctx->packet_list, packet_info) { + ret = read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch)); + ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data); + packet_destroy(packet_info->packet); + free(packet_info); + } + CRITICAL_SECTION_END(&svc_ctx->packet_list_lock); + + tcb_teminate_all(svc_ctx); + return (void *)ret; +} + +/*! + * \NOTE + * MAIN THREAD + */ +struct service_context *service_common_create(const char *addr, int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data), void *data) +{ + int status; + struct service_context *svc_ctx; + + if (!service_thread_main || !addr) { + return NULL; + } + + svc_ctx = calloc(1, sizeof(*svc_ctx)); + if (!svc_ctx) { + return NULL; + } + + /* + * cleanup old socket file + */ + struct stat tmp; + if (!stat(addr, &tmp)) { + if (unlink(addr)) { + perror("Unable to unlink old socket file"); + free(svc_ctx); + return NULL; + } + } + + svc_ctx->fd = secure_socket_create_server(addr); + if (svc_ctx->fd < 0) { + free(svc_ctx); + return NULL; + } + + svc_ctx->service_thread_main = service_thread_main; + svc_ctx->service_thread_data = data; + + fcntl(svc_ctx->fd, F_SETFD, FD_CLOEXEC); + + fcntl(svc_ctx->fd, F_SETFL, O_NONBLOCK); + + if (pipe2(svc_ctx->evt_pipe, O_NONBLOCK | O_CLOEXEC) < 0) { + secure_socket_destroy_handle(svc_ctx->fd); + free(svc_ctx); + return NULL; + } + + if (pipe2(svc_ctx->tcb_pipe, O_NONBLOCK | O_CLOEXEC) < 0) { + CLOSE_PIPE(svc_ctx->evt_pipe); + secure_socket_destroy_handle(svc_ctx->fd); + free(svc_ctx); + return NULL; + } + + status = pthread_mutex_init(&svc_ctx->packet_list_lock, NULL); + if (status != 0) { + CLOSE_PIPE(svc_ctx->evt_pipe); + CLOSE_PIPE(svc_ctx->tcb_pipe); + secure_socket_destroy_handle(svc_ctx->fd); + free(svc_ctx); + return NULL; + } + + status = pthread_create(&svc_ctx->server_thid, NULL, server_main, svc_ctx); + if (status != 0) { + status = pthread_mutex_destroy(&svc_ctx->packet_list_lock); + CLOSE_PIPE(svc_ctx->evt_pipe); + CLOSE_PIPE(svc_ctx->tcb_pipe); + secure_socket_destroy_handle(svc_ctx->fd); + free(svc_ctx); + return NULL; + } + + return svc_ctx; +} + +/*! + * \note + * MAIN THREAD + */ +int service_common_destroy(struct service_context *svc_ctx) +{ + int status; + void *ret; + + if (!svc_ctx) + return -EINVAL; + + /*! + * \note + * Terminate server thread + */ + secure_socket_destroy_handle(svc_ctx->fd); + + status = pthread_join(svc_ctx->server_thid, &ret); + + status = pthread_mutex_destroy(&svc_ctx->packet_list_lock); + + CLOSE_PIPE(svc_ctx->evt_pipe); + CLOSE_PIPE(svc_ctx->tcb_pipe); + free(svc_ctx); + return 0; +} + +/*! + * \note + * SERVER THREAD + */ +int tcb_fd(struct tcb *tcb) +{ + if (!tcb) + return -EINVAL; + + return tcb->fd; +} + +/*! + * \note + * SERVER THREAD + */ +int tcb_client_type(struct tcb *tcb) +{ + if (!tcb) + return -EINVAL; + + return tcb->type; +} + +/*! + * \note + * SERVER THREAD + */ +int tcb_client_type_set(struct tcb *tcb, enum tcb_type type) +{ + if (!tcb) + return -EINVAL; + + tcb->type = type; + return 0; +} + +/*! + * \note + * SERVER THREAD + */ +struct service_context *tcb_svc_ctx(struct tcb *tcb) +{ + if (!tcb) + return NULL; + + return tcb->svc_ctx; +} + +/*! + * \note + * SERVER THREAD + */ +int service_common_unicast_packet(struct tcb *tcb, struct packet *packet) +{ + if (!tcb || !packet) + return -EINVAL; + + return secure_socket_send(tcb->fd, (void *)packet_data(packet), packet_size(packet)); +} + +/*! + * \note + * SERVER THREAD + */ +int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type) +{ + Eina_List *l; + struct tcb *target; + struct service_context *svc_ctx; + int ret; + + if (!tcb || !packet) + return -EINVAL; + + svc_ctx = tcb->svc_ctx; + + EINA_LIST_FOREACH(svc_ctx->tcb_list, l, target) { + if (target == tcb || target->type != type) { + continue; + } + + ret = secure_socket_send(target->fd, (void *)packet_data(packet), packet_size(packet)); + } + return 0; +} + +/*! + * \note + * SERVER THREAD + */ +struct service_event_item *service_common_add_timer(struct service_context *svc_ctx, double timer, int (*timer_cb)(struct service_context *svc_cx, void *data), void *data) +{ + struct service_event_item *item; + struct itimerspec spec; + + item = calloc(1, sizeof(*item)); + if (!item) { + return NULL; + } + + item->type = SERVICE_EVENT_TIMER; + item->info.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if (item->info.timer.fd < 0) { + free(item); + return NULL; + } + + spec.it_interval.tv_sec = (time_t)timer; + spec.it_interval.tv_nsec = (timer - spec.it_interval.tv_sec) * 1000000000; + spec.it_value.tv_sec = 0; + spec.it_value.tv_nsec = 0; + + if (timerfd_settime(item->info.timer.fd, 0, &spec, NULL) < 0) { + close(item->info.timer.fd); + free(item); + return NULL; + } + + item->event_cb = timer_cb; + item->cbdata = data; + + svc_ctx->event_list = eina_list_append(svc_ctx->event_list, item); + return item; +} + +/*! + * \note + * SERVER THREAD + */ +int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item) +{ + if (!eina_list_data_find(svc_ctx->event_list, item)) { + return -EINVAL; + } + + svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item); + + close(item->info.timer.fd); + free(item); + return 0; +} + +/* End of a file */ diff --git a/service_common.h b/service_common.h new file mode 100644 index 0000000..3dc7d46 --- /dev/null +++ b/service_common.h @@ -0,0 +1,84 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ +enum tcb_type { + TCB_CLIENT_TYPE_APP = 0x00, + TCB_CLIENT_TYPE_SERVICE = 0x01, + TCB_CLIENT_TYPE_UNKNOWN = 0xff, +}; + +struct tcb; +struct service_context; +struct service_event_item; + +extern int tcb_fd(struct tcb *tcb); +extern struct service_context *tcb_svc_ctx(struct tcb *tcb); +extern int tcb_client_type(struct tcb *tcb); +extern int tcb_client_type_set(struct tcb *tcb, enum tcb_type type); + +extern struct service_context *service_common_create(const char *addr, int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data), void *data); +extern int service_common_destroy(struct service_context *svc_ctx); + +extern int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type); +extern int service_common_unicast_packet(struct tcb *tcb, struct packet *packet); + +extern struct service_event_item *service_common_add_timer(struct service_context *svc_ctx, double timer, int (*timer_cb)(struct service_context *svc_cx, void *data), void *data); +extern int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item); + +#define CRITICAL_SECTION_BEGIN(handle) \ +do { \ + int ret; \ + ret = pthread_mutex_lock(handle); \ + if (ret != 0) \ + fprintf(stderr, "Failed to lock: %s\n", strerror(ret)); \ +} while (0) + +#define CRITICAL_SECTION_END(handle) \ +do { \ + int ret; \ + ret = pthread_mutex_unlock(handle); \ + if (ret != 0) \ + fprintf(stderr, "Failed to unlock: %s\n", strerror(ret)); \ +} while (0) + +#define CANCEL_SECTION_BEGIN() do { \ + int ret; \ + ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); \ + if (ret != 0) \ + fprintf(stderr, "Unable to set cancelate state: %s\n", strerror(ret)); \ +} while (0) + +#define CANCEL_SECTION_END() do { \ + int ret; \ + ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); \ + if (ret != 0) \ + fprintf(stderr, "Unable to set cancelate state: %s\n", strerror(ret)); \ +} while (0) + +#define CLOSE_PIPE(p) do { \ + int status; \ + status = close(p[PIPE_READ]); \ + if (status < 0) \ + fprintf(stderr, "close: %s\n", strerror(errno)); \ + status = close(p[PIPE_WRITE]); \ + if (status < 0) \ + fprintf(stderr, "close: %s\n", strerror(errno)); \ +} while (0) + +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define PIPE_MAX 2 + +/* End of a file */ -- 2.7.4 From 92d69a9d6f7bf1c2f2a3ff849768e4bf6529e650 Mon Sep 17 00:00:00 2001 From: Rusty Lynch Date: Fri, 6 Sep 2013 12:13:36 -0700 Subject: [PATCH 02/14] Add packaging Change-Id: Id31a139d6fadc5a43c9082bca772f1a21f6c5f9d Signed-off-by: Rusty Lynch --- packaging/notification-service.changes | 3 +++ packaging/notification-service.spec | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 packaging/notification-service.changes create mode 100644 packaging/notification-service.spec diff --git a/packaging/notification-service.changes b/packaging/notification-service.changes new file mode 100644 index 0000000..b78ee49 --- /dev/null +++ b/packaging/notification-service.changes @@ -0,0 +1,3 @@ +* Fri Sep 06 2013 Rusty Lynch 3fb22fc +- Initial import + diff --git a/packaging/notification-service.spec b/packaging/notification-service.spec new file mode 100644 index 0000000..4028a2c --- /dev/null +++ b/packaging/notification-service.spec @@ -0,0 +1,36 @@ +Name: notification-service +Summary: Simple notification service +Version: 0.0.1 +Release: 1 +Group: Application Framework/Notifications +License: Flora +Source0: %{name}-%{version}.tar.bz2 +BuildRequires: pkgconfig(eina) +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(com-core) +BuildRequires: pkgconfig(notification) + +%description +Headless notification service that collects incoming notifications from the +the platform, maintains a database of active notifications, and broadcast updates +to all listeners. + +%prep +%setup -q -n %{name}-%{version} + +%define PREFIX %{_prefix}/apps/ + +%build +%autogen +make %{?_smp_mflags} + +%install +rm -rf %{buildroot} +%make_install + +%files +%defattr(-,root,root,-) +%{_bindir}/notification-service +%{_libdir}/systemd/system/notifications.service +%{_libdir}/systemd/system/notifications.socket +%{_libdir}/systemd/system/sockets.target.wants/notifications.socket -- 2.7.4 From 340924fcd3bcf1f0d0ca1e8fd32bfe75b02ab59b Mon Sep 17 00:00:00 2001 From: Rusty Lynch Date: Tue, 10 Sep 2013 11:49:40 -0700 Subject: [PATCH 03/14] Add unit test for sending and recieving notifications Change-Id: Id3c6aa1868a9267d3ffea18a5fcb863bec1f3cf0 --- Makefile.am | 10 ++- packaging/notification-service.spec | 11 +++ sample_display_client.c | 64 +++++++++++++++ send_notification.c | 157 ++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 sample_display_client.c create mode 100644 send_notification.c diff --git a/Makefile.am b/Makefile.am index c0b4bbc..5b7257b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -bin_PROGRAMS = notification-service +bin_PROGRAMS = notification-service sample-display-client send-notification AM_CFLAGS = $(GCC_CFLAGS) AM_CPPFLAGS = $(GCC_CFLAGS) @@ -10,6 +10,14 @@ notification_service_SOURCES = \ notification_service_CFLAGS = -I. $(TIZEN_CFLAGS) notification_service_LDADD = $(TIZEN_LIBS) +send_notification_SOURCES = send_notification.c +send_notification_CFLAGS = -I. $(TIZEN_CFLAGS) +send_notification_LDADD = $(TIZEN_LIBS) + +sample_display_client_SOURCES = sample_display_client.c +sample_display_client_CFLAGS = -I. $(TIZEN_CFLAGS) +sample_display_client_LDADD = $(TIZEN_LIBS) + SCRIPT_IN_FILES = \ notifications.service.in \ notifications.socket.in diff --git a/packaging/notification-service.spec b/packaging/notification-service.spec index 4028a2c..d2e8b4d 100644 --- a/packaging/notification-service.spec +++ b/packaging/notification-service.spec @@ -15,6 +15,12 @@ Headless notification service that collects incoming notifications from the the platform, maintains a database of active notifications, and broadcast updates to all listeners. +%package test +Summary: Test clients for %{name} +Group: Application Framework/Notifications +%description test +This package provides unit test used in the development of the notification service. + %prep %setup -q -n %{name}-%{version} @@ -34,3 +40,8 @@ rm -rf %{buildroot} %{_libdir}/systemd/system/notifications.service %{_libdir}/systemd/system/notifications.socket %{_libdir}/systemd/system/sockets.target.wants/notifications.socket + +%files test +%defattr(-,root,root,-) +%{_bindir}/sample-display-client +%{_bindir}/send-notification diff --git a/sample_display_client.c b/sample_display_client.c new file mode 100644 index 0000000..1f449f0 --- /dev/null +++ b/sample_display_client.c @@ -0,0 +1,64 @@ +#include +#include +#include + +static void __noti_changed_cb(void *data, notification_type_e type) +{ + notification_h noti = NULL; + notification_list_h notification_list = NULL; + notification_list_h get_list = NULL; + int count = 0, group_id = 0, priv_id = 0, show_noti = 0, num = 1; + char *pkgname = NULL; + char *title = NULL; + char *str_count = NULL; + int i = 1; + char buf[512] = {0}; + + notification_get_list(NOTIFICATION_TYPE_NOTI, -1, ¬ification_list); + if (notification_list) { + get_list = notification_list_get_head(notification_list); + noti = notification_list_get_data(get_list); + while(get_list != NULL) { + notification_get_id(noti, &group_id, &priv_id); + notification_get_pkgname(noti, &pkgname); + if(pkgname == NULL){ + notification_get_application(noti, &pkgname); + } + + notification_get_text(noti, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, &str_count); + if (!str_count) { + count = 0; + } else { + count = atoi(str_count); + } + notification_get_title(noti, &title, NULL); + + fprintf(stdout, "NOTIFICATION: %s - %s - %i - %i\n", pkgname, title, count, num); + + get_list = notification_list_get_next(get_list); + noti = notification_list_get_data(get_list); + num++; + } + } + if (notification_list != NULL) { + notification_free_list(notification_list); + notification_list = NULL; + } +} + +int +main(int argc, char **argv) +{ + if (!ecore_init()) { + fprintf(stderr, "ERROR: Cannot init Ecore!\n"); + return -1; + } + + notification_resister_changed_cb(__noti_changed_cb, NULL); + ecore_main_loop_begin(); + + shutdown: + ecore_shutdown(); + return 0; +} + diff --git a/send_notification.c b/send_notification.c new file mode 100644 index 0000000..52e5686 --- /dev/null +++ b/send_notification.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include + +const char *error_to_string(notification_error_e error) +{ + if (error == NOTIFICATION_ERROR_INVALID_DATA) + return "NOTIFICATION_ERROR_INVALID_DATA"; + if (error == NOTIFICATION_ERROR_NO_MEMORY) + return "NOTIFICATION_ERROR_NO_MEMORY"; + if (error == NOTIFICATION_ERROR_FROM_DB) + return "NOTIFICATION_ERROR_FROM_DB"; + if (error == NOTIFICATION_ERROR_ALREADY_EXIST_ID) + return "NOTIFICATION_ERROR_ALREADY_EXIST_ID"; + if (error == NOTIFICATION_ERROR_FROM_DBUS) + return "NOTIFICATION_ERROR_FROM_DBUS"; + if (error == NOTIFICATION_ERROR_NOT_EXIST_ID) + return "NOTIFICATION_ERROR_NOT_EXIST_ID"; + if (error == NOTIFICATION_ERROR_IO) + return "NOTIFICATION_ERROR_IO"; + if (error == NOTIFICATION_ERROR_SERVICE_NOT_READY) + return "NOTIFICATION_ERROR_SERVICE_NOT_READY"; + if (error == NOTIFICATION_ERROR_NONE) + return "NOTIFICATION_ERROR_NONE"; + + return "UNHANDLED ERROR"; +} + +static Eina_Bool remove_all(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + const char *str, + void *data, + Ecore_Getopt_Value *storage) +{ + notification_error_e err = NOTIFICATION_ERROR_NONE; + + err = notification_delete_all_by_type("SEND_TEST_PKG", NOTIFICATION_TYPE_NOTI); + if (err != NOTIFICATION_ERROR_NONE) { + fprintf(stderr, "Unable to remove notifications: %s\n", error_to_string(err)); + exit(-1); + } + + exit(0); + + // will never reach here + return 0; +} + +static const Ecore_Getopt optdesc = { + "send notification test utility", + NULL, + "0.0", + "(C) 2013 Intel Corp", + "Flora", + "Test utility for sending notifications", + 0, + { + ECORE_GETOPT_STORE_STR('t', "title", "Title"), + ECORE_GETOPT_STORE_STR('c', "content", "Content"), + ECORE_GETOPT_STORE_STR('i', "icon", "Path to icon"), + ECORE_GETOPT_STORE_STR('m', "image", "Path to image"), + ECORE_GETOPT_STORE_INT('y', "imagetype", "Image type enum value"), + ECORE_GETOPT_CALLBACK_NOARGS('r', "removeall", "Remove all notifications", remove_all, NULL), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +int +main(int argc, char **argv) +{ + char *title = NULL; + char *content = NULL; + char *icon = NULL; + char *image = NULL; + int imageType = 0; + Eina_Bool remove = EINA_FALSE; + notification_h noti = NULL; + notification_error_e err = NOTIFICATION_ERROR_NONE; + + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_STR(title), + ECORE_GETOPT_VALUE_STR(content), + ECORE_GETOPT_VALUE_STR(icon), + ECORE_GETOPT_VALUE_STR(image), + ECORE_GETOPT_VALUE_INT(imageType), + ECORE_GETOPT_VALUE_NONE + }; + + if (!ecore_init()) { + fprintf(stderr, "ERROR: Cannot init Ecore!\n"); + return -1; + } + + if (ecore_getopt_parse(&optdesc, values, argc, argv) < 0) { + fprintf(stderr, "Parsing arguments failed!\n"); + return -1; + } + + noti = notification_new(NOTIFICATION_TYPE_NOTI, + NOTIFICATION_GROUP_ID_NONE, + NOTIFICATION_PRIV_ID_NONE); + if (noti == NULL) { + fprintf(stderr, "Failed to create notification: %s\n", error_to_string(err)); + return -1; + } + + err = notification_set_pkgname(noti, "SEND_TEST_PKG"); + if (err != NOTIFICATION_ERROR_NONE) { + fprintf(stderr, "Unable to set pkgname: %s\n", error_to_string(err)); + return -1; + } + + err = notification_set_text(noti, NOTIFICATION_TEXT_TYPE_TITLE, + title ? title : "Default Title", + NULL, NOTIFICATION_VARIABLE_TYPE_NONE); + if (err != NOTIFICATION_ERROR_NONE) { + fprintf(stderr, "Unable to set notification title: %s\n", error_to_string(err)); + return -1; + } + + err = notification_set_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT, + title ? title : "Default Content", + NULL, NOTIFICATION_VARIABLE_TYPE_NONE); + if (err != NOTIFICATION_ERROR_NONE) { + fprintf(stderr, "Unable to set notification content: %s\n", error_to_string(err)); + return -1; + } + + if (icon) { + err = notification_set_image(noti, NOTIFICATION_IMAGE_TYPE_ICON, icon); + if (err != NOTIFICATION_ERROR_NONE) { + fprintf(stderr, "Unable to set notification icon path: %s\n", error_to_string(err)); + return -1; + } + } + + if (image) { + err = notification_set_image(noti, imageType, image); + if (err != NOTIFICATION_ERROR_NONE) { + fprintf(stderr, "Unable to set notification image path: %s\n", error_to_string(err)); + return -1; + } + } + + err = notification_insert(noti, NULL); + if (err != NOTIFICATION_ERROR_NONE) { + fprintf(stderr, "Unable to insert notification: %s\n", error_to_string(err)); + return -1; + } + + fprintf(stdout, "Sent Notification > %s : %s : %s : %s : %i\n", + title, content, icon, image, imageType); + return 0; +} + -- 2.7.4 From a298f8726f54414abf7d1d4adde7e6d72902ded0 Mon Sep 17 00:00:00 2001 From: Rusty Lynch Date: Mon, 16 Sep 2013 14:09:50 -0700 Subject: [PATCH 04/14] Remove socket cleanup code Change-Id: I04d379037991c7e450d7905213b576e12108e08e --- service_common.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/service_common.c b/service_common.c index db79011..b53d1ff 100644 --- a/service_common.c +++ b/service_common.c @@ -575,18 +575,6 @@ struct service_context *service_common_create(const char *addr, int (*service_th return NULL; } - /* - * cleanup old socket file - */ - struct stat tmp; - if (!stat(addr, &tmp)) { - if (unlink(addr)) { - perror("Unable to unlink old socket file"); - free(svc_ctx); - return NULL; - } - } - svc_ctx->fd = secure_socket_create_server(addr); if (svc_ctx->fd < 0) { free(svc_ctx); -- 2.7.4 From 2427a9d9f63e72b5f9b8b1d4b236f441c5e9d872 Mon Sep 17 00:00:00 2001 From: Rusty Lynch Date: Mon, 16 Sep 2013 15:32:50 -0700 Subject: [PATCH 05/14] Update changelog for release Change-Id: Ief212257233fba462330ce3dd3a7db3c6564f4b4 --- packaging/notification-service.changes | 4 ++++ packaging/notification-service.spec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packaging/notification-service.changes b/packaging/notification-service.changes index b78ee49..0493d52 100644 --- a/packaging/notification-service.changes +++ b/packaging/notification-service.changes @@ -1,3 +1,7 @@ +* Mon Sep 16 2013 Rusty Lynch submit/tizen/20130906.193836@a298f87 +- Remove socket cleanup code +- Add unit test for sending and recieving notifications + * Fri Sep 06 2013 Rusty Lynch 3fb22fc - Initial import diff --git a/packaging/notification-service.spec b/packaging/notification-service.spec index d2e8b4d..8d629db 100644 --- a/packaging/notification-service.spec +++ b/packaging/notification-service.spec @@ -1,6 +1,6 @@ Name: notification-service Summary: Simple notification service -Version: 0.0.1 +Version: 0.0.2 Release: 1 Group: Application Framework/Notifications License: Flora -- 2.7.4 From 06d4a8e7425129958d7b05c6fa6f9965b94e16ec Mon Sep 17 00:00:00 2001 From: Jean-Benoit MARTIN Date: Fri, 20 Sep 2013 14:30:32 +0200 Subject: [PATCH 06/14] Send and display content from notification Change-Id: I609ec048f7ffe34104a0c4cdc2a2bedd2566601d --- sample_display_client.c | 5 ++++- send_notification.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sample_display_client.c b/sample_display_client.c index 1f449f0..ccdd255 100644 --- a/sample_display_client.c +++ b/sample_display_client.c @@ -11,6 +11,7 @@ static void __noti_changed_cb(void *data, notification_type_e type) char *pkgname = NULL; char *title = NULL; char *str_count = NULL; + char *content = NULL; int i = 1; char buf[512] = {0}; @@ -32,8 +33,10 @@ static void __noti_changed_cb(void *data, notification_type_e type) count = atoi(str_count); } notification_get_title(noti, &title, NULL); + notification_get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT, &content); - fprintf(stdout, "NOTIFICATION: %s - %s - %i - %i\n", pkgname, title, count, num); + + fprintf(stdout, "NOTIFICATION: %s - %s - %s - %i - %i\n", pkgname, title, content, count, num); get_list = notification_list_get_next(get_list); noti = notification_list_get_data(get_list); diff --git a/send_notification.c b/send_notification.c index 52e5686..0a15d86 100644 --- a/send_notification.c +++ b/send_notification.c @@ -121,7 +121,7 @@ main(int argc, char **argv) } err = notification_set_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT, - title ? title : "Default Content", + content ? content : "Default Content", NULL, NOTIFICATION_VARIABLE_TYPE_NONE); if (err != NOTIFICATION_ERROR_NONE) { fprintf(stderr, "Unable to set notification content: %s\n", error_to_string(err)); -- 2.7.4 From 179e82142574e8ce4f86479adf4eb7453306c39f Mon Sep 17 00:00:00 2001 From: Jean-Benoit MARTIN Date: Fri, 20 Sep 2013 14:17:26 +0200 Subject: [PATCH 07/14] Add Bluetooth-client-notification to test bluetooth pairing Change-Id: I1b079a270fe39ca04cb6774e97db19e21f7f9d25 --- Makefile.am | 6 +- bluetooth_notification_client.c | 327 ++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- packaging/notification-service.spec | 5 + 4 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 bluetooth_notification_client.c diff --git a/Makefile.am b/Makefile.am index 5b7257b..28b715c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -bin_PROGRAMS = notification-service sample-display-client send-notification +bin_PROGRAMS = notification-service sample-display-client send-notification bluetooth_notification_client AM_CFLAGS = $(GCC_CFLAGS) AM_CPPFLAGS = $(GCC_CFLAGS) @@ -18,6 +18,10 @@ sample_display_client_SOURCES = sample_display_client.c sample_display_client_CFLAGS = -I. $(TIZEN_CFLAGS) sample_display_client_LDADD = $(TIZEN_LIBS) +bluetooth_notification_client_SOURCES = bluetooth_notification_client.c +bluetooth_notification_client_CFLAGS = -I. $(TIZEN_CFLAGS) +bluetooth_notification_client_LDADD = $(TIZEN_LIBS) + SCRIPT_IN_FILES = \ notifications.service.in \ notifications.socket.in diff --git a/bluetooth_notification_client.c b/bluetooth_notification_client.c new file mode 100644 index 0000000..50a3095 --- /dev/null +++ b/bluetooth_notification_client.c @@ -0,0 +1,327 @@ +#include +#include +#include + +#include +#include +#include +#include + +typedef enum { + BT_AGENT_ACCEPT, + BT_AGENT_REJECT, + BT_AGENT_CANCEL, + BT_CORE_AGENT_TIMEOUT, +} bt_agent_accept_type_t; + + +typedef void (*bt_notification)(DBusGProxy *proxy); + +static DBusGProxy* +__bluetooth_create_agent_proxy(DBusGConnection *sys_conn, const char *path) +{ + return dbus_g_proxy_new_for_name (sys_conn, + "org.projectx.bt", + path, + "org.bluez.Agent"); +} + +static DBusGProxy* +__bluetooth_create_obex_proxy(DBusGConnection *sys_conn) +{ + return dbus_g_proxy_new_for_name(sys_conn, + "org.bluez.frwk_agent", + "/org/obex/ops_agent", + "org.openobex.Agent"); +} + +static void +__notify_passkey_confirm_request_accept_cb( DBusGProxy* agent_proxy) +{ + dbus_g_proxy_call_no_reply( agent_proxy, "ReplyConfirmation", + G_TYPE_UINT, BT_AGENT_ACCEPT, + G_TYPE_INVALID, G_TYPE_INVALID); + +} + +static void +__notify_passkey_confirm_request_cancel_cb(DBusGProxy* agent_proxy) +{ + + dbus_g_proxy_call_no_reply( agent_proxy, "ReplyConfirmation", + G_TYPE_UINT, BT_AGENT_CANCEL, + G_TYPE_INVALID, G_TYPE_INVALID); + +} + +static void +__notify_push_authorize_request_accept_cb(DBusGProxy* obex_proxy) +{ + + dbus_g_proxy_call_no_reply( obex_proxy, "ReplyAuthorize", + G_TYPE_UINT, BT_AGENT_ACCEPT, + G_TYPE_INVALID, G_TYPE_INVALID); + +} + +static void +__notify_push_authorize_request_cancel_cb(DBusGProxy* obex_proxy) +{ + + dbus_g_proxy_call_no_reply( obex_proxy, "ReplyAuthorize", + G_TYPE_UINT, BT_AGENT_CANCEL, + G_TYPE_INVALID, G_TYPE_INVALID); + +} + +static void +__notify_authorize_request_accept_cb(DBusGProxy* agent_proxy) +{ + + dbus_g_proxy_call_no_reply( agent_proxy, "ReplyAuthorize", + G_TYPE_UINT, BT_AGENT_ACCEPT, + G_TYPE_INVALID, G_TYPE_INVALID); +} + +static void +__notify_authorize_request_cancel_cb(DBusGProxy* agent_proxy) +{ + + dbus_g_proxy_call_no_reply( agent_proxy, "ReplyAuthorize", + G_TYPE_UINT, BT_AGENT_CANCEL, + G_TYPE_INVALID, G_TYPE_INVALID); + +} + +static int +__display_notification(bt_notification cb_1, bt_notification cb_2, DBusGProxy *proxy) +{ + + notification_error_e err = NOTIFICATION_ERROR_NONE; + int bt_yesno; + bt_yesno = 1; + char line[256]; + + fprintf(stdout, "Do you confirm yes or no ? "); + while ( bt_yesno != 0){ + gets(line); + if ( strcmp(line,"yes") == 0){ + (cb_1) (proxy); + bt_yesno = 0; + } else if ( strcmp(line,"no") == 0){ + (cb_2) (proxy); + bt_yesno = 0; + } else { + fprintf(stdout," yes or no :"); + } + } + err = notification_delete_all_by_type("bluetooth-frwk-bt-service", NOTIFICATION_TYPE_NOTI); + if (err != NOTIFICATION_ERROR_NONE) { + fprintf(stdout, "Unable to remove notifications"); + } + +} + +static int __noti_changed_cb(void *data, notification_type_e type) +{ + notification_h noti = NULL; + notification_list_h notification_list = NULL; + notification_list_h get_list = NULL; + int count = 0, group_id = 0, priv_id = 0, show_noti = 0, num = 1; + char *pkgname = NULL; + char *title = NULL; + char *str_count = NULL; + char *content= NULL; + bundle *user_data = NULL; + DBusGConnection *sys_conn; + DBusGProxy *agent_proxy; + DBusGProxy *obex_proxy; + + + const char *device_name = NULL; + const char *passkey = NULL; + const char *file = NULL; + const char *agent_path; + const char *event_type = NULL; + + notification_get_list(NOTIFICATION_TYPE_NOTI, -1, ¬ification_list); + if (notification_list) { + get_list = notification_list_get_head(notification_list); + noti = notification_list_get_data(get_list); + notification_get_id(noti, &group_id, &priv_id); + notification_get_pkgname(noti, &pkgname); + if(pkgname == NULL){ + notification_get_application(noti, &pkgname); + } + + notification_get_text(noti, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, &str_count); + if (!str_count) { + count = 0; + } else { + count = atoi(str_count); + } + notification_get_title(noti, &title, NULL); + notification_get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT , &content); + notification_get_execute_option(noti, NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH,NULL, &user_data); + + fprintf(stdout, "NOTIFICATION: %s - %s - %s - %i - %i \n", pkgname, title, content, count, num); + + event_type = bundle_get_val(user_data, "event-type"); + + if(!strcasecmp(event_type, "pin-request")) { + /* Not implemented */ + fprintf(stdout," Not implemented\n"); + + } else if (!strcasecmp(event_type, "passkey-confirm-request")){ + device_name = (gchar*) bundle_get_val(user_data, "device-name"); + passkey = (gchar*) bundle_get_val(user_data, "passkey"); + agent_path = bundle_get_val(user_data, "agent-path"); + + sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); + if (sys_conn == NULL) { + fprintf(stdout,"ERROR: Can't get on system bus"); + return EXIT_FAILURE; + } + + agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); + if (!agent_proxy){ + fprintf(stdout,"create new agent_proxy failed\n"); + return EXIT_FAILURE; + } + + __display_notification(__notify_passkey_confirm_request_accept_cb, __notify_passkey_confirm_request_cancel_cb,agent_proxy); + } else if (!strcasecmp(event_type, "passkey-request")) { + /* Not implemented */ + fprintf(stdout," Not implemented\n"); + + } else if (!strcasecmp(event_type, "passkey-display-request")) { + /* Not implemented */ + fprintf(stdout," Not implemented\n"); + + } else if (!strcasecmp(event_type, "authorize-request")) { + device_name = (gchar*) bundle_get_val(user_data, "device-name"); + agent_path = bundle_get_val(user_data, "agent-path"); + + sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); + if (sys_conn == NULL) { + fprintf(stdout,"ERROR: Can't get on system bus"); + return EXIT_FAILURE; + } + + agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); + if (!agent_proxy){ + fprintf(stdout,"create new agent_proxy failed\n"); + return EXIT_FAILURE; + } + + __display_notification( __notify_authorize_request_accept_cb, __notify_authorize_request_cancel_cb,agent_proxy); + } else if (!strcasecmp(event_type, "app-confirm-request")) { + /* Not implemented */ + fprintf(stdout," Not implemented\n"); + + } else if (!strcasecmp(event_type, "push-authorize-request")) { + file = (gchar*) bundle_get_val(user_data, "file"); + device_name = (gchar*) bundle_get_val(user_data, "device-name"); + + sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); + if (sys_conn == NULL) { + fprintf(stdout,"ERROR: Can't get on system bus"); + return EXIT_FAILURE; + } + + obex_proxy = __bluetooth_create_obex_proxy(sys_conn); + if (!obex_proxy){ + fprintf(stdout,"create new obex_proxy failed\n"); + return EXIT_FAILURE; + } + + __display_notification( __notify_push_authorize_request_accept_cb, __notify_push_authorize_request_cancel_cb,obex_proxy); + } else if (!strcasecmp(event_type, "confirm-overwrite-request")) { + /* Not implemented */ + fprintf(stdout," Not implemented\n"); + + } else if (!strcasecmp(event_type, "keyboard-passkey-request")) { + /* Not implemented */ + fprintf(stdout," Not implemented\n"); + + } else if (!strcasecmp(event_type, "bt-information")) { + /* Not implemented */ + fprintf(stdout," Not implemented\n"); + + } else if (!strcasecmp(event_type, "exchange-request")) { + device_name = (gchar*) bundle_get_val(user_data, "device-name"); + agent_path = bundle_get_val(user_data, "agent-path"); + + sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); + if (sys_conn == NULL) { + fprintf(stdout,"ERROR: Can't get on system bus"); + return EXIT_FAILURE; + } + + agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); + if (!agent_proxy){ + fprintf(stdout,"create new agent_proxy failed\n"); + return EXIT_FAILURE; + } + + __display_notification( __notify_authorize_request_accept_cb, __notify_authorize_request_cancel_cb,agent_proxy); + } else if (!strcasecmp(event_type, "phonebook-request")) { + device_name = bundle_get_val(user_data, "device-name"); + agent_path = bundle_get_val(user_data, "agent-path"); + + sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); + if (sys_conn == NULL) { + fprintf(stdout,"ERROR: Can't get on system bus"); + return EXIT_FAILURE; + } + + agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); + if (!agent_proxy){ + fprintf(stdout,"create new agent_proxy failed\n"); + return EXIT_FAILURE; + } + + __display_notification( __notify_authorize_request_accept_cb, __notify_authorize_request_cancel_cb,agent_proxy); + } else if (!strcasecmp(event_type, "message-request")) { + device_name = bundle_get_val(user_data, "device-name"); + agent_path = bundle_get_val(user_data, "agent-path"); + + sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); + if (sys_conn == NULL) { + fprintf(stdout,"ERROR: Can't get on system bus"); + return EXIT_FAILURE; + } + + agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); + if (!agent_proxy){ + fprintf(stdout,"create new agent_proxy failed\n"); + return EXIT_FAILURE; + } + + __display_notification( __notify_authorize_request_accept_cb, __notify_authorize_request_cancel_cb,agent_proxy); + } + } + if (notification_list != NULL) { + notification_free_list(notification_list); + notification_list = NULL; + } + + return EXIT_SUCCESS; +} + +int +main(int argc, char **argv) +{ + if (!ecore_init()) { + fprintf(stderr, "ERROR: Cannot init Ecore!\n"); + return -1; + } + + notification_resister_changed_cb(__noti_changed_cb, NULL); + ecore_main_loop_begin(); + + shutdown: + ecore_shutdown(); + return 0; +} + diff --git a/configure.ac b/configure.ac index 394cdfe..56dec67 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ LT_PREREQ([2.2]) LT_INIT([disable-static]) PKG_PROG_PKG_CONFIG() -PKG_CHECK_MODULES([TIZEN], [eina ecore com-core notification]) +PKG_CHECK_MODULES([TIZEN], [eina ecore com-core notification dbus-1 bluetooth-api]) AC_SUBST(TIZEN_CFLAGS) AC_SUBST(TIZEN_LIBS) diff --git a/packaging/notification-service.spec b/packaging/notification-service.spec index 8d629db..f1657e8 100644 --- a/packaging/notification-service.spec +++ b/packaging/notification-service.spec @@ -9,6 +9,10 @@ BuildRequires: pkgconfig(eina) BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(com-core) BuildRequires: pkgconfig(notification) +BuildRequires: dbus-devel +BuildRequires: pkgconfig(dbus-glib-1) +BuildRequires: bluetooth-frwk-devel +BuildRequires: bundle-devel %description Headless notification service that collects incoming notifications from the @@ -45,3 +49,4 @@ rm -rf %{buildroot} %defattr(-,root,root,-) %{_bindir}/sample-display-client %{_bindir}/send-notification +%{_bindir}/bluetooth_notification_client -- 2.7.4 From 9a127c22d26a2c7524f4491c008b07c4a8add6cd Mon Sep 17 00:00:00 2001 From: Rusty Lynch Date: Fri, 20 Sep 2013 11:22:39 -0700 Subject: [PATCH 08/14] Update changelog for release Change-Id: I21f247ec57cfab000a870cf63abe6ec489bff8c5 --- packaging/notification-service.changes | 4 ++++ packaging/notification-service.spec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packaging/notification-service.changes b/packaging/notification-service.changes index 0493d52..01b10c1 100644 --- a/packaging/notification-service.changes +++ b/packaging/notification-service.changes @@ -1,3 +1,7 @@ +* Fri Sep 20 2013 Rusty Lynch accepted/tizen/20130917.000007@6b2a8d7 +- Add Bluetooth-client-notification to test bluetooth pairing +- Send and display content from notification + * Mon Sep 16 2013 Rusty Lynch submit/tizen/20130906.193836@a298f87 - Remove socket cleanup code - Add unit test for sending and recieving notifications diff --git a/packaging/notification-service.spec b/packaging/notification-service.spec index f1657e8..e48dfa8 100644 --- a/packaging/notification-service.spec +++ b/packaging/notification-service.spec @@ -1,6 +1,6 @@ Name: notification-service Summary: Simple notification service -Version: 0.0.2 +Version: 0.0.3 Release: 1 Group: Application Framework/Notifications License: Flora -- 2.7.4 From 81d8b0c9e8437729b0838433673a4fc1c792f613 Mon Sep 17 00:00:00 2001 From: Rusty Lynch Date: Thu, 24 Oct 2013 12:58:59 -0700 Subject: [PATCH 09/14] Fix build warnings - Stop using deprecated gets - Fix prototype for notification callback Change-Id: I56b088c461d04bf26ae568ce9074e0b680e57847 Signed-off-by: Rusty Lynch --- bluetooth_notification_client.c | 33 +++++++++++++++++---------------- packaging/notification-service.changes | 4 ++++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/bluetooth_notification_client.c b/bluetooth_notification_client.c index 50a3095..2ccd5ad 100644 --- a/bluetooth_notification_client.c +++ b/bluetooth_notification_client.c @@ -100,11 +100,12 @@ __display_notification(bt_notification cb_1, bt_notification cb_2, DBusGProxy *p notification_error_e err = NOTIFICATION_ERROR_NONE; int bt_yesno; bt_yesno = 1; - char line[256]; + char line[4]; fprintf(stdout, "Do you confirm yes or no ? "); while ( bt_yesno != 0){ - gets(line); + if (!fgets(line, sizeof(line), stdin)) + continue; if ( strcmp(line,"yes") == 0){ (cb_1) (proxy); bt_yesno = 0; @@ -122,7 +123,7 @@ __display_notification(bt_notification cb_1, bt_notification cb_2, DBusGProxy *p } -static int __noti_changed_cb(void *data, notification_type_e type) +static void __noti_changed_cb(void *data, notification_type_e type) { notification_h noti = NULL; notification_list_h notification_list = NULL; @@ -180,13 +181,13 @@ static int __noti_changed_cb(void *data, notification_type_e type) sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); if (sys_conn == NULL) { fprintf(stdout,"ERROR: Can't get on system bus"); - return EXIT_FAILURE; + return; } agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); if (!agent_proxy){ fprintf(stdout,"create new agent_proxy failed\n"); - return EXIT_FAILURE; + return; } __display_notification(__notify_passkey_confirm_request_accept_cb, __notify_passkey_confirm_request_cancel_cb,agent_proxy); @@ -205,13 +206,13 @@ static int __noti_changed_cb(void *data, notification_type_e type) sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); if (sys_conn == NULL) { fprintf(stdout,"ERROR: Can't get on system bus"); - return EXIT_FAILURE; + return; } agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); if (!agent_proxy){ fprintf(stdout,"create new agent_proxy failed\n"); - return EXIT_FAILURE; + return; } __display_notification( __notify_authorize_request_accept_cb, __notify_authorize_request_cancel_cb,agent_proxy); @@ -226,13 +227,13 @@ static int __noti_changed_cb(void *data, notification_type_e type) sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); if (sys_conn == NULL) { fprintf(stdout,"ERROR: Can't get on system bus"); - return EXIT_FAILURE; + return; } obex_proxy = __bluetooth_create_obex_proxy(sys_conn); if (!obex_proxy){ fprintf(stdout,"create new obex_proxy failed\n"); - return EXIT_FAILURE; + return; } __display_notification( __notify_push_authorize_request_accept_cb, __notify_push_authorize_request_cancel_cb,obex_proxy); @@ -255,13 +256,13 @@ static int __noti_changed_cb(void *data, notification_type_e type) sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); if (sys_conn == NULL) { fprintf(stdout,"ERROR: Can't get on system bus"); - return EXIT_FAILURE; + return; } agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); if (!agent_proxy){ fprintf(stdout,"create new agent_proxy failed\n"); - return EXIT_FAILURE; + return; } __display_notification( __notify_authorize_request_accept_cb, __notify_authorize_request_cancel_cb,agent_proxy); @@ -272,13 +273,13 @@ static int __noti_changed_cb(void *data, notification_type_e type) sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); if (sys_conn == NULL) { fprintf(stdout,"ERROR: Can't get on system bus"); - return EXIT_FAILURE; + return; } agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); if (!agent_proxy){ fprintf(stdout,"create new agent_proxy failed\n"); - return EXIT_FAILURE; + return; } __display_notification( __notify_authorize_request_accept_cb, __notify_authorize_request_cancel_cb,agent_proxy); @@ -289,13 +290,13 @@ static int __noti_changed_cb(void *data, notification_type_e type) sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); if (sys_conn == NULL) { fprintf(stdout,"ERROR: Can't get on system bus"); - return EXIT_FAILURE; + return; } agent_proxy = __bluetooth_create_agent_proxy(sys_conn, agent_path); if (!agent_proxy){ fprintf(stdout,"create new agent_proxy failed\n"); - return EXIT_FAILURE; + return; } __display_notification( __notify_authorize_request_accept_cb, __notify_authorize_request_cancel_cb,agent_proxy); @@ -306,7 +307,7 @@ static int __noti_changed_cb(void *data, notification_type_e type) notification_list = NULL; } - return EXIT_SUCCESS; + return; } int diff --git a/packaging/notification-service.changes b/packaging/notification-service.changes index 01b10c1..27d4d6b 100644 --- a/packaging/notification-service.changes +++ b/packaging/notification-service.changes @@ -1,3 +1,7 @@ +* Thu Oct 24 2013 Rusty Lynch accepted/tizen/20130920.213625@237321e +- Fix build warnings by no longer using 'gets' and fixing the + prototype for notification callback + * Fri Sep 20 2013 Rusty Lynch accepted/tizen/20130917.000007@6b2a8d7 - Add Bluetooth-client-notification to test bluetooth pairing - Send and display content from notification -- 2.7.4 From 42929a10a04bfe1b91648fad8d12bb6a57ca9364 Mon Sep 17 00:00:00 2001 From: Corentin Lecouvey Date: Thu, 16 Jan 2014 15:28:45 +0100 Subject: [PATCH 10/14] Do not use systemd socket mechanism Notifications daemon discusses with its clients using secure sockets. Secure sockets are not adapted to systemd socket. Now notifications daemon is started at boot time. Change-Id: If6ee8164df1d1db18b973da62d5b066d06c44524 Signed-off-by: Corentin Lecouvey --- Makefile.am | 8 ++------ configure.ac | 2 +- notifications.service.in | 6 ++++++ packaging/notification-service.spec | 25 ++++++++++++++++--------- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Makefile.am b/Makefile.am index 28b715c..60a8844 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,12 +23,8 @@ bluetooth_notification_client_CFLAGS = -I. $(TIZEN_CFLAGS) bluetooth_notification_client_LDADD = $(TIZEN_LIBS) SCRIPT_IN_FILES = \ - notifications.service.in \ - notifications.socket.in + notifications.service.in install-data-hook: - $(mkinstalldirs) $(DESTDIR)/usr/lib/systemd/system/sockets.target.wants + $(mkinstalldirs) $(DESTDIR)/usr/lib/systemd/system/ install -m 0644 notifications.service $(DESTDIR)/usr/lib/systemd/system/notifications.service - install -m 0644 notifications.socket $(DESTDIR)/usr/lib/systemd/system/notifications.socket - ln -fs ../notifications.socket $(DESTDIR)/usr/lib/systemd/system/sockets.target.wants/notifications.socket - diff --git a/configure.ac b/configure.ac index 56dec67..9f7eae1 100644 --- a/configure.ac +++ b/configure.ac @@ -14,6 +14,6 @@ PKG_CHECK_MODULES([TIZEN], [eina ecore com-core notification dbus-1 bluetooth-ap AC_SUBST(TIZEN_CFLAGS) AC_SUBST(TIZEN_LIBS) -AC_CONFIG_FILES([Makefile notifications.service notifications.socket]) +AC_CONFIG_FILES([Makefile notifications.service]) AC_PROG_RANLIB([ranlib]) AC_OUTPUT diff --git a/notifications.service.in b/notifications.service.in index 47db370..ebbd62c 100644 --- a/notifications.service.in +++ b/notifications.service.in @@ -1,2 +1,8 @@ +[Unit] +Description=Notifications daemon + [Service] ExecStart=/usr/bin/notification-service + +[Install] +WantedBy=graphical.target diff --git a/packaging/notification-service.spec b/packaging/notification-service.spec index e48dfa8..ecea933 100644 --- a/packaging/notification-service.spec +++ b/packaging/notification-service.spec @@ -9,10 +9,11 @@ BuildRequires: pkgconfig(eina) BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(com-core) BuildRequires: pkgconfig(notification) -BuildRequires: dbus-devel +BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(dbus-glib-1) -BuildRequires: bluetooth-frwk-devel -BuildRequires: bundle-devel +BuildRequires: pkgconfig(bluetooth-api) +BuildRequires: pkgconfig(bundle) +%{?systemd_requires} %description Headless notification service that collects incoming notifications from the @@ -28,22 +29,28 @@ This package provides unit test used in the development of the notification serv %prep %setup -q -n %{name}-%{version} -%define PREFIX %{_prefix}/apps/ - %build %autogen make %{?_smp_mflags} %install -rm -rf %{buildroot} %make_install +%install_service graphical.target.wants notifications.service + +%post +%systemd_post notifications.service + +%preun +%systemd_preun notifications.service + +%postun +%systemd_postun notifications.service %files %defattr(-,root,root,-) %{_bindir}/notification-service -%{_libdir}/systemd/system/notifications.service -%{_libdir}/systemd/system/notifications.socket -%{_libdir}/systemd/system/sockets.target.wants/notifications.socket +%{_unitdir}/notifications.service +%{_unitdir}/graphical.target.wants/notifications.service %files test %defattr(-,root,root,-) -- 2.7.4 From 800d8f5c481bda3fd05868f575a9b945e726a2eb Mon Sep 17 00:00:00 2001 From: Corentin Lecouvey Date: Thu, 16 Jan 2014 15:42:04 +0100 Subject: [PATCH 11/14] adapt agent dbus interface to BlueZ 5 in test program Change-Id: Ic17652f6d5dda394c168f892b2452305648f663b Signed-off-by: Corentin Lecouvey --- bluetooth_notification_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bluetooth_notification_client.c b/bluetooth_notification_client.c index 2ccd5ad..ffe475e 100644 --- a/bluetooth_notification_client.c +++ b/bluetooth_notification_client.c @@ -23,7 +23,7 @@ __bluetooth_create_agent_proxy(DBusGConnection *sys_conn, const char *path) return dbus_g_proxy_new_for_name (sys_conn, "org.projectx.bt", path, - "org.bluez.Agent"); + "org.bluez.Agent1"); } static DBusGProxy* -- 2.7.4 From 97d87d6956ae90d7bc9988480028cc8d5e647652 Mon Sep 17 00:00:00 2001 From: Stephane Desneux Date: Thu, 22 May 2014 00:44:36 +0200 Subject: [PATCH 12/14] Fix build dependency (notification-service-devel) Commit 38b527f on platform/core/api/notification splitted notification API in two packages. Dependency on notification-service-devel was added. Change-Id: I40cbfd36281275fd89ab4daf671e406db9fb8a49 Signed-off-by: Stephane Desneux --- notification_service.c | 4 ++-- packaging/notification-service.spec | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/notification_service.c b/notification_service.c index 93e8d52..569de48 100644 --- a/notification_service.c +++ b/notification_service.c @@ -16,8 +16,8 @@ #include #include #include -#include -#include +#include +#include #include #include "service_common.h" diff --git a/packaging/notification-service.spec b/packaging/notification-service.spec index ecea933..33aad4f 100644 --- a/packaging/notification-service.spec +++ b/packaging/notification-service.spec @@ -5,10 +5,11 @@ Release: 1 Group: Application Framework/Notifications License: Flora Source0: %{name}-%{version}.tar.bz2 -BuildRequires: pkgconfig(eina) -BuildRequires: pkgconfig(ecore) -BuildRequires: pkgconfig(com-core) +BuildRequires: pkgconfig(eina) +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(com-core) BuildRequires: pkgconfig(notification) +BuildRequires: pkgconfig(notification-service) BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(dbus-glib-1) BuildRequires: pkgconfig(bluetooth-api) -- 2.7.4 From 81c3bdc85bb1ca835b41a95c1bca0eef8ac89a86 Mon Sep 17 00:00:00 2001 From: Manuel Bachmann Date: Fri, 29 Aug 2014 10:35:50 +0200 Subject: [PATCH 13/14] send-notification: do not send a notification when using "--help" Change-Id: I5d0b339e0c7e1dca644839d3e5e2061393687c7b Signed-off-by: Manuel Bachmann --- send_notification.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/send_notification.c b/send_notification.c index 0a15d86..a42b9dd 100644 --- a/send_notification.c +++ b/send_notification.c @@ -75,6 +75,7 @@ main(int argc, char **argv) char *icon = NULL; char *image = NULL; int imageType = 0; + Eina_Bool quit = EINA_FALSE; Eina_Bool remove = EINA_FALSE; notification_h noti = NULL; notification_error_e err = NOTIFICATION_ERROR_NONE; @@ -85,7 +86,8 @@ main(int argc, char **argv) ECORE_GETOPT_VALUE_STR(icon), ECORE_GETOPT_VALUE_STR(image), ECORE_GETOPT_VALUE_INT(imageType), - ECORE_GETOPT_VALUE_NONE + ECORE_GETOPT_VALUE_NONE, + ECORE_GETOPT_VALUE_BOOL(quit) }; if (!ecore_init()) { @@ -98,6 +100,9 @@ main(int argc, char **argv) return -1; } + if (quit) + return 0; + noti = notification_new(NOTIFICATION_TYPE_NOTI, NOTIFICATION_GROUP_ID_NONE, NOTIFICATION_PRIV_ID_NONE); -- 2.7.4 From a6677f7ec1ca22e265d02e7d2f2418bd08f7d033 Mon Sep 17 00:00:00 2001 From: Corentin Lecouvey Date: Fri, 29 Aug 2014 14:10:00 +0200 Subject: [PATCH 14/14] bluetooth_notification_client: activate GUI notifications Add a dependency on libwlmessage, which will be used by blueooth_notification_client to display popup messages on both Wayland and X11. dlog some of the error messages. Change-Id: Ic85de8aad4f20f080c6776ded5dd2237b6364271 Signed-off-by: Manuel Bachmann Author: Manuel Bachmann Author: Corentin Lecouvey --- bluetooth_notification_client.c | 42 ++++++++++++++++++++++++++++++------- configure.ac | 2 +- packaging/notification-service.spec | 4 ++++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/bluetooth_notification_client.c b/bluetooth_notification_client.c index ffe475e..bffaecd 100644 --- a/bluetooth_notification_client.c +++ b/bluetooth_notification_client.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include typedef enum { BT_AGENT_ACCEPT, @@ -98,27 +100,46 @@ __display_notification(bt_notification cb_1, bt_notification cb_2, DBusGProxy *p { notification_error_e err = NOTIFICATION_ERROR_NONE; - int bt_yesno; - bt_yesno = 1; + int bt_yesno = 1; char line[4]; + struct wlmessage *wlmessage = wlmessage_create(); + wlmessage_set_message(wlmessage, "Do you confirm ?"); + wlmessage_add_button(wlmessage, 1, "Yes"); + wlmessage_add_button(wlmessage, 0, "No"); + wlmessage_set_default_button(wlmessage, 1); + bt_yesno = wlmessage_show(wlmessage, NULL); + wlmessage_destroy(wlmessage); + + if (bt_yesno == 1) { + LOGD("user accepts to pair with device "); + (cb_1) (proxy); + } else if (bt_yesno == 0) { + LOGD("user rejects to pair with device "); + (cb_2) (proxy); + } + +#if 0 fprintf(stdout, "Do you confirm yes or no ? "); while ( bt_yesno != 0){ if (!fgets(line, sizeof(line), stdin)) continue; - if ( strcmp(line,"yes") == 0){ + if (strncmp("yes", line, 3) == 0) { + LOGD("user accepts to pair with device "); (cb_1) (proxy); bt_yesno = 0; - } else if ( strcmp(line,"no") == 0){ + } else if (strncmp("no", line, 2) == 0) { + LOGD("user rejects to pair with device "); (cb_2) (proxy); bt_yesno = 0; } else { - fprintf(stdout," yes or no :"); + fprintf(stdout," yes or no ?\n"); } } +#endif err = notification_delete_all_by_type("bluetooth-frwk-bt-service", NOTIFICATION_TYPE_NOTI); if (err != NOTIFICATION_ERROR_NONE) { - fprintf(stdout, "Unable to remove notifications"); + LOGE("Unable to remove notifications"); } } @@ -169,6 +190,11 @@ static void __noti_changed_cb(void *data, notification_type_e type) event_type = bundle_get_val(user_data, "event-type"); + if (!event_type) { + LOGD("Not a bluetooth-related notification..."); + return; + } + if(!strcasecmp(event_type, "pin-request")) { /* Not implemented */ fprintf(stdout," Not implemented\n"); @@ -314,7 +340,7 @@ int main(int argc, char **argv) { if (!ecore_init()) { - fprintf(stderr, "ERROR: Cannot init Ecore!\n"); + LOGE("ERROR: Cannot init Ecore!\n"); return -1; } @@ -323,6 +349,6 @@ main(int argc, char **argv) shutdown: ecore_shutdown(); - return 0; + return 1; } diff --git a/configure.ac b/configure.ac index 9f7eae1..194baa9 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ LT_PREREQ([2.2]) LT_INIT([disable-static]) PKG_PROG_PKG_CONFIG() -PKG_CHECK_MODULES([TIZEN], [eina ecore com-core notification dbus-1 bluetooth-api]) +PKG_CHECK_MODULES([TIZEN], [eina ecore com-core notification dbus-1 bluetooth-api dlog libwlmessage]) AC_SUBST(TIZEN_CFLAGS) AC_SUBST(TIZEN_LIBS) diff --git a/packaging/notification-service.spec b/packaging/notification-service.spec index 33aad4f..8772d1e 100644 --- a/packaging/notification-service.spec +++ b/packaging/notification-service.spec @@ -1,3 +1,5 @@ +%bcond_with wayland + Name: notification-service Summary: Simple notification service Version: 0.0.3 @@ -13,7 +15,9 @@ BuildRequires: pkgconfig(notification-service) BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(dbus-glib-1) BuildRequires: pkgconfig(bluetooth-api) +BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(libwlmessage) %{?systemd_requires} %description -- 2.7.4