d93ff8208af29cd5d0840bfd38287744dcb33e8d
[platform/core/convergence/service-adaptor.git] / adaptor / push-adaptor / push-adaptor.c
1 /*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <dirent.h>
21 #include <dlfcn.h>
22
23 #include "push-adaptor.h"
24 #include "push-adaptor-log.h"
25
26 /**
27  * Push adaptor plugin
28  */
29 typedef struct push_adaptor_plugin_s {
30         push_adaptor_h                  adaptor;                /* Adaptor */
31         char                            *path;                  /* Plugin library path */
32         push_adaptor_plugin_handle_h    handle;                 /* Plugin handle */
33         void                            *dl_handle;             /* Plugin library handle */
34         int                             ref_counter;            /* Plugin reference counter */
35         GMutex                          ref_counter_mutex;      /* Plugin reference counter mutex */
36         push_adaptor_plugin_listener_h  plugin_listener;        /* Plugin callback listener */
37         GMutex                          plugin_listener_mutex;  /* Plugin callback listener mutex */
38 } push_adaptor_plugin_t;
39
40 /**
41  * Push adaptor
42  */
43 typedef struct push_adaptor_s {
44         GMutex  push_adaptor_mutex;             /* Adaptor mutex */
45         int     started;                        /* Started flag */
46         char    *plugins_dir;                   /* Plugins directory path */
47         GList   *plugins;                       /* List of loaded plugins */
48         GMutex  plugins_mutex;                  /* Plugin list mutex */
49         GList   *adaptor_listeners;             /* List of vservice channel listener (for now not effective) */
50         GMutex  adaptor_listeners_mutex;        /* Listener list mutex */
51 } push_adaptor_t;
52
53 /**
54  * Creates plugin
55  */
56 static push_adaptor_plugin_h push_adaptor_create_plugin(const char *plugin_path);
57
58 /**
59  * Destroys plugin and deletes all resources associated with it
60  */
61 static void push_adaptor_destroy_plugin(push_adaptor_plugin_h plugin);
62
63 /**
64  * Loads plugins from selected directory
65  */
66 static int push_adaptor_load_plugins_from_directory(push_adaptor_h adaptor, const char *dir_path);
67
68 /**
69  * Checks if plugin is loaded by selected plugin adaptor
70  */
71 static int push_adaptor_has_plugin(push_adaptor_h adaptor, push_adaptor_plugin_h plugin);
72
73 /**
74  * Increases adaptor's plugin references counter
75  */
76 static void push_adaptor_plugin_ref(push_adaptor_plugin_h);
77
78 /**
79  * Decreases adaptor's plugin references counter
80  */
81 static void push_adaptor_plugin_unref(push_adaptor_plugin_h);
82
83 /**
84  * On notification received callback for service adaptor
85  */
86 push_adaptor_service_on_notification_received_cb _service_adaptor_on_notification_received = NULL;
87
88 /**
89  * Called on push notification received from plugin
90  */
91 void
92 push_adaptor_on_notification_received(push_adaptor_notification_data_h notification, void *user_data)
93 {
94         push_adaptor_info("[Push MSG]: %s", notification->msg);
95
96         if (NULL != _service_adaptor_on_notification_received) {
97                 _service_adaptor_on_notification_received(notification, user_data);
98         }
99 }
100
101 /* //////////////////////////////////////////////////////
102    // Mandatory: Internal adaptor management function
103    ////////////////////////////////////////////////////// */
104
105 /**
106  * Creates plugin
107  */
108 static push_adaptor_plugin_h push_adaptor_create_plugin(const char *plugin_path)
109 {
110         push_adaptor_debug("Create plugin");
111
112         if (NULL == plugin_path) {
113                 push_adaptor_error("Invalid argument");
114                 return NULL;
115         }
116
117         void *dl_handle = dlopen(plugin_path, RTLD_LAZY);
118         if (NULL == dl_handle) {
119                 push_adaptor_error("Could not load plugin %s: %s", plugin_path, dlerror());
120                 return NULL;
121         }
122
123         push_adaptor_plugin_handle_h (*get_adaptee_handle)(void) = NULL;
124
125         get_adaptee_handle = (push_adaptor_plugin_handle_h (*)(void))(dlsym(dl_handle, "create_plugin_handle"));
126         if (NULL == get_adaptee_handle) {
127                 dlclose(dl_handle);
128                 push_adaptor_error("Could not get function pointer to create_plugin_handle");
129                 return NULL;
130         }
131
132         plugin_req_enter();
133         push_adaptor_plugin_handle_h handle = get_adaptee_handle();
134         plugin_req_exit_void();
135
136         if (NULL == handle) {
137                 dlclose(dl_handle);
138                 push_adaptor_error("Could not get adaptee handle");
139                 return NULL;
140         }
141
142         push_adaptor_plugin_h plugin = (push_adaptor_plugin_h) calloc(1, sizeof(push_adaptor_plugin_t));
143         if (NULL == plugin) {
144                 dlclose(dl_handle);
145                 push_adaptor_error("Could not create plugin object");
146                 return NULL;
147         }
148
149         push_adaptor_plugin_listener_h listener =
150                 (push_adaptor_plugin_listener_h) calloc(1, sizeof(push_adaptor_plugin_listener_t));
151         if (NULL == listener) {
152                 free(plugin);
153                 dlclose(dl_handle);
154                 push_adaptor_error("Could not create listener object");
155                 return NULL;
156         }
157
158         plugin->path = g_strdup(plugin_path);
159         plugin->handle = handle;
160         plugin->dl_handle = dl_handle;
161         plugin->ref_counter = 0;
162
163         g_mutex_init(&plugin->ref_counter_mutex);
164         g_mutex_init(&plugin->plugin_listener_mutex);
165
166         listener->_on_notification_received = push_adaptor_on_notification_received;
167
168         plugin_req_enter();
169         plugin->handle->set_listener(listener);
170         plugin_req_exit_void();
171
172         g_mutex_lock(&plugin->plugin_listener_mutex);
173         plugin->plugin_listener = listener;
174         g_mutex_unlock(&plugin->plugin_listener_mutex);
175
176         return plugin;
177 }
178
179 /**
180  * Destroys plugin and deletes all resources associated with it
181  */
182 static void push_adaptor_destroy_plugin(push_adaptor_plugin_h plugin)
183 {
184         push_adaptor_debug("Destroy plugin");
185
186         if (NULL == plugin) {
187                 push_adaptor_error("Invalid argument");
188                 return;
189         }
190
191         if (NULL != plugin->handle) {
192                 plugin->handle->destroy_handle(plugin->handle);
193
194                 g_mutex_lock(&plugin->plugin_listener_mutex);
195                 plugin_req_enter();
196                 plugin->handle->unset_listener();
197                 plugin_req_exit_void();
198                 g_mutex_unlock(&plugin->plugin_listener_mutex);
199
200                 plugin->handle = NULL;
201         }
202
203         if (NULL != plugin->dl_handle) {
204                 dlclose(plugin->dl_handle);
205                 plugin->dl_handle = NULL;
206         }
207
208         free(plugin->path);
209         plugin->path = NULL;
210
211         free(plugin);
212 }
213
214 /**
215  * Loads plugins from selected directory
216  */
217 static int push_adaptor_load_plugins_from_directory(push_adaptor_h adaptor, const char *dir_path)
218 {
219         push_adaptor_debug("Load plugins from directory");
220
221         char *plugin_path = NULL;
222         DIR *dir = NULL;
223         struct dirent dir_entry, *result = NULL;
224
225         if ((NULL == adaptor) || (NULL == dir_path)) {
226                 push_adaptor_error("Invalid argument");
227                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
228         }
229
230         dir = opendir(dir_path);
231         if (NULL == dir) {
232                 push_adaptor_error("Could not open dir path (%s)", dir_path);
233                 return PUSH_ADAPTOR_ERROR_NOT_FOUND;
234         }
235
236         int ret = PUSH_ADAPTOR_ERROR_NONE;
237         while (0 == (readdir_r(dir, &dir_entry, &result))) {
238
239                 if (NULL == result) {
240                         push_adaptor_error("Could not open directory %s", plugin_path);
241                         break;
242                 }
243
244                 if (dir_entry.d_type & DT_DIR) {
245                         continue;
246                 }
247
248                 plugin_path = g_strconcat(dir_path, "/", dir_entry.d_name, NULL);
249                 push_adaptor_plugin_h plugin = push_adaptor_create_plugin(plugin_path);
250
251                 if (NULL != plugin) {
252                         push_adaptor_debug("Loaded plugin: %s", plugin_path);
253                         plugin->adaptor = adaptor;
254                         push_adaptor_plugin_ref(plugin);
255                         g_mutex_lock(&adaptor->plugins_mutex);
256                         adaptor->plugins = g_list_append(adaptor->plugins, plugin);
257                         g_mutex_unlock(&adaptor->plugins_mutex);
258                 } else {
259                         push_adaptor_error("Could not load plugin %s", plugin_path);
260                 }
261
262                 free(plugin_path);
263                 plugin_path = NULL;
264         }
265
266         push_adaptor_debug("End load plugins from directory");
267         closedir(dir);
268         return ret;
269 }
270
271 /**
272  * Checks if plugin is loaded by selected plugin adaptor
273  */
274 static int push_adaptor_has_plugin(push_adaptor_h adaptor, push_adaptor_plugin_h plugin)
275 {
276         push_adaptor_debug("Find plugin in plugin list");
277
278         if ((NULL == adaptor) || (NULL == plugin)) {
279                 push_adaptor_error("Invalid argument");
280                 return 0;
281         }
282
283         int result = 0;
284
285         g_mutex_lock(&adaptor->plugins_mutex);
286         if (NULL != g_list_find(adaptor->plugins, plugin)) {
287                 result = 1;
288         }
289         g_mutex_unlock(&adaptor->plugins_mutex);
290
291         return result;
292 }
293
294 /**
295  * Increases adaptor's plugin references counter
296  */
297 static void push_adaptor_plugin_ref(push_adaptor_plugin_h plugin)
298 {
299         push_adaptor_debug("Increase plugin reference count");
300
301         if (NULL == plugin) {
302                 push_adaptor_error("Invalid argument");
303                 return;
304         }
305
306         g_mutex_lock(&plugin->ref_counter_mutex);
307         plugin->ref_counter = plugin->ref_counter + 1;
308         push_adaptor_info("ref_counter: %d", plugin->ref_counter);
309         g_mutex_unlock(&plugin->ref_counter_mutex);
310 }
311
312 /**
313  * Decreases adaptor's plugin references counter
314  */
315 static void push_adaptor_plugin_unref(push_adaptor_plugin_h plugin)
316 {
317         push_adaptor_debug("Decrease plugin reference count");
318
319         if (NULL == plugin) {
320                 push_adaptor_error("Invalid argument");
321                 return ;
322         }
323
324         int should_destroy = 0;
325
326         g_mutex_lock(&plugin->ref_counter_mutex);
327         plugin->ref_counter = plugin->ref_counter - 1;
328         push_adaptor_info("ref_counter: %d", plugin->ref_counter);
329         if (0 >= plugin->ref_counter) {
330                 should_destroy = 1;
331         }
332         g_mutex_unlock(&plugin->ref_counter_mutex);
333
334         if (should_destroy) {
335                 push_adaptor_debug("Plugin is being destroyed");
336                 push_adaptor_destroy_plugin(plugin);
337         }
338 }
339
340 /* //////////////////////////////////////////////////////
341    // Mandatory: External adaptor management function
342    ////////////////////////////////////////////////////// */
343
344 /**
345 * @brief Creates Push Adaptor
346 *
347 * @param[in]    plugin_dir      specifies directory path where plugins are stored
348 * @return       push_adaptor_h on success, otherwise NULL value
349 */
350 push_adaptor_h push_adaptor_create(const char *plugins_dir)
351 {
352         push_adaptor_warning("Create push adaptor");
353
354         push_adaptor_h push_adaptor = (push_adaptor_h) malloc(sizeof(push_adaptor_t));
355         if (NULL == push_adaptor) {
356                 return NULL;
357         }
358
359         push_adaptor->started = 0;
360         push_adaptor->plugins_dir = strdup(plugins_dir);
361
362         g_mutex_init(&push_adaptor->push_adaptor_mutex);
363         g_mutex_init(&push_adaptor->plugins_mutex);
364         g_mutex_init(&push_adaptor->adaptor_listeners_mutex);
365
366         g_mutex_lock(&push_adaptor->adaptor_listeners_mutex);
367         push_adaptor->adaptor_listeners = NULL;
368         g_mutex_unlock(&push_adaptor->adaptor_listeners_mutex);
369
370         g_mutex_lock(&push_adaptor->plugins_mutex);
371         push_adaptor->plugins = NULL;
372         g_mutex_unlock(&push_adaptor->plugins_mutex);
373
374         return push_adaptor;
375 }
376
377 /**
378 * @brief Destroys push adaptor. If push adaptor was started it is stopped first.
379 *
380 * @param[in]    adaptor         specifies push adaptor handle to be destroyed
381 * @return       void
382 */
383 void push_adaptor_destroy(push_adaptor_h adaptor)
384 {
385         push_adaptor_warning("Destroy push adaptor");
386         if (NULL == adaptor) {
387                 push_adaptor_error("Invalid argument");
388                 return ;
389         }
390
391         g_mutex_lock(&adaptor->push_adaptor_mutex);
392         if (adaptor->started) {
393                 push_adaptor_error("Push adaptor is running. Forcing stop before destroy");
394                 push_adaptor_stop(adaptor);
395         }
396
397         g_mutex_lock(&adaptor->plugins_mutex);
398         if (NULL != adaptor->plugins) {
399                 g_list_free_full(adaptor->plugins, (GDestroyNotify) push_adaptor_plugin_unref);
400                 adaptor->plugins = NULL;
401         }
402         g_mutex_unlock(&adaptor->plugins_mutex);
403
404         g_mutex_lock(&adaptor->adaptor_listeners_mutex);
405         if (NULL != adaptor->adaptor_listeners) {
406                 g_list_free(adaptor->adaptor_listeners);
407                 adaptor->adaptor_listeners = NULL;
408         }
409         g_mutex_unlock(&adaptor->adaptor_listeners_mutex);
410
411         _service_adaptor_on_notification_received = NULL;
412
413         free(adaptor->plugins_dir);
414         adaptor->plugins_dir = NULL;
415
416         g_mutex_unlock(&adaptor->push_adaptor_mutex);
417
418         free(adaptor);
419 }
420
421 /**
422 * @brief Starts push adaptor and loads plugins that were found in plugins search dir
423 * specified in push_adaptor_create
424 *
425 * @param[in]    adaptor         specifies push adaptor handle
426 * @return       0 on success, otherwise a positive error value
427 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
428 */
429 int push_adaptor_start(push_adaptor_h adaptor)
430 {
431         push_adaptor_warning("Start push adaptor");
432         if (NULL == adaptor) {
433                 push_adaptor_error("Invalid argument");
434                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
435         }
436
437         g_mutex_lock(&adaptor->push_adaptor_mutex);
438         int result = PUSH_ADAPTOR_ERROR_NONE;
439         if (adaptor->started) {
440                 push_adaptor_error("Push adaptor is already started");
441                 result = PUSH_ADAPTOR_ERROR_START;
442         } else {
443                 adaptor->started = 1;
444                 result = push_adaptor_load_plugins_from_directory(adaptor, adaptor->plugins_dir);
445                 if (PUSH_ADAPTOR_ERROR_NONE != result) {
446                         adaptor->started = 0;
447                         push_adaptor_error("Could not load plugins from directory");
448                 } else {
449                         push_adaptor_debug("Push adaptor started successfully");
450                 }
451         }
452         g_mutex_unlock(&adaptor->push_adaptor_mutex);
453
454         return result;
455 }
456
457 /**
458 * @brief Stops push adaptor
459 *
460 * @param[in]    adaptor         specifies push adaptor handle
461 * @return       0 on success, otherwise a positive error value
462 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
463 */
464 int push_adaptor_stop(push_adaptor_h adaptor)
465 {
466         push_adaptor_warning("Stop contact adaptor");
467
468         if (NULL == adaptor) {
469                 push_adaptor_error("Invalid argument");
470                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
471         }
472
473         g_mutex_lock(&adaptor->push_adaptor_mutex);
474         int result = PUSH_ADAPTOR_ERROR_NONE;
475         if (!adaptor->started) {
476                 result = PUSH_ADAPTOR_ERROR_START;
477         } else {
478                 if (NULL != adaptor->plugins) {
479                         g_mutex_lock(&adaptor->plugins_mutex);
480                         g_list_free_full(adaptor->plugins, (GDestroyNotify) push_adaptor_plugin_unref);
481                         adaptor->plugins = NULL;
482                         g_mutex_unlock(&adaptor->plugins_mutex);
483                 }
484                 adaptor->started = 0;
485                 push_adaptor_debug("Push adaptor stopped");
486         }
487
488         g_mutex_unlock(&adaptor->push_adaptor_mutex);
489         return result;
490 }
491
492 /**
493 * @brief Registers plugin state listener
494 *
495 * @param[in]    adaptor         specifies push adaptor handle
496 * @param[in]    listener        specifies push adaptor listener handle
497 * @return       0 on success, otherwise a positive error value
498 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
499 */
500 int push_adaptor_register_listener(push_adaptor_h adaptor, push_adaptor_listener_h listener)
501 {
502         push_adaptor_warning("Register push adaptor listener");
503
504         if ((NULL == adaptor) || (NULL == listener)) {
505                 push_adaptor_error("Invalid argument");
506                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
507         }
508
509         g_mutex_lock(&adaptor->adaptor_listeners_mutex);
510         adaptor->adaptor_listeners = g_list_append(adaptor->adaptor_listeners, listener);
511
512         g_mutex_unlock(&adaptor->adaptor_listeners_mutex);
513
514         _service_adaptor_on_notification_received =
515                         (push_adaptor_service_on_notification_received_cb) listener->_on_notification_received;
516
517         return PUSH_ADAPTOR_ERROR_NONE;
518 }
519
520 /**
521 * @brief Unregisters plugin state listener
522 *
523 * @param[in]    adaptor         specifies push adaptor handle
524 * @param[in]    listener        specifies push adaptor listener handle
525 * @return       0 on success, otherwise a positive error value
526 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
527 */
528 int push_adaptor_unregister_listener(push_adaptor_h adaptor, push_adaptor_listener_h listener)
529 {
530         push_adaptor_warning("Unregister push adaptor listener");
531
532         if ((NULL == adaptor) || (NULL == listener)) {
533                 push_adaptor_error("Invalid argument");
534                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
535         }
536
537         g_mutex_lock(&adaptor->adaptor_listeners_mutex);
538
539         if (NULL == g_list_find(adaptor->adaptor_listeners, listener)) {
540                 g_mutex_unlock(&adaptor->adaptor_listeners_mutex);
541                 push_adaptor_error("Could not find listener");
542                 free(listener);
543                 return PUSH_ADAPTOR_ERROR_NOT_FOUND;
544         }
545
546         adaptor->adaptor_listeners = g_list_remove(adaptor->adaptor_listeners, listener);
547         free(listener);
548
549         g_mutex_unlock(&adaptor->adaptor_listeners_mutex);
550
551         _service_adaptor_on_notification_received = NULL;
552
553         return PUSH_ADAPTOR_ERROR_NONE;
554 }
555
556 /* //////////////////////////////////////////////////////
557    // Create / Destroy error code
558    ////////////////////////////////////////////////////// */
559
560 /**
561 * @brief Create error code
562 *
563 * @param[in]    code            specifies error code number
564 * @param[in]    msg             specifies error message
565 * @return       push_adaptor_error_code_h on success, otherwise NULL value
566 */
567 push_adaptor_error_code_h push_adaptor_create_error_code(const int64_t code, const char *msg)
568 {
569         if (NULL == msg) {
570                 return NULL;
571         }
572
573         push_adaptor_error_code_h error_code =
574                 (push_adaptor_error_code_h) malloc(sizeof(push_adaptor_error_code_t));
575         if (NULL == error_code) {
576                 return NULL;
577         }
578
579         error_code->code = code;
580         error_code->msg = strdup(msg);
581
582         return error_code;
583 }
584
585 /**
586 * @brief Destroy error code
587 *
588 * @param[in]    error_code      specifies error code handle
589 * @return       void
590 */
591 void push_adaptor_destroy_error_code(push_adaptor_error_code_h *error_code)
592 {
593         if (NULL == *error_code) {
594                 return;
595         }
596
597         if (NULL != (*error_code)->msg) {
598                 free((*error_code)->msg);
599                 (*error_code)->msg = NULL;
600         }
601
602         free(*error_code);
603         *error_code = NULL;
604 }
605
606 /* //////////////////////////////////////////////////////
607    // Plugin context create / destroy
608    ////////////////////////////////////////////////////// */
609 /**
610 * @brief Creates plugin context
611 *
612 * @param[in]    plugin          specifies push adaptor plugin handle
613 * @param[in]    push_app_id     specifies push service application ID
614 * @return       push_adaptor_plugin_context_h on success, otherwise NULL value
615 */
616 push_adaptor_plugin_context_h push_adaptor_create_plugin_context(push_adaptor_plugin_h plugin,
617                                                 const char *plugin_uri,
618                                                 const char *push_app_id)
619 {
620         push_adaptor_warning("Create plugin context");
621
622         if (NULL == plugin) {
623                 push_adaptor_error("Invalid argument");
624                 return NULL;
625         }
626
627         if (NULL != plugin->handle) {
628                 push_adaptor_plugin_context_h plugin_context = NULL;
629
630                 plugin_req_enter();
631                 plugin->handle->create_context(&plugin_context, push_app_id);
632                 plugin_req_exit_void();
633
634                 if (NULL != plugin_context) {
635                         plugin_context->plugin_uri = strdup(plugin->handle->plugin_uri);
636                         plugin_context->state = PUSH_ADAPTOR_STATE_DISCONNECTED;
637                 }
638                 return plugin_context;
639         } else {
640                 push_adaptor_error("Plugin handle is null");
641         }
642
643         return NULL;
644 }
645
646 /**
647 * @brief Destroys plugin context
648 *
649 * @param[in]    plugin          specifies push adaptor plugin handle
650 * @param[in]    context         specifies push adaptor plugin context handle
651 * @return       void
652 */
653 void push_adaptor_destroy_plugin_context(push_adaptor_plugin_h plugin,
654                                                 push_adaptor_plugin_context_h plugin_context)
655 {
656         push_adaptor_warning("Destroy plugin context");
657
658         if ((NULL == plugin) || (NULL == plugin_context)) {
659                 push_adaptor_error("Invalid argument");
660                 return;
661         }
662
663         if (NULL != plugin->handle) {
664                 plugin_req_enter();
665                 plugin->handle->destroy_context(plugin_context);
666                 plugin_req_exit_void();
667         } else {
668                 push_adaptor_error("Plugin handle is null");
669         }
670 }
671
672 /* //////////////////////////////////////////////////////
673    // Get plugin by plugin name
674    ////////////////////////////////////////////////////// */
675
676 /**
677 * @brief Gets plugin with specified unique name
678 *
679 * @param[in]    adaptor         specifies push adaptor handle
680 * @param[in]    plugin_name     specifies plugin name to be searched for
681 * @return       push_adaptor_plugin_h on success, otherwise NULL value
682 */
683 push_adaptor_plugin_h push_adaptor_get_plugin_by_name(push_adaptor_h adaptor,
684                                                 const char *plugin_name)
685 {
686         push_adaptor_warning("Get plugin by name: %s", plugin_name);
687
688         if ((NULL == adaptor) || (NULL == plugin_name)) {
689                 push_adaptor_error("Invalid argument");
690                 return NULL;
691         }
692
693         push_adaptor_plugin_h plugin = NULL;
694         g_mutex_lock(&adaptor->plugins_mutex);
695         int count = g_list_length(adaptor->plugins);
696         int i = 0;
697         for (i = 0; i < count; i++) {
698                 push_adaptor_plugin_h temp_plugin = g_list_nth_data(adaptor->plugins, i);
699                 if (NULL != temp_plugin) {
700                         if (0 == strcmp(temp_plugin->handle->plugin_uri, plugin_name)) {
701                                 push_adaptor_plugin_ref(temp_plugin);
702                                 plugin = temp_plugin;
703                                 push_adaptor_debug("Plugin is found by name");
704                                 break;
705                         }
706                 }
707         }
708         g_mutex_unlock(&adaptor->plugins_mutex);
709
710         if (NULL == plugin)
711                 push_adaptor_debug("Plugin is not found by name");
712
713         return plugin;
714 }
715
716 /* //////////////////////////////////////////////////////
717    // Plugin load / unload / get plugin list
718    ////////////////////////////////////////////////////// */
719
720 /**
721 * @brief Loads plugin from selected path
722 *
723 * @param[in]    adaptor         specifies push adaptor handle
724 * @param[in]    plugin_path     specifies plugin's saved path
725 * @return       0 on success, otherwise a positive error value
726 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
727 */
728 int push_adaptor_load_plugin(push_adaptor_h adaptor,
729                                                 const char *plugin_path)
730 {
731         push_adaptor_warning("Load plugin by plugin path: %s", plugin_path);
732
733         if ((NULL == adaptor) || (NULL == plugin_path)) {
734                 push_adaptor_error("Invalid argument");
735                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
736         }
737
738         if (!adaptor->started) {
739                 push_adaptor_error("Push adaptor is not started");
740                 return PUSH_ADAPTOR_ERROR_START;
741         }
742
743         push_adaptor_plugin_h plugin = push_adaptor_create_plugin(plugin_path);
744         if (NULL == plugin) {
745                 push_adaptor_error("Could not load plugin %s", plugin_path);
746                 return PUSH_ADAPTOR_ERROR_CREATE;
747         }
748
749         plugin->adaptor = adaptor;
750         push_adaptor_plugin_ref(plugin);
751
752         g_mutex_lock(&adaptor->plugins_mutex);
753         adaptor->plugins = g_list_append(adaptor->plugins, plugin);
754         g_mutex_unlock(&adaptor->plugins_mutex);
755
756         return PUSH_ADAPTOR_ERROR_NONE;
757 }
758
759 /**
760 * @brief Unloads selected plugin
761 *
762 * @param[in]    adaptor         specifies push adaptor handle
763 * @param[in]    plugin          specifies push adaptor plugin handle
764 * @return       0 on success, otherwise a positive error value
765 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
766 */
767 int push_adaptor_unload_plugin(push_adaptor_h adaptor,
768                                                 push_adaptor_plugin_h plugin)
769 {
770         push_adaptor_warning("Unload plugin");
771
772         if ((NULL == adaptor) || (NULL == plugin)) {
773                 push_adaptor_error("Invalid argument");
774                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
775         }
776
777         if (!adaptor->started) {
778                 push_adaptor_error("Push adaptor is not started");
779                 return PUSH_ADAPTOR_ERROR_START;
780         }
781
782         if (!push_adaptor_has_plugin(adaptor, plugin)) {
783                 push_adaptor_error("Push adaptor has no plugin");
784                 return PUSH_ADAPTOR_ERROR_NOT_FOUND;
785         }
786
787         plugin->adaptor = NULL;
788
789         g_mutex_lock(&adaptor->plugins_mutex);
790         adaptor->plugins = g_list_remove(adaptor->plugins, plugin);
791         g_mutex_unlock(&adaptor->plugins_mutex);
792
793         push_adaptor_plugin_unref(plugin);
794
795         return PUSH_ADAPTOR_ERROR_NONE;
796 }
797
798 /**
799 * @brief Get plugin list
800 *
801 * @param[in]    adaptor         specifies push adaptor handle
802 * @return       GList pointer on success, otherwise NULL value
803 */
804 GList *push_adaptor_get_plugins(push_adaptor_h adaptor)
805 {
806         push_adaptor_warning("Get plugin list");
807
808         if (NULL == adaptor) {
809                 push_adaptor_error("Invalid argument");
810                 return NULL;
811         }
812
813         GList *plugins = NULL;
814
815         g_mutex_lock(&adaptor->plugins_mutex);
816         int plugins_count = g_list_length(adaptor->plugins);
817         int i;
818         for (i = 0; i < plugins_count; i++) {
819                 push_adaptor_plugin_h plugin = g_list_nth_data(adaptor->plugins, i);
820                 if (NULL != plugin) {
821                         push_adaptor_plugin_ref(plugin);
822                         plugins = g_list_append(plugins, plugin);
823                 }
824         }
825         g_mutex_unlock(&adaptor->plugins_mutex);
826
827         return plugins;
828 }
829
830 /* //////////////////////////////////////////////////////
831    // External Push Adaptor APIs
832    ////////////////////////////////////////////////////// */
833
834 /**
835 * @brief Set server information for Push Plugin
836 *
837 * @param[in]    plugin         specifies Push Adaptor Plugin handle
838 * @param[in]    context        specifies Push Adaptor Plugin Context handle
839 * @param[in]    server_info    specifies server information for Push Plugin
840 * @param[out]   error          specifies error code
841 * @return 0 on success, otherwise a positive error value
842 * @retval error code defined in push_error_code_t - PUSH_ADAPTOR_ERROR_NONE if Successful
843 */
844 EXPORT_API
845 push_error_code_t push_adaptor_set_server_info(push_adaptor_plugin_h plugin,
846                                                 push_adaptor_plugin_context_h context,
847                                                 GHashTable *server_info,
848                                                 push_adaptor_error_code_h *error_code)
849 {
850         if ((NULL == plugin) || (NULL == context)) {
851                 push_adaptor_error("Invalid argument");
852
853                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT,
854                                                                 "Invalid argument (plugin or context)");
855
856                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
857         }
858
859         if (NULL == plugin->handle) {
860                 push_adaptor_error("Plugin handle is null");
861
862                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_HANDLE,
863                                                                 "Plugin handle is null");
864
865                 return PUSH_ADAPTOR_ERROR_INVALID_HANDLE;
866         }
867
868 /*      *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_NONE, */
869 /*                                                    "Push adaptor error none"); */
870         push_error_code_t ret;
871         plugin_req_enter();
872         ret = plugin->handle->set_server_info(context, server_info);
873         plugin_req_exit(ret, plugin, error_code);
874
875         return ret;
876 }
877
878 /**
879 * @brief Connects to push service with Push App ID handed over when creates plugin context
880 *
881 * @param[in]    plugin          specifies push adaptor plugin handle
882 * @param[in]    context         specifies push adaptor plugin context handle
883 * @param[out]   error           specifies error code
884 * @return       0 on success, otherwise a positive error value
885 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
886 */
887 push_error_code_t push_adaptor_connect(push_adaptor_plugin_h plugin,
888                                                 push_adaptor_plugin_context_h context,
889                                                 push_adaptor_error_code_h *error_code)
890 {
891         push_adaptor_warning("Connect to push adaptor");
892
893         if ((NULL == plugin) || (NULL == context)) {
894                 push_adaptor_error("Invalid argument");
895
896                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT,
897                                                                 "Invalid argument (plugin or context)");
898
899                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
900         }
901
902         if (NULL == plugin->handle) {
903                 push_adaptor_error("Plugin handle is null");
904
905                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_HANDLE,
906                                                                 "Plugin handle is null");
907
908                 return PUSH_ADAPTOR_ERROR_INVALID_HANDLE;
909         }
910
911 /*      *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_NONE, */
912 /*                                                      "Push adaptor error none"); */
913
914         push_error_code_t ret;
915         plugin_req_enter();
916         ret = plugin->handle->connect(context);
917         plugin_req_exit(ret, plugin, error_code);
918
919         return ret;
920 }
921
922 /**
923 * @brief Disconnects from push service with Push App ID handed over when creates plugin context
924 *
925 * @param[in]    plugin          specifies push adaptor plugin handle
926 * @param[in]    context         specifies push adaptor plugin context handle
927 * @param[out]   error           specifies error code
928 * @return       0 on success, otherwise a positive error value
929 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
930 */
931 push_error_code_t push_adaptor_disconnect(push_adaptor_plugin_h plugin,
932                                                 push_adaptor_plugin_context_h context,
933                                                 push_adaptor_error_code_h *error_code)
934 {
935         push_adaptor_warning("Disconnect from push adaptor");
936
937         if ((NULL == plugin) || (NULL == context)) {
938                 push_adaptor_error("Invalid argument");
939
940                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT,
941                                                                 "Invalid argument (plugin or context)");
942
943                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
944         }
945
946         if (NULL == plugin->handle) {
947                 push_adaptor_error("Plugin handle is null");
948
949                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_HANDLE,
950                                                                 "Plugin handle is null");
951
952                 return PUSH_ADAPTOR_ERROR_INVALID_HANDLE;
953         }
954
955 /*      *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_NONE, */
956 /*                                                      "Push adaptor error none"); */
957
958         push_error_code_t ret;
959         plugin_req_enter();
960         ret = plugin->handle->disconnect(context);
961         plugin_req_exit(ret, plugin, error_code);
962
963         return ret;
964 }
965
966 EXPORT_API
967 push_error_code_t push_adaptor_is_connected(push_adaptor_plugin_h plugin,
968                                                 push_adaptor_plugin_context_h context,
969                                                 int *is_connected)
970 {
971         push_adaptor_info("Check push connection");
972
973         if ((NULL == context) || (NULL == is_connected)) {
974                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
975         }
976
977         *is_connected = context->state;
978
979         return PUSH_ADAPTOR_ERROR_NONE;
980 }
981
982 /**
983 * @brief Asynchronous request to get unread notifications
984 *
985 * @param[in]    plugin          specifies push adaptor plugin handle
986 * @param[in]    context         specifies push adaptor plugin context handle
987 * @param[out]   error           specifies error code
988 * @return       0 on success, otherwise a positive error value
989 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
990 */
991 push_error_code_t push_adaptor_request_unread_notification(push_adaptor_plugin_h plugin,
992                                                 push_adaptor_plugin_context_h context,
993                                                 push_adaptor_error_code_h *error_code)
994 {
995         push_adaptor_warning("Request unread notification");
996
997         if ((NULL == plugin) || (NULL == context)) {
998                 push_adaptor_error("Invalid argument");
999
1000                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT,
1001                                                                 "Invalid argument (plugin or context)");
1002
1003                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
1004         }
1005
1006         if (NULL == plugin->handle) {
1007                 push_adaptor_error("Plugin handle is null");
1008
1009                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_HANDLE,
1010                                                                 "Plugin handle is null");
1011
1012                 return PUSH_ADAPTOR_ERROR_INVALID_HANDLE;
1013         }
1014
1015 /*      *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_NONE, */
1016 /*                                                      "Push adaptor error none"); */
1017
1018         push_error_code_t ret;
1019         plugin_req_enter();
1020         ret = plugin->handle->request_unread_notification(context);
1021         plugin_req_exit(ret, plugin, error_code);
1022
1023         return ret;
1024 }