Various patches are applied
[platform/framework/web/data-provider-master.git] / src / pkgmgr.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 <errno.h>
19 #include <stdlib.h>
20
21 #include <dlog.h>
22 #include <package-manager.h>
23 #include <livebox-errno.h>
24
25 #include <Ecore.h>
26 #include "util.h"
27 #include "debug.h"
28 #include "pkgmgr.h"
29 #include "conf.h"
30
31 struct item {
32         char *pkgname;
33         char *icon;
34
35         enum pkgmgr_event_type type;
36         enum pkgmgr_status status;
37 };
38
39 static struct {
40         pkgmgr_client *listen_pc;
41         Eina_List *item_list;
42
43         Eina_List *install_event;
44         Eina_List *uninstall_event;
45         Eina_List *update_event;
46         Eina_List *download_event;
47         Eina_List *recover_event;
48 } s_info = {
49         .listen_pc = NULL,
50         .item_list = NULL,
51
52         .install_event = NULL,
53         .uninstall_event = NULL,
54         .update_event = NULL,
55         .download_event = NULL,
56         .recover_event = NULL,
57 };
58
59 struct event_item {
60         int (*cb)(const char *pkgname, enum pkgmgr_status status, double value, void *data);
61         void *data;
62 };
63
64 static inline void invoke_install_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
65 {
66         Eina_List *l;
67         struct event_item *item;
68
69         EINA_LIST_FOREACH(s_info.install_event, l, item) {
70                 if (item->cb)
71                         item->cb(pkgname, status, value, item->data);
72         }
73 }
74
75 static inline void invoke_uninstall_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
76 {
77         Eina_List *l;
78         struct event_item *item;
79
80         EINA_LIST_FOREACH(s_info.uninstall_event, l, item) {
81                 if (item->cb)
82                         item->cb(pkgname, status, value, item->data);
83         }
84 }
85
86 static inline void invoke_update_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
87 {
88         Eina_List *l;
89         struct event_item *item;
90
91         EINA_LIST_FOREACH(s_info.update_event, l, item) {
92                 if (item->cb)
93                         item->cb(pkgname, status, value, item->data);
94         }
95 }
96
97 static inline void invoke_download_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
98 {
99         Eina_List *l;
100         struct event_item *item;
101
102         EINA_LIST_FOREACH(s_info.download_event, l, item) {
103                 if (item->cb)
104                         item->cb(pkgname, status, value, item->data);
105         }
106 }
107
108 static inline void invoke_recover_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
109 {
110         Eina_List *l;
111         struct event_item *item;
112
113         EINA_LIST_FOREACH(s_info.recover_event, l, item) {
114                 if (item->cb)
115                         item->cb(pkgname, status, value, item->data);
116         }
117 }
118
119 static inline void invoke_callback(const char *pkgname, struct item *item, double value)
120 {
121         switch (item->type) {
122         case PKGMGR_EVENT_DOWNLOAD:
123                 invoke_download_event_handler(pkgname, item->status, value);
124                 break;
125         case PKGMGR_EVENT_UNINSTALL:
126                 invoke_uninstall_event_handler(pkgname, item->status, value);
127                 break;
128         case PKGMGR_EVENT_INSTALL:
129                 invoke_install_event_handler(pkgname, item->status, value);
130                 break;
131         case PKGMGR_EVENT_UPDATE:
132                 invoke_update_event_handler(pkgname, item->status, value);
133                 break;
134         case PKGMGR_EVENT_RECOVER:
135                 invoke_recover_event_handler(pkgname, item->status, value);
136                 break;
137         default:
138                 ErrPrint("Unknown type: %d\n", item->type);
139                 break;
140         }
141 }
142
143 static inline int is_valid_status(struct item *item, const char *status)
144 {
145         const char *expected_status;
146
147         switch (item->type) {
148         case PKGMGR_EVENT_DOWNLOAD:
149                 expected_status = "download";
150                 break;
151         case PKGMGR_EVENT_UNINSTALL:
152                 expected_status = "uninstall";
153                 break;
154         case PKGMGR_EVENT_INSTALL:
155                 expected_status = "install";
156                 break;
157         case PKGMGR_EVENT_UPDATE:
158                 expected_status = "update";
159                 break;
160         case PKGMGR_EVENT_RECOVER:
161                 expected_status = "recover";
162                 break;
163         default:
164                 return 0;
165         }
166
167         return !strcasecmp(status, expected_status);
168 }
169
170 static struct item *find_item(const char *pkgname)
171 {
172         Eina_List *l;
173         struct item *item;
174
175         if (!pkgname) {
176                 ErrPrint("Package name is not valid\n");
177                 return NULL;
178         }
179
180         EINA_LIST_FOREACH(s_info.item_list, l, item) {
181                 if (strcmp(item->pkgname, pkgname))
182                         continue;
183
184                 return item;
185         }
186
187         DbgPrint("Package %s is not found\n", pkgname);
188         return NULL;
189 }
190
191 static int start_cb(const char *pkgname, const char *val, void *data)
192 {
193         struct item *item;
194
195         DbgPrint("[%s] %s\n", pkgname, val);
196
197         item = calloc(1, sizeof(*item));
198         if (!item) {
199                 ErrPrint("Heap: %s\n", strerror(errno));
200                 return LB_STATUS_ERROR_MEMORY;
201         }
202
203         item->pkgname = strdup(pkgname);
204         if (!item->pkgname) {
205                 ErrPrint("Heap: %s\n", strerror(errno));
206                 DbgFree(item);
207                 return LB_STATUS_ERROR_MEMORY;
208         }
209
210         item->status = PKGMGR_STATUS_START;
211         s_info.item_list = eina_list_append(s_info.item_list, item);
212
213         if (!strcasecmp(val, "download")) {
214                 item->type = PKGMGR_EVENT_DOWNLOAD;
215         } else if (!strcasecmp(val, "uninstall")) {
216                 item->type = PKGMGR_EVENT_UNINSTALL;
217         } else if (!strcasecmp(val, "install")) {
218                 item->type = PKGMGR_EVENT_INSTALL;
219         } else if (!strcasecmp(val, "update")) {
220                 item->type = PKGMGR_EVENT_UPDATE;
221         } else if (!strcasecmp(val, "recover")) {
222                 item->type = PKGMGR_EVENT_RECOVER;
223         } else {
224                 DbgFree(item->pkgname);
225                 DbgFree(item);
226                 ErrPrint("Invalid val: %s\n", val);
227                 return LB_STATUS_ERROR_INVALID;
228         }
229
230         invoke_callback(pkgname, item, 0.0f);
231         return LB_STATUS_SUCCESS;
232 }
233
234 static int icon_path_cb(const char *pkgname, const char *val, void *data)
235 {
236         struct item *item;
237
238         DbgPrint("[%s] %s\n", pkgname, val);
239
240         item = find_item(pkgname);
241         if (!item)
242                 return LB_STATUS_ERROR_NOT_EXIST;
243
244         if (item->icon)
245                 DbgFree(item->icon);
246
247         item->icon = strdup(val);
248         if (!item->icon) {
249                 ErrPrint("Heap: %s\n", strerror(errno));
250                 return LB_STATUS_ERROR_MEMORY;
251         }
252
253         return LB_STATUS_SUCCESS;
254 }
255
256 static int command_cb(const char *pkgname, const char *val, void *data)
257 {
258         struct item *item;
259
260         DbgPrint("[%s] %s\n", pkgname, val);
261
262         item = find_item(pkgname);
263         if (!item)
264                 return LB_STATUS_ERROR_NOT_EXIST;
265
266         if (!is_valid_status(item, val)) {
267                 DbgPrint("Invalid status: %d, %s\n", item->type, val);
268                 return LB_STATUS_ERROR_INVALID;
269         }
270
271         item->status = PKGMGR_STATUS_COMMAND;
272         invoke_callback(pkgname, item, 0.0f);
273         return LB_STATUS_SUCCESS;
274 }
275
276 static int error_cb(const char *pkgname, const char *val, void *data)
277 {
278         /* val = error */
279         struct item *item;
280
281         DbgPrint("[%s] %s\n", pkgname, val);
282
283         item = find_item(pkgname);
284         if (!item)
285                 return LB_STATUS_ERROR_NOT_EXIST;
286
287         item->status = PKGMGR_STATUS_ERROR;
288         invoke_callback(pkgname, item, 0.0f);
289         return LB_STATUS_SUCCESS;
290 }
291
292 static int change_pkgname_cb(const char *pkgname, const char *val, void *data)
293 {
294         struct item *item;
295         char *new_pkgname;
296
297         DbgPrint("[%s] %s\n", pkgname, val);
298
299         item = find_item(pkgname);
300         if (!item)
301                 return LB_STATUS_ERROR_NOT_EXIST;
302
303         new_pkgname = strdup(val);
304         if (!new_pkgname) {
305                 ErrPrint("Heap: %s\n", strerror(errno));
306                 return LB_STATUS_ERROR_MEMORY;
307         }
308
309         DbgFree(item->pkgname);
310         item->pkgname = new_pkgname;
311         return LB_STATUS_SUCCESS;
312 }
313
314 static int download_cb(const char *pkgname, const char *val, void *data)
315 {
316         /* val = integer */
317         struct item *item;
318         double value;
319
320         DbgPrint("[%s] %s\n", pkgname, val);
321
322         item = find_item(pkgname);
323         if (!item) {
324                 DbgPrint("ITEM is not started from the start_cb\n");
325                 return LB_STATUS_ERROR_INVALID;
326         }
327
328         if (item->type != PKGMGR_EVENT_DOWNLOAD) {
329                 DbgPrint("TYPE is not \"download\" : %d\n", item->type);
330                 item->type = PKGMGR_EVENT_DOWNLOAD;
331         }
332
333         switch (item->status) {
334         case PKGMGR_STATUS_START:
335         case PKGMGR_STATUS_COMMAND:
336                 item->status = PKGMGR_STATUS_PROCESSING;
337         case PKGMGR_STATUS_PROCESSING:
338                 break;
339         default:
340                 ErrPrint("Invalid state [%s, %s]\n", pkgname, val);
341                 return LB_STATUS_ERROR_INVALID;
342         }
343
344         if (val) {
345                 if (sscanf(val, "%lf", &value) != 1)
346                         value = (double)LB_STATUS_ERROR_INVALID;
347         } else {
348                 value = (double)LB_STATUS_ERROR_INVALID;
349         }
350
351         invoke_download_event_handler(pkgname, item->status, value);
352         return LB_STATUS_SUCCESS;
353 }
354
355 static int progress_cb(const char *pkgname, const char *val, void *data)
356 {
357         /* val = integer */
358         struct item *item;
359         double value;
360
361         DbgPrint("[%s] %s\n", pkgname, val);
362
363         item = find_item(pkgname);
364         if (!item) {
365                 ErrPrint("ITEM is not started from the start_cb\n");
366                 return LB_STATUS_ERROR_INVALID;
367         }
368
369         switch (item->status) {
370         case PKGMGR_STATUS_START:
371         case PKGMGR_STATUS_COMMAND:
372                 item->status = PKGMGR_STATUS_PROCESSING;
373         case PKGMGR_STATUS_PROCESSING:
374                 break;
375         default:
376                 ErrPrint("Invalid state [%s, %s]\n", pkgname, val);
377                 return LB_STATUS_ERROR_INVALID;
378         }
379
380         if (val) {
381                 if (sscanf(val, "%lf", &value) != 1)
382                         value = (double)LB_STATUS_ERROR_INVALID;
383         } else {
384                 value = (double)LB_STATUS_ERROR_INVALID;
385         }
386
387         invoke_callback(pkgname, item, value);
388         return LB_STATUS_SUCCESS;
389 }
390
391 static int end_cb(const char *pkgname, const char *val, void *data)
392 {
393         struct item *item;
394
395         DbgPrint("[%s] %s\n", pkgname, val);
396
397         item = find_item(pkgname);
398         if (!item)
399                 return LB_STATUS_ERROR_NOT_EXIST;
400
401         item->status = !strcasecmp(val, "ok") ? PKGMGR_STATUS_END : PKGMGR_STATUS_ERROR;
402
403         invoke_callback(pkgname, item, 0.0f);
404
405         s_info.item_list = eina_list_remove(s_info.item_list, item);
406         DbgFree(item->icon);
407         DbgFree(item->pkgname);
408         DbgFree(item);
409         return LB_STATUS_SUCCESS;
410 }
411
412 static struct pkgmgr_handler {
413         const char *key;
414         int (*func)(const char *package, const char *val, void *data);
415 } handler[] = {
416         { "install_percent", progress_cb },
417         { "download_percent", download_cb },
418         { "start", start_cb },
419         { "end", end_cb },
420         { "change_pkg_name", change_pkgname_cb },
421         { "icon_path", icon_path_cb },
422         { "command", command_cb },
423         { "error", error_cb },
424         { NULL, NULL },
425 };
426
427 static int pkgmgr_cb(int req_id, const char *type, const char *pkgname, const char *key, const char *val, const void *pmsg, void *data)
428 {
429         register int i;
430         int ret;
431
432         for (i = 0; handler[i].key; i++) {
433                 if (strcasecmp(key, handler[i].key))
434                         continue;
435
436                 ret = handler[i].func(pkgname, val, data);
437                 DbgPrint("REQ[%d] pkgname[%s], type[%s], key[%s], val[%s], ret = %d\n",
438                                                 req_id, pkgname, type, key, val, ret);
439         }
440
441         return LB_STATUS_SUCCESS;
442 }
443
444 HAPI int pkgmgr_init(void)
445 {
446         if (s_info.listen_pc)
447                 return LB_STATUS_ERROR_ALREADY;
448
449         s_info.listen_pc = pkgmgr_client_new(PC_LISTENING);
450         if (!s_info.listen_pc)
451                 return LB_STATUS_ERROR_FAULT;
452
453         if (pkgmgr_client_listen_status(s_info.listen_pc, pkgmgr_cb, NULL) != PKGMGR_R_OK)
454                 return LB_STATUS_ERROR_FAULT;
455
456         return LB_STATUS_SUCCESS;
457 }
458
459 HAPI int pkgmgr_fini(void)
460 {
461         struct event_item *item;
462         struct item *ctx;
463
464         if (!s_info.listen_pc)
465                 return LB_STATUS_ERROR_INVALID;
466
467         if (pkgmgr_client_free(s_info.listen_pc) != PKGMGR_R_OK)
468                 return LB_STATUS_ERROR_FAULT;
469
470         s_info.listen_pc = NULL;
471
472         EINA_LIST_FREE(s_info.download_event, item) {
473                 DbgFree(item);
474         }
475
476         EINA_LIST_FREE(s_info.uninstall_event, item) {
477                 DbgFree(item);
478         }
479
480         EINA_LIST_FREE(s_info.install_event, item) {
481                 DbgFree(item);
482         }
483
484         EINA_LIST_FREE(s_info.update_event, item) {
485                 DbgFree(item);
486         }
487
488         EINA_LIST_FREE(s_info.recover_event, item) {
489                 DbgFree(item);
490         }
491
492         EINA_LIST_FREE(s_info.item_list, ctx) {
493                 DbgFree(ctx->pkgname);
494                 DbgFree(ctx->icon);
495                 DbgFree(ctx);
496         }
497
498         return LB_STATUS_SUCCESS;
499 }
500
501 HAPI int pkgmgr_add_event_callback(enum pkgmgr_event_type type, int (*cb)(const char *pkgname, enum pkgmgr_status status, double value, void *data), void *data)
502 {
503         struct event_item *item;
504
505         item = calloc(1, sizeof(*item));
506         if (!item) {
507                 ErrPrint("Heap: %s\n", strerror(errno));
508                 return LB_STATUS_ERROR_MEMORY;
509         }
510
511         item->cb = cb;
512         item->data = data;
513
514         switch (type) {
515         case PKGMGR_EVENT_DOWNLOAD:
516                 s_info.download_event = eina_list_prepend(s_info.download_event, item);
517                 break;
518         case PKGMGR_EVENT_UNINSTALL:
519                 s_info.uninstall_event = eina_list_prepend(s_info.uninstall_event, item);
520                 break;
521         case PKGMGR_EVENT_INSTALL:
522                 s_info.install_event = eina_list_prepend(s_info.install_event, item);
523                 break;
524         case PKGMGR_EVENT_UPDATE:
525                 s_info.update_event = eina_list_prepend(s_info.update_event, item);
526                 break;
527         case PKGMGR_EVENT_RECOVER:
528                 s_info.recover_event = eina_list_prepend(s_info.recover_event, item);
529                 break;
530         default:
531                 DbgFree(item);
532                 return LB_STATUS_ERROR_INVALID;
533         }
534
535         return LB_STATUS_SUCCESS;
536 }
537
538 HAPI void *pkgmgr_del_event_callback(enum pkgmgr_event_type type, int (*cb)(const char *pkgname, enum pkgmgr_status status, double value, void *data), void *data)
539 {
540         struct event_item *item;
541         Eina_List *l;
542         void *cbdata = NULL;
543
544         switch (type) {
545         case PKGMGR_EVENT_DOWNLOAD:
546                 EINA_LIST_FOREACH(s_info.download_event, l, item) {
547                         if (item->cb == cb && item->data == data) {
548                                 s_info.download_event = eina_list_remove(s_info.download_event, item);
549                                 cbdata = item->data;
550                                 DbgFree(item);
551                                 break;
552                         }
553                 }
554                 break;
555         case PKGMGR_EVENT_UNINSTALL:
556                 EINA_LIST_FOREACH(s_info.uninstall_event, l, item) {
557                         if (item->cb == cb && item->data == data) {
558                                 s_info.uninstall_event = eina_list_remove(s_info.uninstall_event, item);
559                                 cbdata = item->data;
560                                 DbgFree(item);
561                                 break;
562                         }
563                 }
564                 break;
565         case PKGMGR_EVENT_INSTALL:
566                 EINA_LIST_FOREACH(s_info.install_event, l, item) {
567                         if (item->cb == cb && item->data == data) {
568                                 s_info.install_event = eina_list_remove(s_info.install_event, item);
569                                 cbdata = item->data;
570                                 DbgFree(item);
571                                 break;
572                         }
573                 }
574                 break;
575         case PKGMGR_EVENT_UPDATE:
576                 EINA_LIST_FOREACH(s_info.update_event, l, item) {
577                         if (item->cb == cb && item->data == data) {
578                                 s_info.update_event = eina_list_remove(s_info.update_event, item);
579                                 cbdata = item->data;
580                                 DbgFree(item);
581                                 break;
582                         }
583                 }
584                 break;
585         case PKGMGR_EVENT_RECOVER:
586                 EINA_LIST_FOREACH(s_info.recover_event, l, item) {
587                         if (item->cb == cb && item->data == data) {
588                                 s_info.recover_event = eina_list_remove(s_info.recover_event, item);
589                                 cbdata = item->data;
590                                 DbgFree(item);
591                                 break;
592                         }
593                 }
594                 break;
595         default:
596                 ErrPrint("Invalid type\n");
597                 break;
598         }
599
600         return cbdata;
601 }
602
603 /* End of a file */