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