Update Log
[platform/framework/web/data-provider-slave.git] / src / lb.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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> /* exit */
19 #include <errno.h>
20
21 #include <Ecore.h>
22 #include <Eina.h>
23
24 #include <dlog.h>
25 #include <provider.h>
26 #include <livebox.h>
27 #include <livebox-errno.h>
28
29 #include "critical_log.h"
30 #include "debug.h"
31 #include "conf.h"
32 #include "so_handler.h"
33 #include "lb.h"
34 #include "update_monitor.h"
35 #include "fault.h"
36 #include "util.h"
37
38 #define IS_LB_SHOWN(itm) (!(itm)->inst->item->has_livebox_script || ((itm)->inst->item->has_livebox_script && (itm)->is_lb_show))
39
40 int errno;
41
42 struct item {
43         Ecore_Timer *timer;
44         struct instance *inst;
45         int monitor_cnt;
46         Ecore_Timer *monitor;
47         int deleteme;
48         double update_interval;
49         int heavy_updating; /* Only for debugging message */
50         int is_paused; /* 1 is paused, 0 is resumed */
51         double sleep_at;
52
53         int is_lb_show;
54         int is_pd_show;
55         int is_lb_updated;
56 };
57
58 static struct info {
59         Eina_List *item_list;
60         struct item *update;
61         Eina_List *pending_list;
62         Ecore_Timer *pending_timer;
63         Eina_List *pd_open_pending_list;
64         Ecore_Timer *pd_open_pending_timer;
65         int paused;
66         Eina_List *pd_list;
67         int secured;
68         int pending_timer_freezed;
69 } s_info  = {
70         .item_list = NULL,
71         .update = NULL,
72         .pending_list = NULL,
73         .pending_timer = NULL,
74         .pd_open_pending_list = NULL,
75         .pd_open_pending_timer = NULL,
76         .paused = 0,
77         .pd_list = NULL,
78         .secured = 0,
79         .pending_timer_freezed = 0,
80 };
81
82 static Eina_Bool updator_cb(void *data);
83
84 static void pending_timer_freeze(void)
85 {
86         DbgPrint("Freezed Count: %d\n", s_info.pending_timer_freezed);
87         if (s_info.pending_timer && !s_info.pending_timer_freezed) {
88                 DbgPrint("Freeze the pending timer\n");
89                 ecore_timer_freeze(s_info.pending_timer);
90         }
91
92         s_info.pending_timer_freezed++;
93 }
94
95 static void pending_timer_thaw(void)
96 {
97         DbgPrint("Freezed Count: %d\n", s_info.pending_timer_freezed);
98         if (!s_info.pending_timer_freezed)
99                 return;
100
101         s_info.pending_timer_freezed--;
102         if (s_info.pending_timer && !s_info.pending_timer_freezed) {
103                 DbgPrint("Thaw the pending timer\n");
104                 ecore_timer_thaw(s_info.pending_timer);
105         }
106 }
107
108 /*
109  * -1 : PD is opened, but not mine
110  *  0 : PD is not opened
111  *  1 : my PD is opened
112  */
113 static inline int pd_is_opened(const char *pkgname)
114 {
115         int i;
116         Eina_List *l;
117         char *tmp;
118
119         i = 0;
120         EINA_LIST_FOREACH(s_info.pd_list, l, tmp) {
121                 if (pkgname && !strcmp(pkgname, tmp))
122                         return 1;
123
124                 i++;
125         }
126
127         return i > 0 ? -1 : 0;
128 }
129
130 static Eina_Bool pd_open_pended_cmd_consumer_cb(void *data)
131 {
132         struct item *item;
133
134         item = eina_list_nth(s_info.pd_open_pending_list, 0);
135         if (!item)
136                 goto cleanout;
137
138         if (s_info.update)
139                 return ECORE_CALLBACK_RENEW;
140
141         s_info.pd_open_pending_list = eina_list_remove(s_info.pd_open_pending_list, item);
142         /*!
143          * \note
144          * To prevent from checking the is_updated function
145          */
146         (void)updator_cb(item);
147         if (s_info.pd_open_pending_list)
148                 return ECORE_CALLBACK_RENEW;
149
150 cleanout:
151         s_info.pd_open_pending_timer = NULL;
152         return ECORE_CALLBACK_CANCEL;
153 }
154
155 static Eina_Bool pended_cmd_consumer_cb(void *data)
156 {
157         struct item *item;
158
159         item = eina_list_nth(s_info.pending_list, 0);
160         if (!item)
161                 goto cleanout;
162
163         if (s_info.update || pd_is_opened(item->inst->item->pkgname) < 0)
164                 return ECORE_CALLBACK_RENEW;
165
166         s_info.pending_list = eina_list_remove(s_info.pending_list, item);
167         /*!
168          * \note
169          * To prevent from checking the is_updated function
170          */
171         (void)updator_cb(item);
172         if (s_info.pending_list)
173                 return ECORE_CALLBACK_RENEW;
174
175 cleanout:
176         s_info.pending_timer = NULL;
177         s_info.pending_timer_freezed = 0;
178         return ECORE_CALLBACK_CANCEL;
179 }
180
181 static inline __attribute__((always_inline)) int activate_pending_consumer(void)
182 {
183         if (s_info.pending_timer)
184                 return 0;
185
186         s_info.pending_timer = ecore_timer_add(0.000001f, pended_cmd_consumer_cb, NULL);
187         if (!s_info.pending_timer) {
188                 ErrPrint("Failed to add a new pended command consumer\n");
189                 return LB_STATUS_ERROR_FAULT;
190         }
191
192         /*!
193          * Do not increase the freezed counter.
194          * Just freeze the timer.
195          */
196         if (s_info.pending_timer_freezed)
197                 ecore_timer_freeze(s_info.pending_timer);
198
199         return 0;
200 }
201
202 static inline void deactivate_pending_consumer(void)
203 {
204         if (!s_info.pending_timer)
205                 return;
206
207         ecore_timer_del(s_info.pending_timer);
208         s_info.pending_timer = NULL;
209         s_info.pending_timer_freezed = 0;
210 }
211
212 static inline void deactivate_pd_open_pending_consumer(void)
213 {
214         if (!s_info.pd_open_pending_timer)
215                 return;
216
217         ecore_timer_del(s_info.pd_open_pending_timer);
218         s_info.pd_open_pending_timer = NULL;
219 }
220
221 static inline int __attribute__((always_inline)) activate_pd_open_pending_consumer(void)
222 {
223         if (s_info.pd_open_pending_timer)
224                 return 0;
225
226         s_info.pd_open_pending_timer = ecore_timer_add(0.000001f, pd_open_pended_cmd_consumer_cb, NULL);
227         if (!s_info.pd_open_pending_timer) {
228                 ErrPrint("Failed to add a new pended command consumer\n");
229                 return LB_STATUS_ERROR_FAULT;
230         }
231
232         return 0;
233 }
234
235 static inline void migrate_to_pd_open_pending_list(const char *pkgname)
236 {
237         Eina_List *l;
238         Eina_List *n;
239         struct item *item;
240         int cnt = 0;
241
242         EINA_LIST_FOREACH_SAFE(s_info.pending_list, l, n, item) {
243                 if (strcmp(pkgname, item->inst->item->pkgname))
244                         continue;
245
246                 s_info.pending_list = eina_list_remove(s_info.pending_list, item);
247                 s_info.pd_open_pending_list = eina_list_append(s_info.pd_open_pending_list, item);
248                 cnt++;
249         }
250
251         if (s_info.pd_open_pending_list)
252                 activate_pd_open_pending_consumer();
253
254         if (!s_info.pending_list)
255                 deactivate_pending_consumer();
256 }
257
258 static inline void migrate_to_pending_list(const char *pkgname)
259 {
260         Eina_List *l;
261         Eina_List *n;
262         struct item *item;
263         int cnt = 0;
264
265         EINA_LIST_FOREACH_SAFE(s_info.pd_open_pending_list, l, n, item) {
266                 if (strcmp(pkgname, item->inst->item->pkgname))
267                         continue;
268
269                 s_info.pd_open_pending_list = eina_list_remove(s_info.pd_open_pending_list, item);
270                 s_info.pending_list = eina_list_append(s_info.pending_list, item);
271                 cnt++;
272         }
273
274         if (s_info.pending_list)
275                 activate_pending_consumer();
276
277         if (!s_info.pd_open_pending_list)
278                 deactivate_pd_open_pending_consumer();
279 }
280
281 static inline int append_pending_list(struct item *item)
282 {
283         if (pd_is_opened(item->inst->item->pkgname) == 1) {
284                 if (eina_list_data_find(s_info.pd_open_pending_list, item) == item) {
285                         DbgPrint("Already pended - %s\n", item->inst->item->pkgname);
286                         return LB_STATUS_ERROR_EXIST;
287                 }
288
289                 if (activate_pd_open_pending_consumer() < 0) {
290                         ErrPrint("Failed to activate PD open pending consumer\n");
291                         return LB_STATUS_ERROR_FAULT;
292                 }
293
294                 s_info.pd_open_pending_list = eina_list_append(s_info.pd_open_pending_list, item);
295         } else {
296                 if (eina_list_data_find(s_info.pending_list, item) == item) {
297                         DbgPrint("Already pended - %s\n", item->inst->item->pkgname);
298                         return LB_STATUS_ERROR_EXIST;
299                 }
300
301                 if (activate_pending_consumer() < 0)
302                         return LB_STATUS_ERROR_FAULT;
303
304                 s_info.pending_list = eina_list_append(s_info.pending_list, item);
305         }
306         return 0;
307 }
308
309 static inline void timer_thaw(struct item *item)
310 {
311         double pending;
312         double period;
313         double delay;
314         double sleep_time;
315
316         if (!item->timer)
317                 return;
318
319         ecore_timer_thaw(item->timer);
320         period = ecore_timer_interval_get(item->timer);
321         pending = ecore_timer_pending_get(item->timer);
322         delay = util_time_delay_for_compensation(period) - pending;
323         ecore_timer_delay(item->timer, delay);
324
325         if (item->sleep_at == 0.0f)
326                 return;
327
328         sleep_time = util_timestamp() - item->sleep_at;
329         if (sleep_time > pending)
330                 (void)updator_cb(item);
331
332         item->sleep_at = 0.0f;
333 }
334
335 static inline void timer_freeze(struct item *item)
336 {
337         struct timeval tv;
338
339         if (!item->timer)
340                 return;
341
342         ecore_timer_freeze(item->timer);
343
344         if (ecore_timer_interval_get(item->timer) <= 1.0f)
345                 return;
346
347         if (gettimeofday(&tv, NULL) < 0) {
348                 ErrPrint("gettimeofday: %s\n", strerror(errno));
349                 tv.tv_sec = 0;
350                 tv.tv_usec = 0;
351         }
352
353         item->sleep_at = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
354 }
355
356 static inline void update_monitor_cnt(struct item *item)
357 {
358         double now;
359         double interval;
360
361         now = util_timestamp();
362         interval = now - item->update_interval;
363
364         /*!
365          * \note
366          * If the content update is processed in too short time,
367          * don't increase the monitor counter, instead of it
368          * set the heavy updating flag.
369          * And handling this heavy updating from the
370          * file update callback.
371          */
372         if (interval >= MINIMUM_UPDATE_INTERVAL) {
373                 if (s_info.update == item) {
374                         /*!
375                          * \note
376                          * If already in updating mode,
377                          * reset the monitor_cnt to 1,
378                          * all updated event will be merged into A inotify event
379                          */
380                         DbgPrint("While waiting updated event, content is updated [%s]\n", item->inst->id);
381                         item->monitor_cnt = 1;
382                 } else {
383                         item->monitor_cnt++;
384                 }
385         } else {
386                 item->heavy_updating = 1;
387         }
388
389         item->update_interval = now;
390 }
391
392 static inline Eina_List *find_item(struct instance *inst)
393 {
394         Eina_List *l;
395         struct item *item;
396         
397         EINA_LIST_FOREACH(s_info.item_list, l, item) {
398                 if (item->inst == inst)
399                         return l;
400         }
401
402         return NULL;
403 }
404
405 static inline int output_handler(struct item *item)
406 {
407         int invalid = 0;
408
409         item->monitor_cnt--;
410         if (item->monitor_cnt < 0 || item->heavy_updating) {
411                 if (!item->heavy_updating) {
412                         WarnPrint("%s has invalid monitor_cnt\n", item->inst->id);
413                         invalid = 1;
414                 } else {
415                         item->heavy_updating = 0;       /* Reset flag */
416                 }
417
418                 item->monitor_cnt = 0;
419         }
420
421         if (item->monitor_cnt == 0) {
422                 if (!invalid)
423                         fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM);
424
425                 if (item->monitor) {
426                         ecore_timer_del(item->monitor);
427                         item->monitor = NULL;
428                 }
429
430                 if (s_info.update == item)
431                         s_info.update = NULL;
432
433                 if (item->deleteme) {
434                         provider_send_deleted(item->inst->item->pkgname, item->inst->id);
435                         (void)so_destroy(item->inst);
436                         free(item);
437                         return EXIT_FAILURE;
438                 }
439         }
440
441         return EXIT_SUCCESS;
442 }
443
444 static int desc_updated_cb(const char *filename, void *data, int over)
445 {
446         struct item *item;
447
448         if (over)
449                 WarnPrint("Event Q overflow\n");
450
451         item = data;
452
453         DbgPrint("DESC %s is updated\n", filename);
454         if (item->is_pd_show) {
455                 provider_send_desc_updated(item->inst->item->pkgname, item->inst->id, filename);
456         } else {
457                 ErrPrint("But PD is not opened, Ignore this update (%s)\n", item->inst->id);
458         }
459         return EXIT_SUCCESS;
460 }
461
462 static int file_updated_cb(const char *filename, void *data, int over)
463 {
464         struct item *item;
465         int w;
466         int h;
467         double priority;
468         char *content = NULL;
469         char *title = NULL;
470         int ret;
471
472         if (over)
473                 WarnPrint("Event Q overflow\n");
474
475         item = data;
476
477         ret = util_get_filesize(filename);
478         if (ret <= 0) {
479                 ErrPrint("Content is updated. but invalid. ret = %d (Update is ignored)\n", ret);
480                 return EXIT_SUCCESS; /*!< To keep the callback */
481         }
482
483         ret = so_get_output_info(item->inst, &w, &h, &priority, &content, &title);
484         if (ret < 0) {
485                 ErrPrint("livebox_get_info returns %d\n", ret);
486                 return EXIT_SUCCESS; /*!< To keep the callback */
487         }
488
489         if (IS_LB_SHOWN(item)) {
490                 provider_send_updated(item->inst->item->pkgname, item->inst->id,
491                                         item->inst->w, item->inst->h, item->inst->priority, content, title);
492         } else {
493                 item->is_lb_updated++;
494         }
495
496         return output_handler(item);
497 }
498
499 static inline int clear_from_pd_open_pending_list(struct item *item)
500 {
501         Eina_List *l;
502         struct item *tmp;
503
504         EINA_LIST_FOREACH(s_info.pd_open_pending_list, l, tmp) {
505                 if (tmp != item)
506                         continue;
507
508                 s_info.pd_open_pending_list = eina_list_remove_list(s_info.pd_open_pending_list, l);
509                 if (!s_info.pd_open_pending_list)
510                         deactivate_pd_open_pending_consumer();
511                 return LB_STATUS_SUCCESS;
512         }
513
514         return LB_STATUS_ERROR_NOT_EXIST;
515 }
516
517 static inline int clear_from_pending_list(struct item *item)
518 {
519         Eina_List *l;
520         struct item *tmp;
521
522         EINA_LIST_FOREACH(s_info.pending_list, l, tmp) {
523                 if (tmp != item)
524                         continue;
525
526                 s_info.pending_list = eina_list_remove_list(s_info.pending_list, l);
527                 if (!s_info.pending_list)
528                         deactivate_pending_consumer();
529                 return LB_STATUS_SUCCESS;
530         }
531
532         return LB_STATUS_ERROR_NOT_EXIST;
533 }
534
535 static Eina_Bool update_timeout_cb(void *data)
536 {
537         struct item *item;
538
539         item = data;
540
541         ErrPrint("UPDATE TIMEOUT ========> %s - %s\n", item->inst->item->pkgname, item->inst->id);
542
543         if (s_info.update != item)
544                 ErrPrint("Updating item is not matched\n");
545
546         fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM);
547         fault_mark_call(item->inst->item->pkgname, item->inst->id, "update,timeout", NO_ALARM, DEFAULT_LIFE_TIMER);
548         s_info.update = NULL;
549
550         exit(ETIME);
551         return ECORE_CALLBACK_CANCEL;
552 }
553
554 static Eina_Bool updator_cb(void *data)
555 {
556         struct item *item;
557         int ret;
558
559         item = data;
560
561         if (item->monitor) {/*!< If this item is already in update process */
562                 return ECORE_CALLBACK_RENEW;
563         }
564
565         if (!IS_LB_SHOWN(item)) {
566                 DbgPrint("%s is not shown yet. delaying updates\n", item->inst->item->pkgname);
567                 (void)append_pending_list(item);
568                 return ECORE_CALLBACK_RENEW;
569         }
570
571         ret = so_is_updated(item->inst);
572         if (ret <= 0) {
573                 if (so_need_to_destroy(item->inst) == NEED_TO_DESTROY) {
574                         provider_send_deleted(item->inst->item->pkgname, item->inst->id);
575                         lb_destroy(item->inst->item->pkgname, item->inst->id);
576
577                         ecore_timer_del(item->timer);
578                         item->timer = NULL;
579                         return ECORE_CALLBACK_CANCEL;
580                 }
581
582                 return ECORE_CALLBACK_RENEW;
583         }
584
585         if (s_info.update || pd_is_opened(item->inst->item->pkgname) < 0) {
586                 DbgPrint("%s is busy\n", s_info.update ? s_info.update->inst->id : item->inst->id);
587                 (void)append_pending_list(item);
588                 return ECORE_CALLBACK_RENEW;
589         }
590
591         item->monitor = ecore_timer_add(item->inst->item->timeout, update_timeout_cb, item);
592         if (!item->monitor) {
593                 ErrPrint("Failed to add update monitor %s(%s):%d\n",
594                                         item->inst->item->pkgname, item->inst->id, item->inst->item->timeout);
595                 return ECORE_CALLBACK_RENEW;
596         }
597
598         ret = so_update(item->inst);
599         if (ret < 0) {
600                 ecore_timer_del(item->monitor);
601                 item->monitor = NULL;
602                 return ECORE_CALLBACK_RENEW;
603         }
604
605         /*!
606          * \note
607          * Counter of the event monitor is only used for asynchronous content updating,
608          * So reset it to 1 from here because the async updating is started now,
609          * even if it is accumulated by other event function before this.
610          */
611         item->monitor_cnt = 1;
612
613         /*!
614          * \note
615          * While waiting the Callback function call,
616          * Add this for finding the crash
617          */
618         fault_mark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM, DEFAULT_LIFE_TIMER);
619
620         if (ret & NEED_TO_SCHEDULE)
621                 (void)append_pending_list(item);
622
623         if (ret & OUTPUT_UPDATED) {
624                 /*!
625                  * \NOTE 
626                  * In this case, there is potential issue
627                  * 1. User added update CALLBACK -> Inotify event (Only once)
628                  *    > We have to detect this case. Is it possible to be a user callback called faster than inotify event handler?
629                  * 2. Inotify event -> User added update CALLBACK -> Inotify event
630                  *    > Okay. What we want is this.
631                  */
632                 update_monitor_cnt(item);
633         }
634
635         /*
636          * \NOTE
637          * This should be updated after "update_monitor_cnt" function call,
638          * because the update_monitor_cnt function will see the s_info.update variable,
639          */
640         s_info.update = item;
641
642         return ECORE_CALLBACK_RENEW;
643 }
644
645 static inline void update_monitor_del(const char *id, struct item *item)
646 {
647         char *tmp;
648         int len;
649
650         update_monitor_del_update_cb(util_uri_to_path(id), file_updated_cb);
651
652         len = strlen(util_uri_to_path(id)) + strlen(".desc") + 1;
653         tmp = malloc(len);
654         if (!tmp) {
655                 ErrPrint("Heap: %s (%s.desc)\n", strerror(errno), util_uri_to_path(id));
656                 return;
657         }
658
659         snprintf(tmp, len, "%s.desc", util_uri_to_path(id));
660         update_monitor_del_update_cb(tmp, desc_updated_cb);
661         free(tmp);
662 }
663
664 static inline int add_desc_update_monitor(const char *id, struct item *item)
665 {
666         char *filename;
667         int len;
668
669         len = strlen(util_uri_to_path(id)) + strlen(".desc") + 1;
670         filename = malloc(len);
671         if (!filename) {
672                 ErrPrint("Heap: %s (%s.desc)\n", strerror(errno), util_uri_to_path(id));
673                 return LB_STATUS_ERROR_MEMORY;
674         }
675
676         snprintf(filename, len, "%s.desc", util_uri_to_path(id));
677         return update_monitor_add_update_cb(filename, desc_updated_cb, item);
678 }
679
680 static inline int add_file_update_monitor(const char *id, struct item *item)
681 {
682         char *filename;
683
684         filename = strdup(util_uri_to_path(id));
685         if (!filename) {
686                 ErrPrint("Heap: %s (%s)\n", strerror(errno), id);
687                 return LB_STATUS_ERROR_MEMORY;
688         }
689
690         return update_monitor_add_update_cb(filename, file_updated_cb, item);
691 }
692
693 static inline int update_monitor_add(const char *id, struct item *item)
694 {
695         /*!
696          * \NOTE
697          * item->inst is not available yet.
698          */
699         add_file_update_monitor(id, item);
700         add_desc_update_monitor(id, item);
701         return LB_STATUS_SUCCESS;
702 }
703
704 HAPI int lb_init(void)
705 {
706         return LB_STATUS_SUCCESS;
707 }
708
709 HAPI int lb_fini(void)
710 {
711         Eina_List *l;
712         Eina_List *n;
713         struct item *item;
714
715         deactivate_pending_consumer();
716         deactivate_pd_open_pending_consumer();
717
718         EINA_LIST_FREE(s_info.pd_open_pending_list, item);
719         EINA_LIST_FREE(s_info.pending_list, item);
720
721         EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
722                 provider_send_deleted(item->inst->item->pkgname, item->inst->id);
723                 lb_destroy(item->inst->item->pkgname, item->inst->id);
724         }
725
726         return LB_STATUS_SUCCESS;
727 }
728
729 /*!
730  * \note
731  * Exported API for each liveboxes.
732  */
733 const char *livebox_find_pkgname(const char *filename)
734 {
735         Eina_List *l;
736         struct item *item;
737
738         EINA_LIST_FOREACH(s_info.item_list, l, item) {
739                 if (!strcmp(item->inst->id, filename))
740                         return item->inst->item->pkgname;
741         }
742
743         return NULL;
744 }
745
746 int livebox_request_update_by_id(const char *filename)
747 {
748         Eina_List *l;
749         struct item *item;
750
751         EINA_LIST_FOREACH(s_info.item_list, l, item) {
752                 if (!strcmp(item->inst->id, filename)) {
753                         return append_pending_list(item);
754                 }
755         }
756
757         return LB_STATUS_ERROR_NOT_EXIST;
758 }
759
760 HAPI int lb_open_pd(const char *pkgname)
761 {
762         Eina_List *l;
763         char *tmp;
764
765         EINA_LIST_FOREACH(s_info.pd_list, l, tmp) {
766                 if (!strcmp(pkgname, tmp))
767                         return 0;
768         }
769
770         tmp = strdup(pkgname);
771         if (!tmp) {
772                 ErrPrint("Heap: %s\n", strerror(errno));
773                 return LB_STATUS_ERROR_MEMORY;
774         }
775
776         if (!s_info.pd_list)
777                 pending_timer_freeze();
778
779         s_info.pd_list = eina_list_append(s_info.pd_list, tmp);
780
781         /*!
782          * Find all instances from the pending list.
783          * Move them to pd_open_pending_timer
784          */
785         migrate_to_pd_open_pending_list(pkgname);
786         return LB_STATUS_SUCCESS;
787 }
788
789 HAPI int lb_close_pd(const char *pkgname)
790 {
791         Eina_List *l;
792         Eina_List *n;
793         char *tmp;
794
795         EINA_LIST_FOREACH_SAFE(s_info.pd_list, l, n, tmp) {
796                 if (strcmp(tmp, pkgname))
797                         continue;
798
799                 s_info.pd_list = eina_list_remove(s_info.pd_list, tmp);
800                 free(tmp);
801
802                 if (!s_info.pd_list)
803                         pending_timer_thaw();
804
805                 /*!
806                  * Move all items in pd_open_pending_list
807                  * to pending_list.
808                  */
809                 migrate_to_pending_list(pkgname);
810                 return LB_STATUS_SUCCESS;
811         }
812
813         return LB_STATUS_ERROR_NOT_EXIST;
814 }
815
816 HAPI int lb_create(const char *pkgname, const char *id, const char *content_info, int timeout, int has_livebox_script, double period, const char *cluster, const char *category, int *w, int *h, double *priority, int skip_need_to_create, const char *abi, char **out_content, char **out_title)
817 {
818         struct instance *inst;
819         struct item *item;
820         int ret;
821         int create_ret;
822         int need_to_create;
823
824         need_to_create = 0;
825         *out_content = NULL;
826         *out_title = NULL;
827
828         inst = so_find_instance(pkgname, id);
829         if (inst) {
830                 DbgPrint("Instance is already exists [%s - %s] content[%s], cluster[%s], category[%s], abi[%s]\n", pkgname, id, content_info, cluster, category, abi);
831                 return LB_STATUS_SUCCESS;
832         }
833
834         if (!skip_need_to_create) {
835                 ret = so_create_needed(pkgname, cluster, category, abi);
836                 if (ret != NEED_TO_CREATE)
837                         return LB_STATUS_ERROR_PERMISSION;
838
839                 need_to_create = 1;
840         }
841
842         item = calloc(1, sizeof(*item));
843         if (!item) {
844                 ErrPrint("Heap: %s (%s - %s, content[%s], cluster[%s], category[%s], abi[%s])\n", strerror(errno), pkgname, id, content_info, cluster, category, abi);
845                 return LB_STATUS_ERROR_MEMORY;
846         }
847
848         ret = update_monitor_add(id, item);
849         if (ret < 0) {
850                 free(item);
851                 return ret;
852         }
853
854         create_ret = so_create(pkgname, id, content_info, timeout, has_livebox_script, cluster, category, abi, &inst);
855         if (create_ret < 0) {
856                 update_monitor_del(id,  item);
857                 free(item);
858
859                 *w = 0;
860                 *h = 0;
861                 *priority = 0.0f;
862                 return create_ret;
863         }
864
865         item->inst = inst;
866
867         if (period > 0.0f && !s_info.secured) {
868                 item->timer = util_timer_add(period, updator_cb, item);
869                 if (!item->timer) {
870                         ErrPrint("Failed to add timer (%s - %s, content[%s], cluster[%s], category[%s], abi[%s]\n", pkgname, id, content_info, cluster, category, abi);
871                         update_monitor_del(id, item);
872                         (void)so_destroy(inst);
873                         free(item);
874                         return LB_STATUS_ERROR_FAULT;
875                 }
876
877                 if (s_info.paused)
878                         timer_freeze(item);
879         } else {
880                 DbgPrint("Local update timer is disabled: %lf (%d)\n", period, s_info.secured);
881                 item->timer = NULL;
882         }
883
884         s_info.item_list = eina_list_append(s_info.item_list, item);
885
886         if (create_ret & NEED_TO_SCHEDULE) {
887                 DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
888                 (void)append_pending_list(item);
889         }
890
891         if (create_ret & OUTPUT_UPDATED) {
892                 update_monitor_cnt(item);
893                 /*!
894                  * \note
895                  * To send a output info, get the info forcely.
896                  * but the output file monitor will do this again
897                  *
898                  * This function will set the tmp_content and tmp_title
899                  * even if it has no updates on the content, title,
900                  * it will set them to NULL.
901                  */
902                 if (so_get_output_info(inst, w, h, priority, out_content, out_title) == LB_STATUS_SUCCESS) {
903                         if (*out_content) {
904                                 char *tmp;
905
906                                 tmp = strdup(*out_content);
907                                 if (!tmp)
908                                         ErrPrint("Memory: %s\n", strerror(errno));
909
910                                 *out_content = tmp;
911                         }
912
913                         if (*out_title) {
914                                 char *tmp;
915
916                                 tmp = strdup(*out_title);
917                                 if (!tmp)
918                                         ErrPrint("Memory: %s\n", strerror(errno));
919
920                                 *out_title = tmp;
921                         }
922                 }
923         }
924
925         *w = inst->w;
926         *h = inst->h;
927         *priority = inst->priority;
928         return need_to_create;
929 }
930
931 HAPI int lb_destroy(const char *pkgname, const char *id)
932 {
933         Eina_List *l;
934         struct instance *inst;
935         struct item *item;
936
937         inst = so_find_instance(pkgname, id);
938         if (!inst) {
939                 ErrPrint("Instance %s - %s is not created\n", pkgname, id);
940                 return LB_STATUS_ERROR_INVALID;
941         }
942
943         l = find_item(inst);
944         if (!l) {
945                 ErrPrint("Instance is not found (%s - %s)\n", pkgname, id);
946                 return LB_STATUS_ERROR_NOT_EXIST;
947         }
948
949         item = eina_list_data_get(l);
950         s_info.item_list = eina_list_remove_list(s_info.item_list, l);
951
952         if (s_info.update == item)
953                 s_info.update = NULL;
954
955         if (item->timer) {
956                 clear_from_pd_open_pending_list(item);
957                 clear_from_pending_list(item);
958                 ecore_timer_del(item->timer);
959                 item->timer = NULL;
960
961                 if (item->monitor)
962                         item->deleteme = 1;
963                 else
964                         update_monitor_del(id, item);
965         }
966
967         if (!item->monitor) {
968                 free(item);
969                 (void)so_destroy(inst);
970         }
971
972         return LB_STATUS_SUCCESS;
973 }
974
975 HAPI int lb_resize(const char *pkgname, const char *id, int w, int h)
976 {
977         Eina_List *l;
978         struct instance *inst;
979         struct item *item;
980         int ret;
981
982         inst = so_find_instance(pkgname, id);
983         if (!inst) {
984                 ErrPrint("Instance %s - %s is not created (%dx%d)\n", pkgname, id, w, h);
985                 return LB_STATUS_ERROR_INVALID;
986         }
987
988         l = find_item(inst);
989         if (!l) {
990                 ErrPrint("Instance is not found (%s - %s, %dx%d)\n", pkgname, id, w, h);
991                 return LB_STATUS_ERROR_NOT_EXIST;
992         }
993
994         item = eina_list_data_get(l);
995
996         ret = so_resize(inst, w, h);
997         if (ret < 0)
998                 return ret;
999
1000         if (ret & NEED_TO_SCHEDULE) {
1001                 DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
1002                 (void)append_pending_list(item);
1003         }
1004
1005         if (ret & OUTPUT_UPDATED)
1006                 update_monitor_cnt(item);
1007
1008         return LB_STATUS_SUCCESS;
1009 }
1010
1011 HAPI char *lb_pinup(const char *pkgname, const char *id, int pinup)
1012 {
1013         struct instance *inst;
1014         char *ret;
1015
1016         inst = so_find_instance(pkgname, id);
1017         if (!inst) {
1018                 ErrPrint("Instance %s - %s is not found (pinup[%d])\n", pkgname, id, pinup);
1019                 return NULL;
1020         }
1021
1022         ret = so_pinup(inst, pinup);
1023         return ret;
1024 }
1025
1026 HAPI int lb_set_period(const char *pkgname, const char *id, double period)
1027 {
1028         Eina_List *l;
1029         struct instance *inst;
1030         struct item *item;
1031
1032         inst = so_find_instance(pkgname, id);
1033         if (!inst) {
1034                 ErrPrint("Instance %s - %s is not found (period[%lf])\n", pkgname, id, period);
1035                 return LB_STATUS_ERROR_INVALID;
1036         }
1037
1038         l = find_item(inst);
1039         if (!l) {
1040                 ErrPrint("Instance is not found (%s - %s, period[%lf])\n", pkgname, id, period);
1041                 return LB_STATUS_ERROR_NOT_EXIST;
1042         }
1043
1044         item = eina_list_data_get(l);
1045
1046         if (period <= 0.0f) {
1047                 if (item->timer) {
1048                         ecore_timer_del(item->timer);
1049                         item->timer = NULL;
1050                 }
1051         } else {
1052                 if (item->timer) {
1053                         util_timer_interval_set(item->timer, period);
1054                 } else if (!s_info.secured) {
1055                         item->timer = util_timer_add(period, updator_cb, item);
1056                         if (!item->timer) {
1057                                 ErrPrint("Failed to add timer (%s - %s)\n", pkgname, id);
1058                                 return LB_STATUS_ERROR_FAULT;
1059                         }
1060
1061                         if (s_info.paused)
1062                                 timer_freeze(item);
1063                 }
1064         }
1065
1066         return LB_STATUS_SUCCESS;
1067 }
1068
1069 HAPI int lb_clicked(const char *pkgname, const char *id, const char *event, double timestamp, double x, double y)
1070 {
1071         Eina_List *l;
1072         struct instance *inst;
1073         struct item *item;
1074         int ret;
1075
1076         inst = so_find_instance(pkgname, id);
1077         if (!inst) {
1078                 ErrPrint("Instance %s - %s is not exists (event[%s])\n", pkgname, id, event);
1079                 return LB_STATUS_ERROR_INVALID;
1080         }
1081
1082         l = find_item(inst);
1083         if (!l) {
1084                 ErrPrint("Instance is not found (%s - %s, event[%s])\n", pkgname, id, event);
1085                 return LB_STATUS_ERROR_NOT_EXIST;
1086         }
1087
1088         item = eina_list_data_get(l);
1089
1090         ret = so_clicked(inst, event, timestamp, x, y);
1091         if (ret < 0)
1092                 return ret;
1093
1094         if (ret & NEED_TO_SCHEDULE) {
1095                 DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
1096                 (void)append_pending_list(item);
1097         }
1098
1099         if (ret & OUTPUT_UPDATED)
1100                 update_monitor_cnt(item);
1101
1102         return LB_STATUS_SUCCESS;
1103 }
1104
1105 HAPI int lb_script_event(const char *pkgname, const char *id, const char *emission, const char *source, struct event_info *event_info)
1106 {
1107         Eina_List *l;
1108         struct instance *inst;
1109         struct item *item;
1110         int ret;
1111
1112         inst = so_find_instance(pkgname, id);
1113         if (!inst) {
1114                 ErrPrint("Instance %s - %s is not exists (emission[%s], source[%s])\n", pkgname, id, emission, source);
1115                 return LB_STATUS_ERROR_INVALID;
1116         }
1117
1118         l = find_item(inst);
1119         if (!l) {
1120                 ErrPrint("Instance is not found (%s - %s, emissino[%s], source[%s])\n", pkgname, id, emission, source);
1121                 return LB_STATUS_ERROR_NOT_EXIST;
1122         }
1123
1124         item = eina_list_data_get(l);
1125
1126         if (emission && source && !strcmp(source, id)) {
1127                 if (item->inst->item->has_livebox_script) {
1128                         if (!strcmp(emission, "lb,show")) {
1129                                 item->is_lb_show = 1;
1130
1131                                 DbgPrint("[%s] Updated %d times, (content: %s), (title: %s)\n", id, item->is_lb_updated, item->inst->content, item->inst->title);
1132                                 if (item->is_lb_updated) {
1133                                         provider_send_updated(item->inst->item->pkgname, item->inst->id,
1134                                                                 item->inst->w, item->inst->h, item->inst->priority, item->inst->content, item->inst->title);
1135                                         item->is_lb_updated = 0;
1136                                 }
1137
1138                                 source = util_uri_to_path(source);
1139                         } else if (!strcmp(emission, "lb,hide")) {
1140                                 DbgPrint("Livebox(%s) script is hide now\n", id);
1141                                 item->is_lb_show = 0;
1142
1143                                 source = util_uri_to_path(source);
1144                         }
1145                 }
1146
1147                 if (!strcmp(emission, "pd,show")) {
1148                         item->is_pd_show = 1;
1149                         source = util_uri_to_path(source);
1150                 } else if (!strcmp(emission, "pd,hide")) {
1151                         item->is_pd_show = 0;
1152                         source = util_uri_to_path(source);
1153                 }
1154         }
1155
1156         ret = so_script_event(inst, emission, source, event_info);
1157         if (ret < 0)
1158                 return ret;
1159
1160         if (ret & NEED_TO_SCHEDULE) {
1161                 DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
1162                 (void)append_pending_list(item);
1163         }
1164
1165         if (ret & OUTPUT_UPDATED)
1166                 update_monitor_cnt(item);
1167
1168         return LB_STATUS_SUCCESS;
1169 }
1170
1171 HAPI int lb_is_pinned_up(const char *pkgname, const char *id)
1172 {
1173         Eina_List *l;
1174         struct instance *inst;
1175         struct item *item;
1176
1177         inst = so_find_instance(pkgname, id);
1178         if (!inst) {
1179                 ErrPrint("Instance %s - %s is not created\n", pkgname, id);
1180                 return LB_STATUS_ERROR_INVALID;
1181         }
1182
1183         l = find_item(inst);
1184         if (!l) {
1185                 ErrPrint("Instance is not found(%s - %s)\n", pkgname, id);
1186                 return LB_STATUS_ERROR_NOT_EXIST;
1187         }
1188
1189         item = eina_list_data_get(l);
1190         if (!item) {
1191                 ErrPrint("Invalid item(%s - %s)\n", pkgname, id);
1192                 return LB_STATUS_ERROR_FAULT;
1193         }
1194         /*!
1195          * NOTE:
1196          * item is not used.
1197          * Maybe this is not neccessary for this operation
1198          */
1199         return so_is_pinned_up(inst);
1200 }
1201
1202 HAPI int lb_change_group(const char *pkgname, const char *id, const char *cluster, const char *category)
1203 {
1204         Eina_List *l;
1205         struct instance *inst;
1206         struct item *item;
1207         int ret;
1208
1209         inst = so_find_instance(pkgname, id);
1210         if (!inst) {
1211                 ErrPrint("Instance %s - %s is not created (cluster[%s], category[%s])\n", pkgname, id, cluster, category);
1212                 return LB_STATUS_ERROR_INVALID;
1213         }
1214
1215         l = find_item(inst);
1216         if (!l) {
1217                 ErrPrint("Instance is not found(%s - %s, cluster[%s], category[%s])\n", pkgname, id, cluster, category);
1218                 return LB_STATUS_ERROR_NOT_EXIST;
1219         }
1220
1221         item = eina_list_data_get(l);
1222
1223         ret = so_change_group(inst, cluster, category);
1224         if (ret < 0)
1225                 return ret;
1226
1227         if (ret & NEED_TO_SCHEDULE) {
1228                 DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
1229                 (void)append_pending_list(item);
1230         }
1231
1232         if (ret & OUTPUT_UPDATED)
1233                 update_monitor_cnt(item);
1234
1235         return LB_STATUS_SUCCESS;
1236 }
1237
1238 static inline int lb_sys_event(struct instance *inst, struct item *item, int event)
1239 {
1240         int ret;
1241
1242         ret = so_sys_event(inst, event);
1243         if (ret < 0)
1244                 return ret;
1245
1246         if (ret & NEED_TO_SCHEDULE)
1247                 (void)append_pending_list(item);
1248
1249         if (ret & OUTPUT_UPDATED)
1250                 update_monitor_cnt(item);
1251
1252         return LB_STATUS_SUCCESS;
1253 }
1254
1255 HAPI int lb_system_event(const char *pkgname, const char *id, int event)
1256 {
1257         Eina_List *l;
1258         struct instance *inst;
1259         struct item *item;
1260
1261         inst = so_find_instance(pkgname, id);
1262         if (!inst) {
1263                 ErrPrint("instance %s - %s is not created\n");
1264                 return LB_STATUS_ERROR_INVALID;
1265         }
1266
1267         l = find_item(inst);
1268         if (!l) {
1269                 ErrPrint("Instance is not found(%s - %s)\n", pkgname, id);
1270                 return LB_STATUS_ERROR_NOT_EXIST;
1271         }
1272
1273         item = eina_list_data_get(l);
1274         return lb_sys_event(inst, item, event);
1275 }
1276
1277 HAPI int lb_update(const char *pkgname, const char *id)
1278 {
1279         Eina_List *l;
1280         struct instance *inst;
1281         struct item *item;
1282
1283         inst = so_find_instance(pkgname, id);
1284         if (!inst) {
1285                 ErrPrint("Instance %s - %s is not created\n", pkgname, id);
1286                 return LB_STATUS_ERROR_INVALID;
1287         }
1288
1289         l = find_item(inst);
1290         if (!l) {
1291                 ErrPrint("Instance is not found(%s - %s)\n", pkgname, id);
1292                 return LB_STATUS_ERROR_NOT_EXIST;
1293         }
1294
1295         item = eina_list_data_get(l);
1296         (void)append_pending_list(item);
1297         return LB_STATUS_SUCCESS;
1298 }
1299
1300 HAPI int lb_update_all(const char *pkgname, const char *cluster, const char *category)
1301 {
1302         Eina_List *l;
1303         Eina_List *n;
1304         struct item *item;
1305
1306         DbgPrint("Update content for %s\n", pkgname ? pkgname : "(all)");
1307         EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
1308                 if (item->deleteme)
1309                         continue;
1310
1311                 if (cluster && strcasecmp(item->inst->cluster, cluster))
1312                         continue;
1313
1314                 if (category && strcasecmp(item->inst->category, category))
1315                         continue;
1316
1317                 if (pkgname && strlen(pkgname)) {
1318                         if (!strcmp(item->inst->item->pkgname, pkgname)) {
1319                                 (void)append_pending_list(item);
1320                         }
1321                 } else {
1322                         (void)append_pending_list(item);
1323                 }
1324         }
1325
1326         return LB_STATUS_SUCCESS;
1327 }
1328
1329 HAPI int lb_delete_all_deleteme(void)
1330 {
1331         Eina_List *l;
1332         Eina_List *n;
1333         struct item *item;
1334         int cnt = 0;
1335
1336         EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
1337                 if (!item->deleteme)
1338                         continue;
1339
1340                 s_info.item_list = eina_list_remove(s_info.item_list, item);
1341
1342                 update_monitor_del(item->inst->id, item);
1343                 (void)so_destroy(item->inst);
1344                 free(item);
1345                 cnt++;
1346         }
1347
1348         DbgPrint("Delete all deleteme: %d\n", cnt);
1349         return LB_STATUS_SUCCESS;
1350 }
1351
1352 HAPI int lb_system_event_all(int event)
1353 {
1354         Eina_List *l;
1355         Eina_List *n;
1356         struct item *item;
1357
1358         EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
1359                 if (item->deleteme)
1360                         continue;
1361
1362                 DbgPrint("System event for %s (%d)\n", item->inst->id, event);
1363                 lb_sys_event(item->inst, item, event);
1364         }
1365
1366         return LB_STATUS_SUCCESS;
1367 }
1368
1369 HAPI void lb_pause_all(void)
1370 {
1371         Eina_List *l;
1372         struct item *item;
1373
1374         s_info.paused = 1;
1375
1376         pending_timer_freeze();
1377
1378         EINA_LIST_FOREACH(s_info.item_list, l, item) {
1379                 if (item->deleteme) {
1380                         DbgPrint("Instance %s skip timer pause (deleteme)\n", item->inst->item->pkgname);
1381                         continue;
1382                 }
1383
1384                 if (item->is_paused)
1385                         continue;
1386
1387                 timer_freeze(item);
1388
1389                 lb_sys_event(item->inst, item, LB_SYS_EVENT_PAUSED);
1390         }
1391 }
1392
1393 HAPI void lb_resume_all(void)
1394 {
1395         Eina_List *l;
1396         struct item *item;
1397
1398         s_info.paused = 0;
1399
1400         pending_timer_thaw();
1401
1402         EINA_LIST_FOREACH(s_info.item_list, l, item) {
1403                 if (item->deleteme) {
1404                         DbgPrint("Instance %s skip timer resume (deleteme)\n", item->inst->item->pkgname);
1405                         continue;
1406                 }
1407
1408                 if (item->is_paused)
1409                         continue;
1410
1411                 timer_thaw(item);
1412
1413                 lb_sys_event(item->inst, item, LB_SYS_EVENT_RESUMED);
1414         }
1415 }
1416
1417 HAPI int lb_pause(const char *pkgname, const char *id)
1418 {
1419         struct instance *inst;
1420         Eina_List *l;
1421         struct item *item;
1422
1423         inst = so_find_instance(pkgname, id);
1424         if (!inst)
1425                 return LB_STATUS_ERROR_INVALID;
1426
1427         l = find_item(inst);
1428         if (!l) {
1429                 ErrPrint("Instance is not found (%s - %s)\n", pkgname, id);
1430                 return LB_STATUS_ERROR_NOT_EXIST;
1431         }
1432
1433         item = eina_list_data_get(l);
1434         if (!item)
1435                 return LB_STATUS_ERROR_FAULT;
1436
1437         if (item->deleteme) {
1438                 DbgPrint("Instance %s will be deleted (%s)\n", item->inst->item->pkgname, item->inst->id);
1439                 return LB_STATUS_ERROR_BUSY;
1440         }
1441
1442         item->is_paused = 1;
1443
1444         if (s_info.paused)
1445                 return LB_STATUS_SUCCESS;
1446
1447         timer_freeze(item);
1448
1449         lb_sys_event(inst, item, LB_SYS_EVENT_PAUSED);
1450
1451         return LB_STATUS_SUCCESS;
1452 }
1453
1454 HAPI int lb_resume(const char *pkgname, const char *id)
1455 {
1456         struct instance *inst;
1457         Eina_List *l;
1458         struct item *item;
1459
1460         inst = so_find_instance(pkgname, id);
1461         if (!inst)
1462                 return LB_STATUS_ERROR_INVALID;
1463
1464         l = find_item(inst);
1465         if (!l) {
1466                 ErrPrint("Instance is not found (%s - %s)\n", pkgname, id);
1467                 return LB_STATUS_ERROR_NOT_EXIST;
1468         }
1469
1470         item = eina_list_data_get(l);
1471         if (!item)
1472                 return LB_STATUS_ERROR_FAULT;
1473
1474         if (item->deleteme) {
1475                 DbgPrint("Instance %s will be deleted (%s)\n", item->inst->item->pkgname, item->inst->id);
1476                 return LB_STATUS_ERROR_BUSY;
1477         }
1478
1479         item->is_paused = 0;
1480
1481         if (s_info.paused)
1482                 return LB_STATUS_SUCCESS;
1483
1484         timer_thaw(item);
1485
1486         lb_sys_event(inst, item, LB_SYS_EVENT_RESUMED);
1487         return LB_STATUS_SUCCESS;
1488 }
1489
1490 HAPI void lb_turn_secured_on(void)
1491 {
1492         s_info.secured = 1;
1493 }
1494
1495 HAPI int lb_is_all_paused(void)
1496 {
1497         return s_info.paused;
1498 }
1499
1500 /* End of a file */