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