Fix build error (set but unused variables)
[platform/core/appfw/shortcut.git] / lib / src / icon.c
1 /*
2  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <sys/socket.h>
24 #include <sys/ioctl.h>
25 #include <libgen.h>
26 #include <sys/time.h>
27 #include <time.h>
28
29 #include <dlog.h>
30 #include <glib.h>
31 #include <db-util.h>
32 #include <vconf.h>
33 #include <vconf-keys.h>
34
35 #include <packet.h>
36 #include <com-core.h>
37 #include <com-core_packet.h>
38
39 #include "shortcut_internal.h"
40 #include "shortcut.h"
41 #include "dlist.h"
42
43
44
45 #define CREATED 0x00BEEF00
46 #define DESTROYED 0x00DEAD00
47
48 static struct info {
49         int fd;
50         int (*init_cb)(int status, void *data);
51         void *cbdata;
52         int initialized;
53
54         const char *utility_socket;
55
56         struct dlist *pending_list;
57 #if defined(_USE_ECORE_TIME_GET)
58         clockid_t type;
59 #endif
60 } s_info = {
61         .fd = -1,
62         .init_cb = NULL,
63         .cbdata = NULL,
64         .initialized = 0,
65
66         .utility_socket = "/tmp/.utility.service",
67         .pending_list = NULL,
68 #if defined(_USE_ECORE_TIME_GET)
69         .type = CLOCK_MONOTONIC,
70 #endif
71 };
72
73
74
75 struct request_item {
76         struct shortcut_icon *handle;
77         icon_request_cb_t result_cb;
78         void *data;
79 };
80
81
82
83 struct pending_item {
84         struct request_item *item;
85         struct packet *packet;
86 };
87
88
89
90 struct block {
91         unsigned int idx;
92
93         char *type;
94         char *part;
95         char *data;
96         char *option;
97         char *id;
98         char *target_id;
99 };
100
101
102
103 struct shortcut_icon {
104         unsigned int state;
105         struct shortcut_desc *desc;
106         int refcnt;
107         void *data;
108 };
109
110
111
112 struct shortcut_desc {
113         int for_pd;
114
115         unsigned int last_idx;
116
117         struct dlist *block_list;
118 };
119
120
121
122 static inline void delete_block(struct block *block)
123 {
124         DbgPrint("Release block: %p\n", block);
125         free(block->type);
126         free(block->part);
127         free(block->data);
128         free(block->option);
129         free(block->id);
130         free(block->target_id);
131         free(block);
132 }
133
134
135
136 static inline int shortcut_icon_desc_close(struct shortcut_desc *handle)
137 {
138         struct dlist *l;
139         struct dlist *n;
140         struct block *block;
141
142         dlist_foreach_safe(handle->block_list, l, n, block) {
143                 handle->block_list = dlist_remove(handle->block_list, l);
144                 delete_block(block);
145         }
146
147         free(handle);
148         return 0;
149 }
150
151
152
153 static inline struct shortcut_icon *shortcut_icon_request_unref(struct shortcut_icon *handle)
154 {
155         handle->refcnt--;
156         DbgPrint("Handle: refcnt[%d]\n", handle->refcnt);
157
158         if (handle->refcnt == 0) {
159                 handle->state = DESTROYED;
160                 shortcut_icon_desc_close(handle->desc);
161                 free(handle);
162                 handle = NULL;
163         }
164
165         return handle;
166 }
167
168
169
170 static inline struct shortcut_icon *shortcut_icon_request_ref(struct shortcut_icon *handle)
171 {
172         handle->refcnt++;
173         DbgPrint("Handle: refcnt[%d]\n", handle->refcnt);
174         return handle;
175 }
176
177
178
179 static int disconnected_cb(int handle, void *data)
180 {
181         if (s_info.fd != handle) {
182                 return 0;
183         }
184
185         ErrPrint("Disconnected\n");
186         s_info.fd = -1;
187         s_info.init_cb = NULL;
188         s_info.cbdata = NULL;
189         s_info.initialized = 0;
190         return 0;
191 }
192
193
194
195 static inline struct shortcut_desc *shortcut_icon_desc_open(void)
196 {
197         struct shortcut_desc *handle;
198
199         handle = calloc(1, sizeof(*handle));
200         if (!handle) {
201                 ErrPrint("Error: %s\n", strerror(errno));
202                 return NULL;
203         }
204
205         return handle;
206 }
207
208
209
210 static inline int shortcut_icon_desc_save(struct shortcut_desc *handle, const char *filename)
211 {
212         struct dlist *l;
213         struct dlist *n;
214         struct block *block;
215         FILE *fp;
216
217         if (!handle) {
218                 return SHORTCUT_ERROR_INVALID;
219         }
220
221         fp = fopen(filename, "w+t");
222         if (!fp) {
223                 ErrPrint("Error: %s\n", strerror(errno));
224                 return SHORTCUT_ERROR_IO;
225         }
226
227         DbgPrint("Close and flush\n");
228         dlist_foreach_safe(handle->block_list, l, n, block) {
229                 DbgPrint("{\n");
230                 fprintf(fp, "{\n");
231                 if (block->type) {
232                         fprintf(fp, "type=%s\n", block->type);
233                         DbgPrint("type=%s\n", block->type);
234                 }
235
236                 if (block->part) {
237                         fprintf(fp, "part=%s\n", block->part);
238                         DbgPrint("part=%s\n", block->part);
239                 }
240
241                 if (block->data) {
242                         fprintf(fp, "data=%s\n", block->data);
243                         DbgPrint("data=%s\n", block->data);
244                 }
245
246                 if (block->option) {
247                         fprintf(fp, "option=%s\n", block->option);
248                         DbgPrint("option=%s\n", block->option);
249                 }
250
251                 if (block->id) {
252                         fprintf(fp, "id=%s\n", block->id);
253                         DbgPrint("id=%s\n", block->id);
254                 }
255
256                 if (block->target_id) {
257                         fprintf(fp, "target=%s\n", block->target_id);
258                         DbgPrint("target=%s\n", block->target_id);
259                 }
260
261                 fprintf(fp, "}\n");
262                 DbgPrint("}\n");
263         }
264
265         if (fclose(fp) != 0) {
266                 ErrPrint("fclose: %s\n", strerror(errno));
267         }
268         return SHORTCUT_SUCCESS;
269 }
270
271
272
273 static inline struct block *find_block(struct shortcut_desc *handle, const char *id, const char *part)
274 {
275         struct block *block;
276         struct dlist *l;
277
278         dlist_foreach(handle->block_list, l, block) {
279                 if (!strcmp(block->part, part) && (!id || !strcmp(block->id, id))) {
280                         return block;
281                 }
282         }
283
284         return NULL;
285 }
286
287
288
289 static inline int update_block(struct block *block, const char *data, const char *option)
290 {
291         char *_data = NULL;
292         char *_option = NULL;
293
294         if (data) {
295                 _data = strdup(data);
296                 if (!_data) {
297                         ErrPrint("Heap: %s\n", strerror(errno));
298                         return SHORTCUT_ERROR_MEMORY;
299                 }
300         }
301
302         if (option) {
303                 _option = strdup(option);
304                 if (!_option) {
305                         ErrPrint("Heap: %s\n", strerror(errno));
306                         return SHORTCUT_ERROR_MEMORY;
307                 }
308         }
309
310         free(block->data);
311         free(block->option);
312
313         block->data = _data;
314         block->option = _option;
315         return 0;
316 }
317
318
319
320 /*!
321  * \return idx
322  */
323
324
325
326 static inline int shortcut_icon_desc_add_block(struct shortcut_desc *handle, const char *id, const char *type, const char *part, const char *data, const char *option, const char *target_id)
327 {
328         struct block *block;
329
330         if (!handle || !type) {
331                 return SHORTCUT_ERROR_INVALID;
332         }
333
334         if (!part) {
335                 part = "";
336         }
337
338         if (!data) {
339                 data = "";
340         }
341
342         if (target_id) {
343                 if (strcmp(type, SHORTCUT_ICON_TYPE_SCRIPT)) {
344                         ErrPrint("target id only can be used for script type\n");
345                         return SHORTCUT_ERROR_INVALID;
346                 }
347         }
348
349         block = find_block(handle, id, part);
350         if (!block) {
351                 block = calloc(1, sizeof(*block));
352                 if (!block) {
353                         ErrPrint("Heap: %s\n", strerror(errno));
354                         return SHORTCUT_ERROR_MEMORY;
355                 }
356
357                 block->type = strdup(type);
358                 if (!block->type) {
359                         ErrPrint("Heap: %s\n", strerror(errno));
360                         free(block);
361                         return SHORTCUT_ERROR_MEMORY;
362                 }
363
364                 block->part = strdup(part);
365                 if (!block->part) {
366                         ErrPrint("Heap: %s\n", strerror(errno));
367                         free(block->type);
368                         free(block);
369                         return SHORTCUT_ERROR_MEMORY;
370                 }
371
372                 block->data = strdup(data);
373                 if (!block->data) {
374                         ErrPrint("Heap: %s\n", strerror(errno));
375                         free(block->type);
376                         free(block->part);
377                         free(block);
378                         return SHORTCUT_ERROR_MEMORY;
379                 }
380
381                 if (option) {
382                         block->option = strdup(option);
383                         if (!block->option) {
384                                 ErrPrint("Heap: %s\n", strerror(errno));
385                                 free(block->data);
386                                 free(block->type);
387                                 free(block->part);
388                                 free(block);
389                                 return SHORTCUT_ERROR_MEMORY;
390                         }
391                 }
392
393                 if (id) {
394                         block->id = strdup(id);
395                         if (!block->id) {
396                                 ErrPrint("Heap: %s\n", strerror(errno));
397                                 free(block->option);
398                                 free(block->data);
399                                 free(block->type);
400                                 free(block->part);
401                                 free(block);
402                                 return SHORTCUT_ERROR_MEMORY;
403                         }
404                 }
405
406                 if (target_id) {
407                         block->target_id = strdup(target_id);
408                         if (!block->target_id) {
409                                 ErrPrint("Heap: %s\n", strerror(errno));
410                                 free(block->id);
411                                 free(block->option);
412                                 free(block->data);
413                                 free(block->type);
414                                 free(block->part);
415                                 free(block);
416                                 return SHORTCUT_ERROR_MEMORY;
417                         }
418                 }
419
420                 block->idx = handle->last_idx++;
421                 handle->block_list = dlist_append(handle->block_list, block);
422         } else {
423                 if (strcmp(block->type, type)) {
424                         ErrPrint("type is not valid (%s, %s)\n", block->type, type);
425                         return SHORTCUT_ERROR_INVALID;
426                 }
427
428                 if ((block->target_id && !target_id) || (!block->target_id && target_id)) {
429                         ErrPrint("type is not valid (%s, %s)\n", block->type, type);
430                         return SHORTCUT_ERROR_INVALID;
431                 }
432
433                 if (block->target_id && target_id && strcmp(block->target_id, target_id)) {
434                         ErrPrint("type is not valid (%s, %s)\n", block->type, type);
435                         return SHORTCUT_ERROR_INVALID;
436                 }
437
438                 update_block(block, data, option);
439         }
440
441         return block->idx;
442 }
443
444
445
446 static int icon_request_cb(pid_t pid, int handle, const struct packet *packet, void *data)
447 {
448         struct request_item *item = data;
449         int ret;
450
451         if (!packet) {
452                 ret = -EFAULT;
453                 DbgPrint("Disconnected?\n");
454         } else {
455                 if (packet_get(packet, "i", &ret) != 1) {
456                         DbgPrint("Invalid packet\n");
457                         ret = -EINVAL;
458                 }
459         }
460
461         if (item->result_cb) {
462                 item->result_cb(item->handle, ret, item->data);
463         }
464
465         (void)shortcut_icon_request_unref(item->handle);
466         free(item);
467         return 0;
468 }
469
470
471
472 static inline int make_connection(void)
473 {
474         int ret;
475         static struct method service_table[] = {
476                 {
477                         .cmd = NULL,
478                         .handler = NULL,
479                 },
480         };
481
482         s_info.fd = com_core_packet_client_init(s_info.utility_socket, 0, service_table);
483         if (s_info.fd < 0) {
484                 ret = SHORTCUT_ERROR_COMM;
485
486                 if (s_info.init_cb) {
487                         s_info.init_cb(ret, s_info.cbdata);
488                 }
489         } else {
490                 struct dlist *l;
491                 struct dlist *n;
492                 struct pending_item *pend;
493
494                 if (s_info.init_cb) {
495                         s_info.init_cb(SHORTCUT_SUCCESS, s_info.cbdata);
496                 }
497
498                 dlist_foreach_safe(s_info.pending_list, l, n, pend) {
499                         s_info.pending_list = dlist_remove(s_info.pending_list, l);
500
501                         ret = com_core_packet_async_send(s_info.fd, pend->packet, 0.0f, icon_request_cb, pend->item);
502                         packet_destroy(pend->packet);
503                         if (ret < 0) {
504                                 ErrPrint("ret: %d\n", ret);
505                                 if (pend->item->result_cb) {
506                                         pend->item->result_cb(pend->item->handle, ret, pend->item->data);
507                                 }
508                                 free(pend->item);
509                         }
510
511                         free(pend);
512                 }
513
514                 ret = SHORTCUT_SUCCESS;
515         }
516
517         return ret;
518 }
519
520
521
522 static void master_started_cb(keynode_t *node, void *user_data)
523 {
524         int state = 0;
525
526         if (vconf_get_bool(VCONFKEY_MASTER_STARTED, &state) < 0) {
527                 ErrPrint("Unable to get \"%s\"\n", VCONFKEY_MASTER_STARTED);
528         }
529
530         if (state == 1 && make_connection() == SHORTCUT_SUCCESS) {
531                 (void)vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb);
532         }
533 }
534
535
536
537 EAPI int shortcut_icon_service_init(int (*init_cb)(int status, void *data), void *data)
538 {
539         int ret;
540
541         if (s_info.fd >= 0) {
542                 return SHORTCUT_ERROR_INVALID;
543         }
544
545         if (s_info.initialized) {
546                 s_info.initialized = 1;
547                 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
548         }
549
550         s_info.init_cb = init_cb;
551         s_info.cbdata = data;
552
553         ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
554         if (ret < 0) {
555                 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
556         } else {
557                 DbgPrint("vconf is registered\n");
558         }
559
560         master_started_cb(NULL, NULL);
561         return SHORTCUT_SUCCESS;
562 }
563
564
565
566 EAPI int shortcut_icon_service_fini(void)
567 {
568         struct dlist *l;
569         struct dlist *n;
570         struct pending_item *pend;
571
572         if (s_info.initialized) {
573                 com_core_del_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
574                 s_info.initialized = 0;
575         }
576
577         if (s_info.fd < 0) {
578                 return SHORTCUT_ERROR_INVALID;
579         }
580
581         com_core_packet_client_fini(s_info.fd);
582         s_info.init_cb = NULL;
583         s_info.cbdata = NULL;
584         s_info.fd = -1;
585
586         dlist_foreach_safe(s_info.pending_list, l, n, pend) {
587                 s_info.pending_list = dlist_remove(s_info.pending_list, l);
588                 packet_unref(pend->packet);
589                 if (pend->item->result_cb) {
590                         pend->item->result_cb(pend->item->handle, SHORTCUT_ERROR_COMM, pend->item->data);
591                 }
592                 free(pend->item);
593                 free(pend);
594         }
595         return SHORTCUT_SUCCESS;
596 }
597
598
599
600 EAPI struct shortcut_icon *shortcut_icon_request_create(void)
601 {
602         struct shortcut_icon *handle;
603
604         handle = malloc(sizeof(*handle));
605         if (!handle) {
606                 ErrPrint("Heap: %s\n", strerror(errno));
607                 return NULL;
608         }
609
610         handle->desc = shortcut_icon_desc_open();
611         if (!handle->desc) {
612                 ErrPrint("Uanble to open desc\n");
613                 free(handle);
614                 return NULL;
615         }
616
617         handle->state = CREATED;
618         handle->refcnt = 1;
619         return handle;
620 }
621
622
623 EAPI int shortcut_icon_request_set_data(struct shortcut_icon *handle, void *data)
624 {
625         if (!handle || handle->state != CREATED) {
626                 ErrPrint("Handle is not valid\n");
627                 return SHORTCUT_ERROR_INVALID;
628         }
629
630         handle->data = data;
631         return SHORTCUT_SUCCESS;
632 }
633
634
635
636 EAPI void *shortcut_icon_request_data(struct shortcut_icon *handle)
637 {
638         if (!handle || handle->state != CREATED) {
639                 ErrPrint("Handle is not valid\n");
640                 return NULL;
641         }
642
643         return handle->data;
644 }
645
646
647
648 EAPI int shortcut_icon_request_set_info(struct shortcut_icon *handle, const char *id, const char *type, const char *part, const char *data, const char *option, const char *subid)
649 {
650         if (!handle || handle->state != CREATED) {
651                 ErrPrint("Handle is not valid\n");
652                 return SHORTCUT_ERROR_INVALID;
653         }
654
655         return shortcut_icon_desc_add_block(handle->desc, id, type, part, data, option, subid);
656 }
657
658
659
660 EAPI int shortcut_icon_request_destroy(struct shortcut_icon *handle)
661 {
662         if (!handle || handle->state != CREATED) {
663                 ErrPrint("Handle is not valid\n");
664                 return SHORTCUT_ERROR_INVALID;
665         }
666
667         (void)shortcut_icon_request_unref(handle);
668         return SHORTCUT_SUCCESS;
669 }
670
671
672
673 EAPI int shortcut_icon_request_send(struct shortcut_icon *handle, int size_type, const char *layout, const char *group, const char *outfile, icon_request_cb_t result_cb, void *data)
674 {
675         int ret;
676         struct packet *packet;
677         struct request_item *item;
678         char *filename;
679         int len;
680
681         if (!handle || handle->state != CREATED) {
682                 ErrPrint("Handle is not valid\n");
683                 return SHORTCUT_ERROR_INVALID;
684         }
685
686         if (!layout) {
687                 layout = DEFAULT_ICON_LAYOUT;
688         }
689
690         if (!group) {
691                 group = DEFAULT_ICON_GROUP;
692         }
693
694         len = strlen(outfile) + strlen(".desc") + 1 + 30; /* 30 == strlen(tv.tv_sec) + strlen(tv.tv_usec) + 10 (reserved) */
695         filename = malloc(len);
696         if (!filename) {
697                 ErrPrint("Heap: %s\n", strerror(errno));
698                 return SHORTCUT_ERROR_MEMORY;
699         }
700
701 #if defined(_USE_ECORE_TIME_GET)
702         struct timespec ts;
703         double tv;
704         do {
705                 if (clock_gettime(s_info.type, &ts) == 0) {
706                         tv = ts.tv_sec + ts.tv_nsec / 1000000000.0f;
707                         break;
708                 }
709
710                 ErrPrint("%d: %s\n", s_info.type, strerror(errno));
711                 if (s_info.type == CLOCK_MONOTONIC) {
712                         s_info.type = CLOCK_REALTIME;
713                 } else if (s_info.type == CLOCK_REALTIME) {
714                         struct timeval _tv;
715                         if (gettimeofday(&_tv, NULL) < 0) {
716                                 ErrPrint("gettimeofday: %s\n", strerror(errno));
717                                 _tv.tv_sec = rand();
718                                 _tv.tv_usec = rand();
719                         }
720
721                         tv = (double)_tv.tv_sec + (double)_tv.tv_usec / 1000000.0f;
722                         break;
723                 }
724         } while (1);
725         ret = snprintf(filename, len, "%s.%lf.desc", outfile, tv);
726 #else
727         struct timeval tv;
728         if (gettimeofday(&tv, NULL) != 0) {
729                 ErrPrint("gettimeofday: %s\n", strerror(errno));
730                 tv.tv_sec = rand();
731                 tv.tv_usec = rand();
732         }
733
734         ret = snprintf(filename, len, "%s.%lu.%lu.desc", outfile, tv.tv_sec, tv.tv_usec);
735 #endif
736         if (ret < 0) {
737                 ErrPrint("snprintf: %s\n", strerror(errno));
738                 goto out;
739         }
740
741         ret = shortcut_icon_desc_save(handle->desc, filename);
742         if (ret < 0) {
743                 goto out;
744         }
745
746         item = malloc(sizeof(*item));
747         if (!item) {
748                 ErrPrint("Heap: %s\n", strerror(errno));
749                 if (unlink(filename) < 0) {
750                         ErrPrint("Unlink: %s\n", strerror(errno));
751                 }
752                 ret = SHORTCUT_ERROR_MEMORY;
753                 goto out;
754         }
755
756         item->result_cb = result_cb;
757         item->data = data;
758         item->handle = shortcut_icon_request_ref(handle);
759
760         packet = packet_create("icon_create", "sssis", layout, group, filename, size_type, outfile);
761         if (!packet) {
762                 ErrPrint("Failed to create a packet\n");
763                 if (unlink(filename) < 0) {
764                         ErrPrint("Unlink: %s\n", strerror(errno));
765                 }
766                 free(item);
767                 (void)shortcut_icon_request_unref(handle);
768                 ret = SHORTCUT_ERROR_FAULT;
769                 goto out;
770         }
771
772         if (s_info.fd >= 0 && !s_info.pending_list) {
773                 ret = com_core_packet_async_send(s_info.fd, packet, 0.0f, icon_request_cb, item);
774                 packet_destroy(packet);
775                 if (ret < 0) {
776                         ErrPrint("ret: %d\n", ret);
777                         if (unlink(filename) < 0) {
778                                 ErrPrint("Unlink: %s\n", strerror(errno));
779                         }
780                         free(item);
781                         (void)shortcut_icon_request_unref(handle);
782                 }
783                 DbgPrint("Request is sent\n");
784         } else {
785                 struct pending_item *pend;
786
787                 pend = malloc(sizeof(*pend));
788                 if (!pend) {
789                         ErrPrint("Heap: %s\n", strerror(errno));
790                         packet_destroy(packet);
791                         free(item);
792                         if (unlink(filename) < 0) {
793                                 ErrPrint("Unlink: %s\n", strerror(errno));
794                         }
795                         (void)shortcut_icon_request_unref(handle);
796                         ret = SHORTCUT_ERROR_MEMORY;
797                         goto out;
798                 }
799
800                 pend->packet = packet;
801                 pend->item = item;
802
803                 s_info.pending_list = dlist_append(s_info.pending_list, pend);
804                 DbgPrint("Request is pended\n");
805
806                 ret = SHORTCUT_SUCCESS;
807         }
808
809 out:
810         free(filename);
811         return ret;
812 }
813
814 /* End of a file */