Fixed svace issue
[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)  {
533                 push_adaptor_error("Invalid argument (adaptor)");
534                 if (NULL != listener) {
535                         free(listener);
536                         listener = NULL;
537                 }
538                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
539         }
540         if (NULL == listener) {
541                 push_adaptor_error("Invalid argument (listener)");
542                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
543         }
544
545         g_mutex_lock(&adaptor->adaptor_listeners_mutex);
546
547         if (NULL == g_list_find(adaptor->adaptor_listeners, listener)) {
548                 g_mutex_unlock(&adaptor->adaptor_listeners_mutex);
549                 push_adaptor_error("Could not find listener");
550                 free(listener);
551                 return PUSH_ADAPTOR_ERROR_NOT_FOUND;
552         }
553
554         adaptor->adaptor_listeners = g_list_remove(adaptor->adaptor_listeners, listener);
555         free(listener);
556
557         g_mutex_unlock(&adaptor->adaptor_listeners_mutex);
558
559         _service_adaptor_on_notification_received = NULL;
560
561         return PUSH_ADAPTOR_ERROR_NONE;
562 }
563
564 /* //////////////////////////////////////////////////////
565    // Create / Destroy error code
566    ////////////////////////////////////////////////////// */
567
568 /**
569 * @brief Create error code
570 *
571 * @param[in]    code            specifies error code number
572 * @param[in]    msg             specifies error message
573 * @return       push_adaptor_error_code_h on success, otherwise NULL value
574 */
575 push_adaptor_error_code_h push_adaptor_create_error_code(const int64_t code, const char *msg)
576 {
577         if (NULL == msg) {
578                 return NULL;
579         }
580
581         push_adaptor_error_code_h error_code =
582                 (push_adaptor_error_code_h) malloc(sizeof(push_adaptor_error_code_t));
583         if (NULL == error_code) {
584                 return NULL;
585         }
586
587         error_code->code = code;
588         error_code->msg = strdup(msg);
589
590         return error_code;
591 }
592
593 /**
594 * @brief Destroy error code
595 *
596 * @param[in]    error_code      specifies error code handle
597 * @return       void
598 */
599 void push_adaptor_destroy_error_code(push_adaptor_error_code_h *error_code)
600 {
601         if (NULL == *error_code) {
602                 return;
603         }
604
605         if (NULL != (*error_code)->msg) {
606                 free((*error_code)->msg);
607                 (*error_code)->msg = NULL;
608         }
609
610         free(*error_code);
611         *error_code = NULL;
612 }
613
614 /* //////////////////////////////////////////////////////
615    // Plugin context create / destroy
616    ////////////////////////////////////////////////////// */
617 /**
618 * @brief Creates plugin context
619 *
620 * @param[in]    plugin          specifies push adaptor plugin handle
621 * @param[in]    push_app_id     specifies push service application ID
622 * @return       push_adaptor_plugin_context_h on success, otherwise NULL value
623 */
624 push_adaptor_plugin_context_h push_adaptor_create_plugin_context(push_adaptor_plugin_h plugin,
625                                                 const char *plugin_uri,
626                                                 const char *push_app_id)
627 {
628         push_adaptor_warning("Create plugin context");
629
630         if (NULL == plugin) {
631                 push_adaptor_error("Invalid argument");
632                 return NULL;
633         }
634
635         if (NULL != plugin->handle) {
636                 push_adaptor_plugin_context_h plugin_context = NULL;
637
638                 plugin_req_enter();
639                 plugin->handle->create_context(&plugin_context, push_app_id);
640                 plugin_req_exit_void();
641
642                 if (NULL != plugin_context) {
643                         plugin_context->plugin_uri = strdup(plugin->handle->plugin_uri);
644                         plugin_context->state = PUSH_ADAPTOR_STATE_DISCONNECTED;
645                 }
646                 return plugin_context;
647         } else {
648                 push_adaptor_error("Plugin handle is null");
649         }
650
651         return NULL;
652 }
653
654 /**
655 * @brief Destroys plugin context
656 *
657 * @param[in]    plugin          specifies push adaptor plugin handle
658 * @param[in]    context         specifies push adaptor plugin context handle
659 * @return       void
660 */
661 void push_adaptor_destroy_plugin_context(push_adaptor_plugin_h plugin,
662                                                 push_adaptor_plugin_context_h plugin_context)
663 {
664         push_adaptor_warning("Destroy plugin context");
665
666         if ((NULL == plugin) || (NULL == plugin_context)) {
667                 push_adaptor_error("Invalid argument");
668                 return;
669         }
670
671         if (NULL != plugin->handle) {
672                 plugin_req_enter();
673                 plugin->handle->destroy_context(plugin_context);
674                 plugin_req_exit_void();
675         } else {
676                 push_adaptor_error("Plugin handle is null");
677         }
678 }
679
680 /* //////////////////////////////////////////////////////
681    // Get plugin by plugin name
682    ////////////////////////////////////////////////////// */
683
684 /**
685 * @brief Gets plugin with specified unique name
686 *
687 * @param[in]    adaptor         specifies push adaptor handle
688 * @param[in]    plugin_name     specifies plugin name to be searched for
689 * @return       push_adaptor_plugin_h on success, otherwise NULL value
690 */
691 push_adaptor_plugin_h push_adaptor_get_plugin_by_name(push_adaptor_h adaptor,
692                                                 const char *plugin_name)
693 {
694         push_adaptor_warning("Get plugin by name: %s", plugin_name);
695
696         if ((NULL == adaptor) || (NULL == plugin_name)) {
697                 push_adaptor_error("Invalid argument");
698                 return NULL;
699         }
700
701         push_adaptor_plugin_h plugin = NULL;
702         g_mutex_lock(&adaptor->plugins_mutex);
703         int count = g_list_length(adaptor->plugins);
704         int i = 0;
705         for (i = 0; i < count; i++) {
706                 push_adaptor_plugin_h temp_plugin = g_list_nth_data(adaptor->plugins, i);
707                 if (NULL != temp_plugin) {
708                         if (0 == strcmp(temp_plugin->handle->plugin_uri, plugin_name)) {
709                                 push_adaptor_plugin_ref(temp_plugin);
710                                 plugin = temp_plugin;
711                                 push_adaptor_debug("Plugin is found by name");
712                                 break;
713                         }
714                 }
715         }
716         g_mutex_unlock(&adaptor->plugins_mutex);
717
718         if (NULL == plugin)
719                 push_adaptor_debug("Plugin is not found by name");
720
721         return plugin;
722 }
723
724 /* //////////////////////////////////////////////////////
725    // Plugin load / unload / get plugin list
726    ////////////////////////////////////////////////////// */
727
728 /**
729 * @brief Loads plugin from selected path
730 *
731 * @param[in]    adaptor         specifies push adaptor handle
732 * @param[in]    plugin_path     specifies plugin's saved path
733 * @return       0 on success, otherwise a positive error value
734 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
735 */
736 int push_adaptor_load_plugin(push_adaptor_h adaptor,
737                                                 const char *plugin_path)
738 {
739         push_adaptor_warning("Load plugin by plugin path: %s", plugin_path);
740
741         if ((NULL == adaptor) || (NULL == plugin_path)) {
742                 push_adaptor_error("Invalid argument");
743                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
744         }
745
746         if (!adaptor->started) {
747                 push_adaptor_error("Push adaptor is not started");
748                 return PUSH_ADAPTOR_ERROR_START;
749         }
750
751         push_adaptor_plugin_h plugin = push_adaptor_create_plugin(plugin_path);
752         if (NULL == plugin) {
753                 push_adaptor_error("Could not load plugin %s", plugin_path);
754                 return PUSH_ADAPTOR_ERROR_CREATE;
755         }
756
757         plugin->adaptor = adaptor;
758         push_adaptor_plugin_ref(plugin);
759
760         g_mutex_lock(&adaptor->plugins_mutex);
761         adaptor->plugins = g_list_append(adaptor->plugins, plugin);
762         g_mutex_unlock(&adaptor->plugins_mutex);
763
764         return PUSH_ADAPTOR_ERROR_NONE;
765 }
766
767 /**
768 * @brief Unloads selected plugin
769 *
770 * @param[in]    adaptor         specifies push adaptor handle
771 * @param[in]    plugin          specifies push adaptor plugin handle
772 * @return       0 on success, otherwise a positive error value
773 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
774 */
775 int push_adaptor_unload_plugin(push_adaptor_h adaptor,
776                                                 push_adaptor_plugin_h plugin)
777 {
778         push_adaptor_warning("Unload plugin");
779
780         if ((NULL == adaptor) || (NULL == plugin)) {
781                 push_adaptor_error("Invalid argument");
782                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
783         }
784
785         if (!adaptor->started) {
786                 push_adaptor_error("Push adaptor is not started");
787                 return PUSH_ADAPTOR_ERROR_START;
788         }
789
790         if (!push_adaptor_has_plugin(adaptor, plugin)) {
791                 push_adaptor_error("Push adaptor has no plugin");
792                 return PUSH_ADAPTOR_ERROR_NOT_FOUND;
793         }
794
795         plugin->adaptor = NULL;
796
797         g_mutex_lock(&adaptor->plugins_mutex);
798         adaptor->plugins = g_list_remove(adaptor->plugins, plugin);
799         g_mutex_unlock(&adaptor->plugins_mutex);
800
801         push_adaptor_plugin_unref(plugin);
802
803         return PUSH_ADAPTOR_ERROR_NONE;
804 }
805
806 /**
807 * @brief Get plugin list
808 *
809 * @param[in]    adaptor         specifies push adaptor handle
810 * @return       GList pointer on success, otherwise NULL value
811 */
812 GList *push_adaptor_get_plugins(push_adaptor_h adaptor)
813 {
814         push_adaptor_warning("Get plugin list");
815
816         if (NULL == adaptor) {
817                 push_adaptor_error("Invalid argument");
818                 return NULL;
819         }
820
821         GList *plugins = NULL;
822
823         g_mutex_lock(&adaptor->plugins_mutex);
824         int plugins_count = g_list_length(adaptor->plugins);
825         int i;
826         for (i = 0; i < plugins_count; i++) {
827                 push_adaptor_plugin_h plugin = g_list_nth_data(adaptor->plugins, i);
828                 if (NULL != plugin) {
829                         push_adaptor_plugin_ref(plugin);
830                         plugins = g_list_append(plugins, plugin);
831                 }
832         }
833         g_mutex_unlock(&adaptor->plugins_mutex);
834
835         return plugins;
836 }
837
838 /* //////////////////////////////////////////////////////
839    // External Push Adaptor APIs
840    ////////////////////////////////////////////////////// */
841
842 /**
843 * @brief Set server information for Push Plugin
844 *
845 * @param[in]    plugin         specifies Push Adaptor Plugin handle
846 * @param[in]    context        specifies Push Adaptor Plugin Context handle
847 * @param[in]    server_info    specifies server information for Push Plugin
848 * @param[out]   error          specifies error code
849 * @return 0 on success, otherwise a positive error value
850 * @retval error code defined in push_error_code_t - PUSH_ADAPTOR_ERROR_NONE if Successful
851 */
852 EXPORT_API
853 push_error_code_t push_adaptor_set_server_info(push_adaptor_plugin_h plugin,
854                                                 push_adaptor_plugin_context_h context,
855                                                 GHashTable *server_info,
856                                                 push_adaptor_error_code_h *error_code)
857 {
858         if ((NULL == plugin) || (NULL == context)) {
859                 push_adaptor_error("Invalid argument");
860
861                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT,
862                                                                 "Invalid argument (plugin or context)");
863
864                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
865         }
866
867         if (NULL == plugin->handle) {
868                 push_adaptor_error("Plugin handle is null");
869
870                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_HANDLE,
871                                                                 "Plugin handle is null");
872
873                 return PUSH_ADAPTOR_ERROR_INVALID_HANDLE;
874         }
875
876 /*      *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_NONE, */
877 /*                                                    "Push adaptor error none"); */
878         push_error_code_t ret;
879         plugin_req_enter();
880         ret = plugin->handle->set_server_info(context, server_info);
881         plugin_req_exit(ret, plugin, error_code);
882
883         return ret;
884 }
885
886 /**
887 * @brief Connects to push service with Push App ID handed over when creates plugin context
888 *
889 * @param[in]    plugin          specifies push adaptor plugin handle
890 * @param[in]    context         specifies push adaptor plugin context handle
891 * @param[out]   error           specifies error code
892 * @return       0 on success, otherwise a positive error value
893 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
894 */
895 push_error_code_t push_adaptor_connect(push_adaptor_plugin_h plugin,
896                                                 push_adaptor_plugin_context_h context,
897                                                 push_adaptor_error_code_h *error_code)
898 {
899         push_adaptor_warning("Connect to push adaptor");
900
901         if ((NULL == plugin) || (NULL == context)) {
902                 push_adaptor_error("Invalid argument");
903
904                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT,
905                                                                 "Invalid argument (plugin or context)");
906
907                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
908         }
909
910         if (NULL == plugin->handle) {
911                 push_adaptor_error("Plugin handle is null");
912
913                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_HANDLE,
914                                                                 "Plugin handle is null");
915
916                 return PUSH_ADAPTOR_ERROR_INVALID_HANDLE;
917         }
918
919 /*      *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_NONE, */
920 /*                                                      "Push adaptor error none"); */
921
922         push_error_code_t ret;
923         plugin_req_enter();
924         ret = plugin->handle->connect(context);
925         plugin_req_exit(ret, plugin, error_code);
926
927         return ret;
928 }
929
930 /**
931 * @brief Disconnects from push service with Push App ID handed over when creates plugin context
932 *
933 * @param[in]    plugin          specifies push adaptor plugin handle
934 * @param[in]    context         specifies push adaptor plugin context handle
935 * @param[out]   error           specifies error code
936 * @return       0 on success, otherwise a positive error value
937 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
938 */
939 push_error_code_t push_adaptor_disconnect(push_adaptor_plugin_h plugin,
940                                                 push_adaptor_plugin_context_h context,
941                                                 push_adaptor_error_code_h *error_code)
942 {
943         push_adaptor_warning("Disconnect from push adaptor");
944
945         if ((NULL == plugin) || (NULL == context)) {
946                 push_adaptor_error("Invalid argument");
947
948                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT,
949                                                                 "Invalid argument (plugin or context)");
950
951                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
952         }
953
954         if (NULL == plugin->handle) {
955                 push_adaptor_error("Plugin handle is null");
956
957                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_HANDLE,
958                                                                 "Plugin handle is null");
959
960                 return PUSH_ADAPTOR_ERROR_INVALID_HANDLE;
961         }
962
963 /*      *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_NONE, */
964 /*                                                      "Push adaptor error none"); */
965
966         push_error_code_t ret;
967         plugin_req_enter();
968         ret = plugin->handle->disconnect(context);
969         plugin_req_exit(ret, plugin, error_code);
970
971         return ret;
972 }
973
974 EXPORT_API
975 push_error_code_t push_adaptor_is_connected(push_adaptor_plugin_h plugin,
976                                                 push_adaptor_plugin_context_h context,
977                                                 int *is_connected)
978 {
979         push_adaptor_info("Check push connection");
980
981         if ((NULL == context) || (NULL == is_connected)) {
982                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
983         }
984
985         *is_connected = context->state;
986
987         return PUSH_ADAPTOR_ERROR_NONE;
988 }
989
990 /**
991 * @brief Asynchronous request to get unread notifications
992 *
993 * @param[in]    plugin          specifies push adaptor plugin handle
994 * @param[in]    context         specifies push adaptor plugin context handle
995 * @param[out]   error           specifies error code
996 * @return       0 on success, otherwise a positive error value
997 * @retval       error code defined in push_error_code_e - PUSH_ADAPTOR_ERROR_NONE if successful
998 */
999 push_error_code_t push_adaptor_request_unread_notification(push_adaptor_plugin_h plugin,
1000                                                 push_adaptor_plugin_context_h context,
1001                                                 push_adaptor_error_code_h *error_code)
1002 {
1003         push_adaptor_warning("Request unread notification");
1004
1005         if ((NULL == plugin) || (NULL == context)) {
1006                 push_adaptor_error("Invalid argument");
1007
1008                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT,
1009                                                                 "Invalid argument (plugin or context)");
1010
1011                 return PUSH_ADAPTOR_ERROR_INVALID_ARGUMENT;
1012         }
1013
1014         if (NULL == plugin->handle) {
1015                 push_adaptor_error("Plugin handle is null");
1016
1017                 *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_INVALID_HANDLE,
1018                                                                 "Plugin handle is null");
1019
1020                 return PUSH_ADAPTOR_ERROR_INVALID_HANDLE;
1021         }
1022
1023 /*      *error_code = push_adaptor_create_error_code((int64_t) PUSH_ADAPTOR_ERROR_NONE, */
1024 /*                                                      "Push adaptor error none"); */
1025
1026         push_error_code_t ret;
1027         plugin_req_enter();
1028         ret = plugin->handle->request_unread_notification(context);
1029         plugin_req_exit(ret, plugin, error_code);
1030
1031         return ret;
1032 }