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